|
root / base / usr / src / lib / brand / shared
shared Plain Text 3634 lines 102.1 KB
   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
#
# 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) 2010, Oracle and/or its affiliates. All rights reserved.
#

default: all

# Build everything in parallel; use .WAIT for dependencies
.PARALLEL:

SUBDIRS =	brand zone
MSGSUBDIRS =	zone

all :		TARGET= all
install :	TARGET= install
clean :	TARGET= clean
clobber :	TARGET= clobber
_msg :		TARGET= _msg

.KEEP_STATE:

all install clean clobber: $(SUBDIRS)


_msg: $(MSGSUBDIRS)

$(SUBDIRS): FRC
	@cd $@; pwd; $(MAKE) $(TARGET)

FRC:
#
# 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) 2010, Oracle and/or its affiliates. All rights reserved.
#

include $(SRC)/lib/Makefile.lib

default:	all

# Hammerhead: amd64-only
SUBDIRS =	$(MACH64)

all :		TARGET= all
clean :	TARGET= clean
clobber :	TARGET= clobber
install :	TARGET= install
_msg :		TARGET= _msg

.KEEP_STATE:

all install clean clobber _msg: $(SUBDIRS)


$(SUBDIRS): FRC
	@cd $@; pwd; $(MAKE) $(TARGET)

FRC:
#
# 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) 2010, Oracle and/or its affiliates. All rights reserved.
#
# Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
#
# Copyright 2019 Joyent, Inc.
#

COBJS =		brand_util.o
ASOBJS =	crt.o handler.o runexe.o
OFFSETS_SRC =	../common/offsets.in
OFFSETS_H =	assym.h
OBJECTS =	$(COBJS) $(ASOBJS)
CLOBBERFILES +=	$(OFFSETS_H)

include $(SRC)/lib/Makefile.lib

SRCDIR =	../common
CSRCS =		$(COBJS:%o=../common/%c)
ASSRCS =	$(ASOBJS:%o=$(ISASRCDIR)/%s)
SRCS =		$(CSRCS) $(ASSRCS)

CPPFLAGS +=	-D_REENTRANT -U_ASM -I. -I../sys
CFLAGS +=	$(CCVERBOSE)
ASFLAGS +=	$(ASFLAGS_$(CURTYPE)) -D_ASM -I. -I../sys
ASFLAGS64 +=	$(ASFLAGS_$(CURTYPE)) -D_ASM -I. -I../sys

#
# Disable stack protection as this code might be running in an s10 context.
#
STACKPROTECT = none

# intentional code after abort()
SMOFF += unreachable

.KEEP_STATE:

# Hammerhead: Enable secondary expansion for $$(PICS) syntax (GNU Make)
.SECONDEXPANSION:

#
# build the offset header before trying to compile any files.  (it's included
# by brand_misc.h, so it's needed for all objects, not just assembly ones.)
#
# Note we have to build assym.h via its dependency on pics/% so that the
# target dependent assignment of CTF_FLAGS will be there, otherwise make
# will see two different commands to build it (endless rebuilds).
#
all: pics .WAIT $$(PICS)

$(OBJECTS:%=pics/%): $(OFFSETS_H)

$(OFFSETS_H): $(OFFSETS_SRC)
	$(OFFSETS_CREATE) < $(OFFSETS_SRC) >$@

pics/%.o: $(ISASRCDIR)/%.S
	$(COMPILE.s) -o $@ $<
	$(POST_PROCESS_S_O)

include $(SRC)/lib/Makefile.targ
#
# 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) 2010, Oracle and/or its affiliates. All rights reserved.
#

ISASRCDIR =	.

include ../Makefile.com
include $(SRC)/lib/Makefile.lib.64

CPPFLAGS += 		-D_SYSCALL32

install: all
/*
 * 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) 2010, Oracle and/or its affiliates. All rights reserved.
 */

#include <sys/asm_linkage.h>

#if defined(lint)

void
_start(void)
{
}

#else	/* lint */
	/*
	 * Initial entry point for the brand emulation library.
	 *
	 * This platform specific assembly entry point exists just to invoke
	 * the common brand library startup routine.  That routine expects to
	 * be called with the following arguments:
	 *	brand_init(int argc, char *argv[], char *envp[])
	 *
	 * There are no arguments explicitly passed to this entry point,
	 * routine, but we do know how our initial stack has been setup by
	 * the kernel.  The stack format is documented in:
	 *	usr/src/cmd/sgs/rtld/amd64/boot.s
	 *
	 * So this routine will troll through the stack to setup the argument
	 * values for the common brand library startup routine and then invoke
	 * it.  This routine is modeled after the default crt1.s`_start()
	 * routines.
	 */
	ENTRY_NP(_start)

	/* Make stack traces look pretty, build a fake stack frame. */
	pushq	$0			/ Build a stack frame. retpc = NULL
	pushq	$0			/ fp = NULL
	movq	%rsp, %rbp		/ first stack frame

	/*
	 * Calculate the location of the envp array by adding the size of
	 * the argv array to the start of the argv array.
	 */
	movq	16(%rbp), %rdi		/ argc in %rax (1st param)
	leaq	24(%rbp), %rsi		/ &argv[0] in %rbx (2nd param)
	leaq	32(%rbp,%rdi,8), %rdx	/ envp in %rcx (3rd param)
	/* Hammerhead: Use PLT call for PIC compatibility (GNU ld) */
	call	brand_init@PLT

	/*NOTREACHED*/
	SET_SIZE(_start)
#endif	/* lint */
/*
 * 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) 2010, Oracle and/or its affiliates. All rights reserved.
 */

#include <brand_misc.h>

/*
 * Each JMP must occupy 16 bytes
 */
#define	JMP	\
	pushq	$_CONST(. - brand_handler_table); \
	jmp	brand_handler;	\
	.align	16;

#define	JMP4	JMP; JMP; JMP; JMP
#define JMP16	JMP4; JMP4; JMP4; JMP4
#define JMP64	JMP16; JMP16; JMP16; JMP16
#define JMP256	JMP64; JMP64; JMP64; JMP64

#if defined(lint)

void
brand_handler_table(void)
{}

void
brand_handler(void)
{
}

#else	/* lint */

	/*
	 * On entry to this table, %rax will hold the return address. The
	 * location where we enter the table is a function of the system
	 * call number. The table needs the same alignment as the individual
	 * entries.
	 */
	.align	16
	ENTRY_NP(brand_handler_table)
	JMP256
	SET_SIZE(brand_handler_table)

	/*
	 * %rax - userland return address
	 * stack contains:
	 *    |    --------------------------------------
	 *    v  8 | syscall arguments			|
	 *  %rsp+0 | syscall number			|
	 *         --------------------------------------
	 */
	ENTRY_NP(brand_handler)
	pushq	%rbp			/* allocate stack frame */
	movq	%rsp, %rbp

	/* Save registers at the time of the syscall. */
	movq	$0, EH_LOCALS_GREG(REG_TRAPNO)(%rbp)
	movq	$0, EH_LOCALS_GREG(REG_ERR)(%rbp)
	movq	%r15, EH_LOCALS_GREG(REG_R15)(%rbp)
	movq	%r14, EH_LOCALS_GREG(REG_R14)(%rbp)
	movq	%r13, EH_LOCALS_GREG(REG_R13)(%rbp)
	movq	%r12, EH_LOCALS_GREG(REG_R12)(%rbp)
	movq	%r11, EH_LOCALS_GREG(REG_R11)(%rbp)
	movq	%r10, EH_LOCALS_GREG(REG_R10)(%rbp)
	movq	%r9, EH_LOCALS_GREG(REG_R9)(%rbp)
	movq	%r8, EH_LOCALS_GREG(REG_R8)(%rbp)
	movq	%rdi, EH_LOCALS_GREG(REG_RDI)(%rbp)
	movq	%rsi, EH_LOCALS_GREG(REG_RSI)(%rbp)
	movq	%rbx, EH_LOCALS_GREG(REG_RBX)(%rbp)
	movq	%rcx, EH_LOCALS_GREG(REG_RCX)(%rbp)
	movq	%rdx, EH_LOCALS_GREG(REG_RDX)(%rbp)
	xorq	%rcx, %rcx
	movw	%cs, %cx
	movq	%rcx, EH_LOCALS_GREG(REG_CS)(%rbp)
	movw	%ds, %cx
	movq	%rcx, EH_LOCALS_GREG(REG_DS)(%rbp)
	movw	%es, %cx
	movq	%rcx, EH_LOCALS_GREG(REG_ES)(%rbp)
	movw	%fs, %cx
	movq	%rcx, EH_LOCALS_GREG(REG_FS)(%rbp)
	movw	%gs, %cx
	movq	%rcx, EH_LOCALS_GREG(REG_GS)(%rbp)
	movw	%ss, %cx
	movq	%rcx, EH_LOCALS_GREG(REG_SS)(%rbp)
	pushfq					/* save syscall flags */
	popq	%r12
	movq	%r12, EH_LOCALS_GREG(REG_RFL)(%rbp)
	movq	EH_ARGS_OFFSET(0)(%rbp), %r12	/* save syscall rbp */
	movq	%r12, EH_LOCALS_GREG(REG_RBP)(%rbp)
	movq	%rbp, %r12			/* save syscall rsp */
	addq	$CPTRSIZE, %r12
	movq	%r12, EH_LOCALS_GREG(REG_RSP)(%rbp)
	movq	%fs:0, %r12			/* save syscall fsbase */
	movq	%r12, EH_LOCALS_GREG(REG_FSBASE)(%rbp)
	movq	$0, EH_LOCALS_GREG(REG_GSBASE)(%rbp)

	/*
	 * The kernel drops us into the middle of the brand_handle_table
	 * above that then pushes that table offset onto the stack, and calls
	 * into brand_handler. That offset indicates the system call number
	 * while %rax holds the return address for the system call. We replace
	 * the value on the stack with the return address, and use the value to
	 * compute the system call number by dividing by the table entry size.
	 */
	xchgq	CPTRSIZE(%rbp), %rax	/* swap JMP table offset and ret addr */
	shrq	$4, %rax		/* table_offset/size = syscall num */
	movq	%rax, EH_LOCALS_GREG(REG_RAX)(%rbp) /* save syscall num */

	/*
	 * Finish setting up our stack frame.  We would normally do this
	 * upon entry to this function, but in this case we delayed it
	 * because a "sub" operation can modify flags and we wanted to
	 * save the flags into the gregset_t above before they get modified.
	 *
	 * Our stack frame format is documented in brand_misc.h.
	 */
	subq	$EH_LOCALS_SIZE, %rsp

	/* Look up the system call's entry in the sysent table */
	movq	brand_sysent_table@GOTPCREL(%rip), %r11 /* %r11 = sysent_tbl */
	shlq	$4, %rax		/* each entry is 16 bytes */
	addq	%rax, %r11		/* %r11 = sysent entry address */

	/*
	 * Get the return value flag and the number of arguments from the
	 * sysent table.
	 */
	movq	CPTRSIZE(%r11), %r12		/* number of args + rv flag */
	andq	$RV_MASK, %r12			/* strip out number of args */
	movq	%r12, EH_LOCALS_RVFLAG(%rbp)	/* save rv flag */

	/*
	 * Setup arguments for our emulation call.  Our input arguments,
	 * 0 to N, will become emulation call arguments 1 to N+1.
	 *
	 * Note: Syscall argument passing is different from function call
	 * argument passing on amd64.  For function calls, the fourth arg
	 * is passed via %rcx, but for system calls the 4th argument is
	 * passed via %r10.  This is because in amd64, the syscall
	 * instruction puts lower 32 bit of %rflags in %r11 and puts the
	 * %rip value to %rcx.
	 */
	movq	EH_ARGS_OFFSET(4)(%rbp), %r12		/* copy 8th arg */
	movq	%r12, EH_ARGS_OFFSET(2)(%rsp)
	movq	EH_ARGS_OFFSET(3)(%rbp), %r12		/* copy 7th arg */
	movq	%r12, EH_ARGS_OFFSET(1)(%rsp)
	movq	%r9, EH_ARGS_OFFSET(0)(%rsp)
	movq	%r8, %r9
	movq	%r10, %r8
	movq	%rdx, %rcx
	movq	%rsi, %rdx
	movq	%rdi, %rsi

	/*
	 * The first parameter to the emulation callback function is a
	 * pointer to a sysret_t structure.
	 */
	movq	%rbp, %rdi
	addq	$EH_LOCALS_SYSRET, %rdi		/* arg0 == sysret_t ptr */

	/* invoke the emulation routine */
	ALTENTRY(brand_handler_savepc)
	call	*(%r11)

	/* restore scratch and parameter registers */
	movq	EH_LOCALS_GREG(REG_R12)(%rbp), %r12	/* restore %r12 */
	movq	EH_LOCALS_GREG(REG_R11)(%rbp), %r11	/* restore %r11 */
	movq	EH_LOCALS_GREG(REG_R10)(%rbp), %r10	/* restore %r10 */
	movq	EH_LOCALS_GREG(REG_R9)(%rbp), %r9	/* restore %r9 */
	movq	EH_LOCALS_GREG(REG_R8)(%rbp), %r8	/* restore %r8 */
	movq	EH_LOCALS_GREG(REG_RCX)(%rbp), %rcx	/* restore %rcx */
	movq	EH_LOCALS_GREG(REG_RDX)(%rbp), %rdx	/* restore %rdx */
	movq	EH_LOCALS_GREG(REG_RSI)(%rbp), %rsi	/* restore %rsi */
	movq	EH_LOCALS_GREG(REG_RDI)(%rbp), %rdi	/* restore %rdi */

	/* Check for syscall emulation success or failure */
	cmpq	$0, %rax
	je	success
	stc					/* failure, set carry flag */
	jmp	return				/* return, %rax == errno */

success:
	/* There is always at least one return value. */
	movq	EH_LOCALS_SYSRET1(%rbp), %rax	/* %rax == sys_rval1 */
	cmpq	$RV_DEFAULT, EH_LOCALS_RVFLAG(%rbp) /* check rv flag */
	je	clear_carry
	mov	EH_LOCALS_SYSRET2(%rbp), %rdx	/* %rdx == sys_rval2 */
clear_carry:
	clc					/* success, clear carry flag */

return:
	movq	%rbp, %rsp			/* restore stack */
	popq	%rbp
	ret					/* ret to instr after syscall */
	SET_SIZE(brand_handler)


#endif	/* lint */
/*
 * 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) 2010, Oracle and/or its affiliates. All rights reserved.
 */

#include <sys/asm_linkage.h>
#include <brand_misc.h>

#if defined(lint)

/*ARGSUSED*/
void
brand_runexe(void *argv, ulong_t entry)
{
}

#else	/* lint */
	/*
	 * Prepare to jump to the target program we actually want to run.
	 * If this program is dynamically linked then we'll be jumping to
	 * another copy of the linker.  If it's a statically linked program
	 * we'll be jumping directy to it's main entry point.  In any case,
	 * we need to reset our current state stack and register state to
	 * something similar to the initial process state setup by the kernel
	 * and documented at:
	 *	usr/src/cmd/sgs/rtld/i386/boot.s
	 *	usr/src/cmd/sgs/rtld/sparcv9/boot.s
	 *
	 * Of course this is the same stack format as when this executable
	 * was first started, so here we'll just roll back the stack and
	 * frame pointers to their values when this processes first started
	 * execution.
	 */
	ENTRY_NP(brand_runexe)

	movq	%rdi, %rax		/ %rax = &argv[0]
	movq	%rsi, %rbx		/ Brand app entry point in %rbx
	subq	$8, %rax		/ Top of stack - must point at argc
	movq	%rax, %rsp		/ Set %rsp to what linkers expect

	/*
	 * We also have to make sure to clear %rdx since nornally ld.so.1 will
	 * set that to non-zero if there is an exit function that should be
	 * invoked when the process is terminating.  This isn't actually
	 * necessary if the target program we're jumping to is a dynamically
	 * linked program since in that case we're actually jumping to another
	 * copy of ld.so.1 and it will just reset %rdx, but if the target
	 * program we're jumping to is a statically linked binary that uses
	 * the standard sun compiler supplied crt1.o`_start(), it will check
	 * to see if %g1 is set.
	 */
	movq	$0, %rdx

	jmp	*%rbx			/ And away we go...
	/*
	 * target will never return.
	 */
	SET_SIZE(brand_runexe)
#endif	/* lint */
/*
 * 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) 2010, Oracle and/or its affiliates. All rights reserved.
 */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <sys/auxv.h>
#include <sys/bitmap.h>
#include <sys/brand.h>
#include <sys/inttypes.h>
#include <sys/lwp.h>
#include <sys/syscall.h>
#include <sys/systm.h>
#include <sys/utsname.h>
#include <fcntl.h>
#include <brand_misc.h>
#include <sys/brand.h>

extern brand_sysent_table_t brand_sysent_table[];

/*LINTED: static unused*/
static volatile int		brand_abort_err;
/*LINTED: static unused*/
static volatile const char	*brand_abort_msg;
/*LINTED: static unused*/
static volatile const char	*brand_abort_file;
/*LINTED: static unused*/
static volatile int		brand_abort_line;

/*
 * Principles of emulation 101.
 *
 *
 * *** Setting errno
 *
 * Just don't do it.  This emulation library is loaded onto a
 * seperate link map from the application who's address space we're
 * running in.  We have our own private copy of libc, so there for,
 * the errno value accessible from here is is also private and changing
 * it will not affect any errno value that the processes who's address
 * space we are running in will see.  To return an error condition we
 * should return the errno value we'd like the system to return.
 * For more information about this see the comments in brand_misc.h.
 * Basically, when we return to the caller that initiated the system
 * call it's their responsibility to set errno.
 *
 *
 * *** Recursion Considerations
 *
 * When emulating system calls we need to be very careful about what
 * library calls we invoke.  Library calls should be kept to a minimum.
 * One issue is that library calls can invoke system calls, so if we're
 * emulating a system call and we invoke a library call that depends on
 * that system call we will probably enter a recursive loop, which would
 * be bad.
 *
 *
 * *** Return Values.
 *
 * See brand_misc.h.
 *
 * *** Agent lwp considerations
 *
 * It is currently impossible to do any emulation for these system call
 * when they are being invoked on behalf of an agent lwp.  To understand why
 * it's impossible you have to understand how agent lwp syscalls work.
 *
 * The agent lwp syscall process works as follows:
 *   1  The controlling process stops the target.
 *   2  The controlling process injects an agent lwp which is also stopped.
 *      This agent lwp assumes the userland stack and register values
 *      of another stopped lwp in the current process.
 *   3  The controlling process configures the agent lwp to start
 *      executing the requested system call.
 *   4  The controlling process configure /proc to stop the agent lwp when
 *      it enters the requested system call.
 *   5  The controlling processes allows the agent lwp to start executing.
 *   6  The agent lwp traps into the kernel to perform the requested system
 *      call and immediately stop.
 *   7  The controlling process copies all the arguments for the requested
 *      system call onto the agent lwp's stack.
 *   8  The controlling process configures /proc to stop the agent lwp
 *      when it completes the requested system call.
 *   9  The controlling processes allows the agent lwp to start executing.
 *  10  The agent lwp executes the system call and then stop before returning
 *      to userland.
 *  11  The controlling process copies the return value and return arguments
 *      back from the agent lwps stack.
 *  12  The controlling process destroys the agent lwp and restarts
 *      the target process.
 *
 * The fundamental problem is that when the agent executes the request
 * system call in step 5, if we're emulating that system call then the
 * lwp is redirected back to our emulation layer without blocking
 * in the kernel.  But our emulation layer can't access the arguments
 * for the system call because they haven't been copied to the stack
 * yet and they still only exist in the controlling processes address
 * space.  This prevents us from being able to do any emulation of
 * agent lwp system calls.  Hence, currently our brand trap interposition
 * callback (XXX_brand_syscall_callback_common) will detect if a system
 * call is being made by an agent lwp, and if this is the case it will
 * never redirect the system call to this emulation library.
 *
 * In the future, if this proves to be a problem the the easiest solution
 * would probably be to replace the branded versions of these application
 * with their native counterparts.  Ie,  truss, plimit, and pfiles could be
 * replace with wrapper scripts that execute the native versions of these
 * applications.  In the case of plimit and pfiles this should be pretty
 * strait forward.  Truss would probably be more tricky since it can
 * execute applications which would be branded applications, so in that
 * case it might be necessary to create a loadable library which could
 * be LD_PRELOADed into truss and this library would interpose on the
 * exec() system call to allow truss to correctly execute branded
 * processes.  It should be pointed out that this solution could work
 * because "native agent lwps" (ie, agent lwps created by native
 * processes) can be treated differently from "branded aged lwps" (ie,
 * agent lwps created by branded processes), since native agent lwps
 * would presumably be making native system calls and hence not need
 * any interposition.
 *
 * *** General considerations
 *
 * One of the differences between the lx brand and the s10
 * brand, is that the s10 brand only interposes on syscalls
 * that need some kind of emulation, whereas the lx brand interposes
 * on _all_ system calls.  Lx branded system calls that don't need
 * any emulation are then redirected back to the kernel from the
 * userland library via the IN_KERNEL_SYSCALL macro.  The lx-syscall
 * dtrace provider depends on this behavior.
 *
 */

/*ARGSUSED*/
void
_brand_abort(int err, const char *msg, const char *file, int line)
{
	sysret_t rval;

	/* Save the error message into convenient globals */
	brand_abort_err = err;
	brand_abort_msg = msg;
	brand_abort_file = file;
	brand_abort_line = line;

	/* kill ourselves */
	abort();

	/* If abort() didn't work, try something stronger. */
	(void) __systemcall(&rval, SYS_lwp_kill + 1024, _lwp_self(), SIGKILL);
}

int
brand_uucopy(const void *from, void *to, size_t size)
{
	sysret_t rval;

	if (__systemcall(&rval, SYS_uucopy + 1024, from, to, size) != 0)
		return (EFAULT);
	return (0);
}

/*
 * ATTENTION: uucopystr() does NOT ensure that string are null terminated!
 */
int
brand_uucopystr(const void *from, void *to, size_t size)
{
	sysret_t rval;

	if (__systemcall(&rval, SYS_uucopystr + 1024, from, to, size) != 0)
		return (EFAULT);
	return (0);
}

/*
 * This function is defined to be NOSYS but it won't be called from the
 * the kernel since the NOSYS system calls are not enabled in the kernel.
 * Thus, the only time this function is called is directly from within the
 * indirect system call path.
 */
/*ARGSUSED*/
long
brand_unimpl(sysret_t *rv, uintptr_t p1)
{
	sysret_t rval;

	/*
	 * We'd like to print out some kind of error message here like
	 * "unsupported syscall", but we can't because it's not safe to
	 * assume that stderr or STDERR_FILENO actually points to something
	 * that is a terminal, and if we wrote to those files we could
	 * inadvertantly write to some applications open files, which would
	 * be bad.
	 *
	 * Normally, if an application calls an invalid system call
	 * it get a SIGSYS sent to it.  So we'll just go ahead and send
	 * ourselves a signal here.  Note that this is far from ideal since
	 * if the application has registered a signal handler, that signal
	 * handler may recieve a ucontext_t as the third parameter to
	 * indicate the context of the process when the signal was
	 * generated, and in this case that context will not be what the
	 * application is expecting.  Hence, we should probably create a
	 * brandsys() kernel function that can deliver the signal to us
	 * with the correct ucontext_t.
	 */
	(void) __systemcall(&rval, SYS_lwp_kill + 1024, _lwp_self(), SIGSYS);
	return (ENOSYS);
}

#if defined(__sparc) && !defined(__sparcv9)
/*
 * Yuck.  For 32-bit sparc applications, handle indirect system calls.
 * Note that we declare this interface to use the maximum number of
 * system call arguments.  If we recieve a system call that uses less
 * arguments, then the additional arguments will be garbage, but they
 * will also be ignored so that should be ok.
 */
long
brand_indir(sysret_t *rv, int code,
    uintptr_t a0, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
    uintptr_t a5, uintptr_t a6, uintptr_t a7)
{
	brand_sysent_table_t *sst = &(brand_sysent_table[code]);

	brand_assert(code < NSYSCALL);
	switch (sst->st_args & NARGS_MASK) {
	case 0:
		return ((sst->st_callc)(rv));
	case 1:
		return ((sst->st_callc)(rv, a0));
	case 2:
		return ((sst->st_callc)(rv, a0, a1));
	case 3:
		return ((sst->st_callc)(rv, a0, a1, a2));
	case 4:
		return ((sst->st_callc)(rv, a0, a1, a2, a3));
	case 5:
		return ((sst->st_callc)(rv, a0, a1, a2, a3, a4));
	case 6:
		return ((sst->st_callc)(rv, a0, a1, a2, a3, a4, a5));
	case 7:
		return ((sst->st_callc)(rv, a0, a1, a2, a3, a4, a5, a6));
	case 8:
		return ((sst->st_callc)(rv, a0, a1, a2, a3, a4, a5, a6, a7));
	}
	brand_abort(0, "invalid entry in brand_sysent_table");
	return (EINVAL);
}
#endif /* __sparc && !__sparcv9 */

/*
 * Close a libc file handle, but don't actually close the underlying
 * file descriptor.
 */
static void
brand_close_fh(FILE *file)
{
	int fd, fd_new;

	if (file == NULL)
		return;

	if ((fd = fileno(file)) < 0)
		return;

	/*
	 * We're a branded process but our handler isn't installed yet.  We
	 * can't use the dup() syscall since it no longer exists. Unfortunately
	 * in an S10 branded zone, this will all pick up the old libc and not
	 * use emulation, which makes it fairly impossible to use safely.
	 */
	fd_new = fcntl(fd, F_DUPFD, 0);
	if (fd_new == -1)
		return;

	(void) fclose(file);
	(void) dup2(fd_new, fd);
	(void) close(fd_new);
}

/*ARGSUSED*/
void
brand_pre_init()
{
	int			i;

	/* Sanity check our translation table return value codes */
	for (i = 0; i < NSYSCALL; i++) {
		brand_sysent_table_t *est = &(brand_sysent_table[i]);
		brand_assert(BIT_ONLYONESET(est->st_args & RV_MASK));
	}

	/*
	 * We need to shutdown all libc stdio.  libc stdio normally goes to
	 * file descriptors, but since we're actually part of a another
	 * process we don't own these file descriptors and we can't make
	 * any assumptions about their state.
	 */
	brand_close_fh(stdin);
	brand_close_fh(stdout);
	brand_close_fh(stderr);
}

/*ARGSUSED*/
ulong_t
brand_post_init(int version, int argc, char *argv[], char *envp[])
{
	sysret_t		rval;
	brand_proc_reg_t	reg;
	brand_elf_data_t	sed;
	auxv_t			*ap;
	uintptr_t		*p;
	int			err;

	/*
	 * Register our syscall emulation table with the kernel.
	 * Note that we don't have to do invoke (syscall_number + 1024)
	 * until we've actually establised a syscall emulation callback
	 * handler address, which is what we're doing with this brand
	 * syscall.
	 */
	reg.sbr_version = version;
#ifdef	__x86
	reg.sbr_handler = (caddr_t)brand_handler_table;
#else	/* !__x86 */
	reg.sbr_handler = (caddr_t)brand_handler;
#endif	/* !__x86 */

	if ((err = __systemcall(&rval, SYS_brand, B_REGISTER, &reg)) != 0) {
		brand_abort(err, "Failed to brand current process");

		/*NOTREACHED*/
	}

	/* Get data about the executable we're running from the kernel. */
	if ((err = __systemcall(&rval, SYS_brand + 1024,
	    B_ELFDATA, (void *)&sed)) != 0) {
		brand_abort(err,
		    "Failed to get required brand ELF data from the kernel");
		/*NOTREACHED*/
	}

	/*
	 * Find the aux vector on the stack.
	 */
	p = (uintptr_t *)envp;
	while (*p != 0)
		p++;

	/*
	 * p is now pointing at the 0 word after the environ pointers.
	 * After that is the aux vectors.
	 *
	 * The aux vectors are currently pointing to the brand emulation
	 * library and associated linker.  We're going to change them to
	 * point to the brand executable and associated linker (or to no
	 * linker for static binaries).  This matches the process data
	 * stored within the kernel and visible from /proc, which was
	 * all setup in sn1_elfexec().  We do this so that when a debugger
	 * attaches to the process it sees the process as a normal solaris
	 * process, this brand emulation library and everything on it's
	 * link map will not be visible, unless our librtld_db plugin
	 * is used.  Note that this is very different from how Linux
	 * branded processes are implemented within lx branded zones.
	 * In that situation, the primary linkmap of the process is the
	 * brand emulation libraries linkmap, not the Linux applications
	 * linkmap.
	 *
	 * We also need to clear the AF_SUN_NOPLM flag from the AT_SUN_AUXFLAGS
	 * aux vector.  This flag told our linker that we don't have a
	 * primary link map.  Now that our linker is done initializing, we
	 * want to clear this flag before we transfer control to the
	 * applications copy of the linker, since we want that linker to have
	 * a primary link map which will be the link map for the application
	 * we're running.
	 */
	p++;
	for (ap = (auxv_t *)p; ap->a_type != AT_NULL; ap++) {
		switch (ap->a_type) {
			case AT_BASE:
				/* Hide AT_BASE if static binary */
				if (sed.sed_base == 0) {
					ap->a_type = AT_IGNORE;
					ap->a_un.a_val = 0;
				} else {
					ap->a_un.a_val = sed.sed_base;
				}
				break;
			case AT_ENTRY:
				ap->a_un.a_val = sed.sed_entry;
				break;
			case AT_PHDR:
				ap->a_un.a_val = sed.sed_phdr;
				break;
			case AT_PHENT:
				ap->a_un.a_val = sed.sed_phent;
				break;
			case AT_PHNUM:
				ap->a_un.a_val = sed.sed_phnum;
				break;
			case AT_SUN_AUXFLAGS:
				ap->a_un.a_val &= ~AF_SUN_NOPLM;
				break;
			case AT_SUN_EMULATOR:
				/*
				 * ld.so.1 inspects AT_SUN_EMULATOR to see if
				 * if it is the linker for the brand emulation
				 * library.  Hide AT_SUN_EMULATOR, as the
				 * linker we are about to jump to is the linker
				 * for the binary.
				 */
				ap->a_type = AT_IGNORE;
				ap->a_un.a_val = 0;
				break;
			case AT_SUN_LDDATA:
				/* Hide AT_SUN_LDDATA if static binary */
				if (sed.sed_lddata == 0) {
					ap->a_type = AT_IGNORE;
					ap->a_un.a_val = 0;
				} else {
					ap->a_un.a_val = sed.sed_lddata;
				}
				break;
			default:
				break;
		}
	}

	return (sed.sed_ldentry);
}
\
\ Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
\
\ 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
\


#include <sys/types.h>
#include <sys/regset.h>
#include <sys/ucontext.h>
#include <sys/syscall.h>

greg_t		SIZEOF_GREG_T

gregset_t	SIZEOF_GREGSET_T

sysret_t	SIZEOF_SYSRET_T
/*
 * 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) 2010, Oracle and/or its affiliates. All rights reserved.
 */

#ifndef _BRAND_MISC_H
#define	_BRAND_MISC_H

#ifdef	__cplusplus
extern "C" {
#endif

/*
 * This header file must uses _ASM defines to allow it to be included
 * in assmebly source files
 */
#include <sys/asm_linkage.h>
#include <sys/regset.h>
#include <sys/syscall.h>
#if !defined(_ASM)
#include <sys/brand.h>
#endif
#include "assym.h"

/*
 * Our syscall emulation callback handler adds one argument to each
 * system call, so we'll need to allocate space for one more argument
 * above the maximum number of arguments that a system call can normally
 * take.  Also, we assume that each syscall argument is a long, ie, we
 * don't support long long syscall parameters.
 */
#if defined(__sparc)
/*
 * 32-bit and 64-bit sparc syscalls can take up to 8 arguments.
 * 32-bit sparc indirect syscalls can take up to 9 arguments.
 * Arguments 1 - 6 are passed via %o0 - %o5.
 * Additional arguments are passed on the stack.
 * So make space for 4 arguments on the stack.
 */
#define	EH_ARGS_COUNT		4
#elif defined(__amd64)
/*
 * amd64 syscalls can take up to 8 arguments.
 * Arguments 1 - 6 are passed via: %rdi, %rsi, %rdx, %r10, %r8, %r9
 * Additional arguments are passed on the stack.
 * So make space for 3 arguments on the stack.
 */
#define	EH_ARGS_COUNT		3
#else /* !__sparc && !__amd64 */
/*
 * ia32 syscalls can take up to 8 arguments.
 * All arguments are passed on the stack.
 * So make space for 9 arguments on the stack.
 */
#define	EH_ARGS_COUNT		9
#endif /* !__sparc && !__amd64 */


#define	EH_ARGS_SIZE		(CPTRSIZE * EH_ARGS_COUNT)
#define	EH_ARGS_OFFSET(x)	(STACK_BIAS + MINFRAME + (CPTRSIZE * (x)))
#define	EH_LOCALS_SIZE		(EH_ARGS_SIZE + SIZEOF_GREGSET_T + \
				    SIZEOF_SYSRET_T + CPTRSIZE)

#if defined(__sparc)
/*
 * On sparc, all emulation callback handler variable access is done
 * relative to %sp, so access offsets are positive.
 */
#define	EH_LOCALS_START		(STACK_BIAS + MINFRAME + EH_ARGS_SIZE)
#define	EH_LOCALS_END_TGT	(STACK_BIAS + MINFRAME + EH_LOCALS_SIZE)
#else /* !__sparc */
/*
 * On x86, all emulation callback handler variable access is done
 * relative to %ebp/%rbp, so access offsets are negative.
 */
#define	EH_LOCALS_START		(-(EH_LOCALS_SIZE - \
				    (STACK_BIAS + MINFRAME + EH_ARGS_SIZE)))
#define	EH_LOCALS_END_TGT	0
#endif /* !__sparc */

/*
 * In our emulation callback handler, our stack will look like:
 *		-------------------------------------------------
 *	  %bp   | long		rvflag				|
 *	   |    | sysret_t	sysret				|
 *	   v    | gregset_t	gregs				|
 *	  %sp   | long		callback args[EH_ARGS_COUNT]	|
 *		-------------------------------------------------
 * For ia32, use %ebp and %esp instead of %bp and %sp.
 * For amd64, use %rbp and %rsp instead of %bp and %sp.
 *
 * Our emulation callback handler always saves enough space to hold the
 * maximum number of stack arguments to a system call.  This is architecture
 * specific and is defined via EH_ARGS_COUNT.
 */
#define	EH_LOCALS_GREGS		(EH_LOCALS_START)
#define	EH_LOCALS_GREG(x)	(EH_LOCALS_GREGS + (SIZEOF_GREG_T * (x)))
#define	EH_LOCALS_SYSRET	(EH_LOCALS_GREGS + SIZEOF_GREGSET_T)
#define	EH_LOCALS_SYSRET1	(EH_LOCALS_SYSRET)
#define	EH_LOCALS_SYSRET2	(EH_LOCALS_SYSRET + CPTRSIZE)
#define	EH_LOCALS_RVFLAG	(EH_LOCALS_SYSRET + SIZEOF_SYSRET_T)
#define	EH_LOCALS_END		(EH_LOCALS_RVFLAG + CPTRSIZE)

#if (EH_LOCALS_END != EH_LOCALS_END_TGT)
#error "brand_misc.h EH_LOCALS_* macros don't add up"
#endif /* (EH_LOCALS_END != EH_LOCALS_END_TGT) */

/*
 * The second parameter of each entry in the {BRAND}_sysent_table
 * contains the number of parameters and flags that describe the
 * syscall return value encoding.
 *
 * When declaring new syscall emulation functions, it is very important
 * to to set the proper RV_* flags in the brand_sysent_table.  Upon failure,
 * syscall emulation fuctions should return an errno value.  Upon success
 * syscall emulation functions should return 0 and set the sysret_t return
 * value parameters accordingly.
 *
 * There are five possible syscall macro wrappers used in the kernel's system
 * call sysent table.  These turn into the following return values:
 *	SYSENT_CL	-> SYSENT_C or SYSENT_CI
 *	SYSENT_C	SE_64RVAL		RV_DEFAULT
 *	SYSENT_CI	SE_32RVAL1		RV_DEFAULT
 *	SYSENT_2CI	SE_32RVAL1|SE_32RVAL2	RV_32RVAL2
 *	SYSENT_AP	SE_64RVAL		RV_64RVAL
 *
 */
#define	NARGS_MASK	0x000000FF	/* Mask for syscalls argument count */
#define	RV_MASK		0x0000FF00	/* Mask for return value flags */
#define	RV_DEFAULT	0x00000100	/* syscall returns "default" values */
#define	RV_32RVAL2	0x00000200	/* syscall returns two 32-bit values */
#define	RV_64RVAL	0x00000400	/* syscall returns a 64-bit value */

#if !defined(_ASM)

/*
 * We define our own version of assert because the default one will
 * try to emit a localized message.  That is bad because first, we can't
 * emit messages to random file descriptors, and second localizing a message
 * requires allocating memory and we can't do that either.
 */
#define	brand_assert(ex)	(void)((ex) || \
				(_brand_abort(0, #ex, __FILE__, __LINE__), 0))
#define	brand_abort(err, msg)	_brand_abort((err), (msg), __FILE__, __LINE__)
#define	EMULATE(cb, args)	{ (sysent_cb_t)(uintptr_t)(cb), (args) }
#define	NOSYS			EMULATE(brand_unimpl, (0 | RV_DEFAULT))

typedef long (*sysent_cb_t)();
typedef struct brand_sysent_table {
	sysent_cb_t	st_callc;
	uintptr_t	st_args;
} brand_sysent_table_t;

/*
 * These macros invoke a brandsys subcommand, B_TRUSS_POINT, used to expose
 * a call to an interpositioned syscall that would have otherwise gone
 * unnoticed by truss(1) because the interpositioned system call did not call
 * any system calls before returning.
 */
#define	B_TRUSS_POINT_5(rval, syscall_num, err, a0, a1, a2, a3, a4) \
	__systemcall(rval, SYS_brand + 1024, \
	    B_TRUSS_POINT, (syscall_num), (err), (a0), (a1), (a2), (a3), \
	    (a4))

#define	B_TRUSS_POINT_4(rval, syscall_num, err, a0, a1, a2, a3) \
	B_TRUSS_POINT_5(rval, (syscall_num), (err), (a0), (a1), (a2), (a3), 0)

#define	B_TRUSS_POINT_3(rval, syscall_num, err, a0, a1, a2) \
	B_TRUSS_POINT_5(rval, (syscall_num), (err), (a0), (a1), (a2), 0, 0)

#define	B_TRUSS_POINT_2(rval, syscall_num, err, a0, a1) \
	B_TRUSS_POINT_5(rval, (syscall_num), (err), (a0), (a1), 0, 0, 0)

#define	B_TRUSS_POINT_1(rval, syscall_num, err, a0) \
	B_TRUSS_POINT_5(rval, (syscall_num), (err), (a0), 0, 0, 0, 0)

#define	B_TRUSS_POINT_0(rval, syscall_num, err) \
	B_TRUSS_POINT_5(rval, (syscall_num), (err), 0, 0, 0, 0, 0)

/*
 * From runexe.s
 */
extern void brand_runexe(void *, ulong_t);

/*
 * From handler.s
 */
extern void brand_handler_table(void);
extern void brand_handler(void);
extern void brand_error(void);
extern void brand_success(void);

/*
 * From brand_util.c
 */
extern long brand_unimpl(sysret_t *rv, uintptr_t p1);
extern void _brand_abort(int, const char *, const char *, int);
extern int brand_uucopy(const void *, void *, size_t);
extern int brand_uucopystr(const void *, void *, size_t);
extern void brand_pre_init();
extern ulong_t brand_post_init(int, int, char **, char **);
#if defined(__sparc) && !defined(__sparcv9)
extern long brand_indir(sysret_t *, int, uintptr_t, uintptr_t, uintptr_t,
	uintptr_t, uintptr_t, uintptr_t, uintptr_t, uintptr_t);
#endif /* __sparc && !__sparcv9 */

#endif	/* !_ASM */

#ifdef	__cplusplus
}
#endif

#endif	/* _BRAND_MISC_H */
#
# 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) 2010, Oracle and/or its affiliates. All rights reserved.
#
# Copyright (c) 2018, Joyent, Inc.

include $(SRC)/lib/Makefile.lib

LIBRARY =	$(BRAND)_librtld_db.a
VERS	=	.1

CSRCS =		$(COBJS:%o=$(BRAND_SHARED)/librtld_db/common/%c)
SRCS  =		$(CSRCS)

SRCDIR =	$(BRAND_SHARED)/librtld_db/common
UTSBASE	=	$(SRC)/uts

#
# ATTENTION:
#	Librtl_db brand plugin libraries should NOT directly invoke any
#	libproc.so interfaces or be linked against libproc.  If a librtl_db
#	brand plugin library uses libproc.so interfaces then it may break
#	any other librtld_db consumers (like mdb) that tries to attach
#	to a branded process.  The only safe interfaces that the a librtld_db
#	brand plugin library can use to access a target process are the
#	proc_service(3PROC) apis.
#
# Hammerhead: Disable -zdefs because ps_pauxv, ps_pdmodel, ps_plog etc.
# are proc_service(3PROC) callbacks provided by the caller at runtime
ZDEFS =
# Hammerhead: Don't add mapfile to DYNFLAGS - it's already in MAPFILES via SRCDIR
DYNFLAGS +=	$(VERSREF)
LIBS =		$(DYNLIB)
LDLIBS +=	-lc -lrtld_db
CFLAGS +=	$(CCVERBOSE)
CPPFLAGS +=	-D_REENTRANT \
			-I$(SRC)/cmd/sgs/librtld_db/common \
			-I$(SRC)/cmd/sgs/include \
			-I$(SRC)/cmd/sgs/include/$(MACH)

# not linted
SMATCH=off

ROOTLIBDIR =	$(ROOT)/usr/lib/brand/$(BRAND)
# Hammerhead: 64-bit only - flatten brand library path
ROOTLIBDIR64 =	$(ROOT)/usr/lib/brand/$(BRAND)

#
# The top level Makefiles define define TEXT_DOMAIN.  But librtld_db.so.1
# isn't internationalized and this library won't be either.  The only
# messages that this library can generate are messages used for debugging
# the operation of the library itself.
#
DTEXTDOM =

.KEEP_STATE:

all: $(LIBS)


pics/%64.o:	$(BRAND_SHARED)/librtld_db/common/%.c
		$(COMPILE.c) -D_ELF64 $(PICFLAGS) -o $@ $<
		$(POST_PROCESS_O)

include $(SRC)/lib/Makefile.targ
/*
 * 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) 2010, Oracle and/or its affiliates. All rights reserved.
 */

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <libproc.h>
#include <proc_service.h>
#include <synch.h>
#include <sys/types.h>
#include <sys/link.h>
#include <rtld_db.h>
#include <sys/brand.h>

/*
 * ATTENTION:
 *	Librtl_db brand plugin libraries should NOT directly invoke any
 *	libproc.so interfaces or be linked against libproc.  If a librtl_db
 *	brand plugin library uses libproc.so interfaces then it may break
 *	any other librtld_db consumers (like mdb) that tries to attach
 *	to a branded process.  The only safe interfaces that the a librtld_db
 *	brand plugin library can use to access a target process are the
 *	proc_service(3PROC) apis.
 */

/*
 * M_DATA comes from some streams header file but is also redifined in
 * _rtld_db.h, so nuke the old streams definition here.
 */
#ifdef M_DATA
#undef M_DATA
#endif /* M_DATA */

/*
 * For 32-bit versions of this library, this file get's compiled once.
 * For 64-bit versions of this library, this file get's compiled twice,
 * once with _ELF64 defined and once without.  The expectation is that
 * the 64-bit version of the library can properly deal with both 32-bit
 * and 64-bit elf files, hence in the 64-bit library there are two copies
 * of all the interfaces in this file, one set named *32 and one named *64.
 *
 * This also means that we need to be careful when declaring local pointers
 * that point to objects in another processes address space, since these
 * pointers may not match the current processes pointer width.  Basically,
 * we should not use any objects that change size between 32 and 64 bit
 * modes like: long, void *, uintprt_t, caddr_t, psaddr_t, size_t, etc.
 * Instead we should declare all pointers as uint32_t.  Then when we
 * are compiled to deal with 64-bit targets we'll re-define uing32_t
 * to be a uint64_t.
 */
#ifdef _LP64
#ifdef _ELF64
#define	uint32_t			uint64_t
#define	Elf32_Dyn			Elf64_Dyn
#define	validate_rdebug32		validate_rdebug64
#define	_rd_loadobj_iter32		_rd_loadobj_iter64
#define	_rd_get_dyns32			_rd_get_dyns64
#define	dummy_ldb32			dummy_ldb64
#define	dummy_ldb_init32		dummy_ldb_init64
#define	dummy_ldb_fini32		dummy_ldb_fini64
#define	dummy_ldb_loadobj_iter32	dummy_ldb_loadobj_iter64
#define	dummy_ldb_get_dyns32		dummy_ldb_get_dyns64
#define	brand_ldb_init32		brand_ldb_init64
#define	brand_ldb_fini32		brand_ldb_fini64
#define	brand_ldb_loadobj_iter32	brand_ldb_loadobj_iter64
#define	brand_ldb_get_dyns32		brand_ldb_get_dyns64
#endif /* _ELF64 */
#endif /* _LP64 */

/* Included from usr/src/cmd/sgs/librtld_db/common */
#include <_rtld_db.h>

/*ARGSUSED*/
static rd_helper_data_t
dummy_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php)
{
	return (NULL);
}

/*ARGSUSED*/
static void
dummy_ldb_fini32(rd_helper_data_t rhd)
{
}

/*ARGSUSED*/
static int
dummy_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data)
{
	return (RD_OK);
}

/*ARGSUSED*/
static rd_err_e
dummy_ldb_get_dyns32(rd_helper_data_t rhd,
    psaddr_t addr, void **dynpp, size_t *dynpp_sz)
{
	*dynpp = NULL;
	*dynpp_sz = 0;
	return (RD_OK);
}

static rd_helper_ops_t dummy_ldb32 = {
	LM_ID_BRAND,
	dummy_ldb_init32,
	dummy_ldb_fini32,
	dummy_ldb_loadobj_iter32,
	dummy_ldb_get_dyns32
};

static uint32_t
brand_ldb_getauxval32(struct ps_prochandle *php, int type)
{
	const auxv_t		*auxvp = NULL;

	if (ps_pauxv(php, &auxvp) != PS_OK)
		return ((uint32_t)-1);

	while (auxvp->a_type != AT_NULL) {
		if (auxvp->a_type == type)
			return ((uint32_t)(uintptr_t)auxvp->a_un.a_ptr);
		auxvp++;
	}
	return ((uint32_t)-1);
}

/*
 * Normally, the native Solaris librtldb_db plugin uses a bunch of different
 * methods to try and find the rdebug structure associated with the target
 * process we're debugging.  For details on the different methods see
 * _rd_reset32().  Thankfully our job is easier.  We know that the brand
 * library is always linked against the native linker, and when the
 * process was first executed we saved off a pointer to the brand linkers
 * rdebug structure in one of our brand specific aux vectors,
 * AT_SUN_BRAND_COMMON_LDDATA.  So we'll just look that up here.
 */
/*ARGSUSED*/
static rd_helper_data_t
brand_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php)
{
	struct rd_agent	*rap_new;
	uint32_t	lddata_addr;
	int		rd_dmodel;

	if (ps_pdmodel(php, &rd_dmodel) != PS_OK) {
		ps_plog("brand_ldb_init: lookup of data model failed");
		return (NULL);
	}
#ifdef _ELF64
	assert(rd_dmodel == PR_MODEL_LP64);
#else /* !_ELF64 */
	assert(rd_dmodel == PR_MODEL_ILP32);
#endif /* !_ELF64 */

	lddata_addr = brand_ldb_getauxval32(php, AT_SUN_BRAND_COMMON_LDDATA);
	if (lddata_addr == (uint32_t)-1) {
		ps_plog("brand_ldb_init: no LDDATA found in aux vector");
		return (NULL);
	}
	ps_plog("brand_ldb_init: found LDDATA auxv ld.so.1 data seg "
	    "at: 0x%p", lddata_addr);

	/*
	 * Ok.  So this is kinda ugly.  Basically we know that we're going to
	 * be parsing data from link maps that are generated by a Solaris
	 * linker.  As it turns out, that's exactly what the default
	 * Solaris librtld_db library is designed to do.  So rather than
	 * duplicate all that link map parsing code here we'll simply
	 * invoke the native librtld_db that normally does this, and when
	 * we do we'll point them at our emulation libraries link map.
	 *
	 * Of course these interfacess aren't really public interfaces
	 * and they take a "struct rd_agent" as a parameter.  So here
	 * we'll allocate and initialize a new "struct rd_agent", point
	 * it at our emulation libraries link map, and initialize just
	 * enough of the structure to make the librtld_db interfaces
	 * that we want to use happy.
	 */
	if ((rap_new = calloc(sizeof (*rap_new), 1)) == NULL) {
		ps_plog("brand_ldb_init: can't allocate memory");
		return (NULL);
	}
	rap_new->rd_dmodel = rd_dmodel;
	rap_new->rd_psp = php;
	rap_new->rd_rdebug = lddata_addr;
	(void) mutex_init(&rap_new->rd_mutex, USYNC_THREAD, 0);

	/*
	 * When we get invoked from librtld_db, and we call back into it,
	 * librtld_db will once again check if there is a plugin and
	 * invoke it.  Since we don't want to enter a recursive loop
	 * we're going to specify a different plugin interface for
	 * our linkmap, and these new plugin interfaces won't actually
	 * do anything other than return.
	 */
	rap_new->rd_helper.rh_ops = &dummy_ldb32;

	/*
	 * validate_rdebug32() requires the following "struct rd_agent"
	 * members to be initialized:
	 *	rd_psp, rd_rdebug
	 *
	 * validate_rdebug32() initializes the following "struct rd_agent"
	 * members:
	 *	rd_flags, rd_rdebugvers, rd_rtlddbpriv
	 */
	if (validate_rdebug32(rap_new) != RD_OK) {
		ps_plog("brand_ldb_init: can't find valid r_debug data");
		free(rap_new);
		return (NULL);
	}

	ps_plog("brand_ldb_init: finished, helper_data=0x%p", rap_new);
	return ((rd_helper_data_t)rap_new);
}

static void
brand_ldb_fini32(rd_helper_data_t rhd)
{
	struct rd_agent	*rap = (struct rd_agent *)rhd;
	ps_plog("brand_ldb_fini: cleaning up brand helper");
	free(rap);
}

/*ARGSUSED*/
static int
brand_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data)
{
	struct rd_agent	*rap = (struct rd_agent *)rhd;
	int		err;

	ps_plog("brand_ldb_loadobj_iter(helper_data=0x%p)", rhd);
	assert(rap->rd_psp == php);
	RDAGLOCK(rap);
	/*
	 * _rd_loadobj_iter32() requires the following "struct rd_agent"
	 * members to be initialized:
	 * 	rd_rtlddbpriv, rd_rdebugvers, rd_flags,
	 * 	rd_helper.rh_ops, rd_dmodel
	 */
	err = _rd_loadobj_iter32(rap, cb, client_data);
	RDAGUNLOCK(rap);
	ps_plog("brand_ldb_loadobj_iter: finished, err = %d", err);
	return (err);
}

/*ARGSUSED*/
static rd_err_e
brand_ldb_get_dyns32(rd_helper_data_t rhd,
    psaddr_t addr, void **dynpp, size_t *dynpp_sz)
{
	struct rd_agent	*rap = (struct rd_agent *)rhd;
	int		err;

	ps_plog("brand_ldb_get_dyns(helper_data=0x%p)", rhd);
	err = _rd_get_dyns32(rap, addr, (Elf32_Dyn **)dynpp, dynpp_sz);
	ps_plog("brand_ldb_get_dyns: finished, err = %d", err);
	return (err);
}

/*
 * Librtld_db plugin linkage struct.
 *
 * When we get loaded by librtld_db, it will look for the symbol below
 * to find our plugin entry points.
 */
rd_helper_ops_t RTLD_DB_BRAND_OPS = {
	LM_ID_NONE,
	brand_ldb_init32,
	brand_ldb_fini32,
	brand_ldb_loadobj_iter32,
	brand_ldb_get_dyns32
};
#
# 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) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
#

#
# MAPFILE HEADER START
#
# WARNING:  STOP NOW.  DO NOT MODIFY THIS FILE.
# Object versioning must comply with the rules detailed in
#
#	usr/src/lib/README.mapfiles
#
# You should not be making modifications here until you've read the most current
# copy of that file. If you need help, contact a gatekeeper for guidance.
#
# MAPFILE HEADER END
#

$mapfile_version 2

SYMBOL_VERSION SUNWprivate_1.1 {
    global:
	rtld_db_brand_ops32	{
				  ASSERT = {
					  TYPE = OBJECT;
					  SIZE = addrsize[5];
					};
				};

$if _ELF64
	rtld_db_brand_ops64	{
				  ASSERT = {
					  TYPE = OBJECT;
					  SIZE = addrsize[5];
					};
				};
$endif

    local:
	*;
};

#Externally defined symbols
SYMBOL_SCOPE {
    global:
	ps_pauxv		{ FLAGS = NODIRECT PARENT; };
	ps_pdmodel		{ FLAGS = NODIRECT PARENT; };
	ps_pglobal_lookup	{ FLAGS = NODIRECT PARENT; };
	ps_pglobal_sym		{ FLAGS = NODIRECT PARENT; };
	ps_plog			{ FLAGS = NODIRECT PARENT; };
	ps_pread		{ FLAGS = NODIRECT PARENT; };
	ps_pwrite		{ FLAGS = NODIRECT PARENT; };
};
#
# 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) 2010, Oracle and/or its affiliates. All rights reserved.
#

PROG=query
SHARED=	common.ksh query uninstall.ksh

include $(SRC)/cmd/Makefile.cmd
include ../../Makefile.brand

$(ROOTSHAREDDIR)/common.ksh : FILEMODE = 0444
$(ROOTSHAREDDIR)/uninstall.ksh : FILEMODE = 0444

POFILES=	common.po query.po uninstall.po
POFILE=		shared.po

$(POFILE): $(POFILES)
	$(RM) $@
	$(CAT) $(POFILES) > $@

all: $(PROG)

install: $(ROOTSHARED)

clean:


include $(SRC)/cmd/Makefile.targ
#
# 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) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
#

#
# Send the error message to the screen and to the logfile.
#
error()
{
        typeset fmt="$1"
        shift

        printf "${MSG_PREFIX}ERROR: ${fmt}\n" "$@"
        [[ -n $LOGFILE ]] && printf "[$(date)] ERROR: ${fmt}\n" "$@" >&2
}

fatal()
{
        typeset fmt="$1"
        shift

	error "$fmt" "$@"
	exit $EXIT_CODE
}

fail_fatal() {
        typeset fmt="$1"
        shift

	error "$fmt" "$@"
	exit $ZONE_SUBPROC_FATAL
}

#
# Send the provided printf()-style arguments to the screen and to the logfile.
#
log()
{
        typeset fmt="$1"
        shift

        printf "${MSG_PREFIX}${fmt}\n" "$@"
        [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2
}

#
# Print provided text to the screen if the shell variable "OPT_V" is set.
# The text is always sent to the logfile.
#
vlog()
{
        typeset fmt="$1"
        shift

        [[ -n $OPT_V ]] && printf "${MSG_PREFIX}${fmt}\n" "$@"
        [[ -n $LOGFILE ]] && printf "[$(date)] ${MSG_PREFIX}${fmt}\n" "$@" >&2
}

#
# Validate that the directory is safe.
#
# It is possible for a malicious zone root user to modify a zone's filesystem
# so that modifications made to the zone's filesystem by administrators in the
# global zone modify the global zone's filesystem.  We can prevent this by
# ensuring that all components of paths accessed by scripts are real (i.e.,
# non-symlink) directories.
#
# NOTE: The specified path should be an absolute path as would be seen from
# within the zone.  Also, this function does not check parent directories.
# If, for example, you need to ensure that every component of the path
# '/foo/bar/baz' is a directory and not a symlink, then do the following:
#
#	safe_dir /foo
#	safe_dir /foo/bar
#	safe_dir /foo/bar/baz
#
safe_dir()
{
	typeset dir="$1"

	if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then
		fatal "$e_baddir" "$dir"
	fi
}

# Like safe_dir except the dir doesn't have to exist.
safe_opt_dir()
{
	typeset dir="$1"

	[[ ! -e $ZONEROOT/$dir ]] && return

	if [[ -h $ZONEROOT/$dir || ! -d $ZONEROOT/$dir ]]; then
		fatal "$e_baddir" "$dir"
	fi
}

# Only make a copy if we haven't already done so.
safe_backup()
{
	typeset src="$1"
	typeset dst="$2"

	if [[ ! -h $src && ! -h $dst && ! -d $dst && ! -f $dst ]]; then
		/bin/cp -p $src $dst || fatal "$e_badfile" "$src"
	fi
}

# Make a copy even if the destination already exists.
safe_copy()
{
	typeset src="$1"
	typeset dst="$2"

	if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then
		/bin/cp -p $src $dst || fatal "$e_badfile" "$src"
	fi
}

# Move a file
safe_move()
{
	typeset src="$1"
	typeset dst="$2"

	if [[ ! -h $src && ! -h $dst && ! -d $dst ]]; then
		/bin/mv $src $dst || fatal "$e_badfile" "$src"
	fi
}

safe_rm()
{
	if [[ ! -h $ZONEROOT/$1 && -f $ZONEROOT/$1 ]]; then
		rm -f "$ZONEROOT/$1"
	fi
}

#
# Replace the file with a wrapper pointing to the native brand code.
# However, we only do the replacement if the file hasn't already been
# replaced with our wrapper.  This function expects the cwd to be the
# location of the file we're replacing.
#
# Some of the files we're replacing are hardlinks to isaexec so we need to 'rm'
# the file before we setup the wrapper while others are hardlinks to rc scripts
# that we need to maintain.
#
safe_replace()
{
	typeset filename="$1"
	typeset runname="$2"
	typeset mode="$3"
	typeset own="$4"
	typeset rem="$5"

	if [ -h $filename -o ! -f $filename ]; then
		return
	fi

	egrep -s "Solaris Brand Replacement" $filename
	if [ $? -eq 0 ]; then
		return
	fi

	safe_backup $filename $filename.pre_p2v
	if [ $rem = "remove" ]; then
		rm -f $filename
	fi

	cat <<-END >$filename || exit 1
	#!/bin/sh -p
	#
	# Solaris Brand Replacement
	#
	# Attention.  This file has been replaced with a new version for
	# use in a virtualized environment.  Modification of this script is not
	# supported and all changes will be lost upon reboot.  The
	# {name}.pre_p2v version of this file is a backup copy of the
	# original and should not be deleted.
	#
	END

	echo ". $runname \"\$@\"" >>$filename || exit 1

	chmod $mode $filename
	chown $own $filename
}

safe_wrap()
{
	typeset filename="$1"
	typeset runname="$2"
	typeset mode="$3"
	typeset own="$4"

	if [ -f $filename ]; then
		log "$e_cannot_wrap" "$filename"
		exit 1
	fi

	cat <<-END >$filename || exit 1
	#!/bin/sh
	#
	# Solaris Brand Wrapper
	#
	# Attention.  This file has been created for use in a
	# virtualized environment.  Modification of this script
	# is not supported and all changes will be lost upon reboot.
	#
	END

	echo ". $runname \"\$@\"" >>$filename || exit 1

	chmod $mode $filename
	chown $own $filename
}

#
# Read zonecfg fs entries and save the relevant data, one entry per
# line.
# This assumes the properties from the zonecfg output, e.g.:
#	fs:
#		dir: /opt
#		special: /opt
#		raw not specified
#		type: lofs
#		options: [noexec,ro,noatime]
#
# and it assumes the order of the fs properties as above.
#
get_fs_info()
{
	zonecfg -z $zonename info fs | nawk '{
		if ($1 == "options:") {
			# Remove brackets.
			options=substr($2, 2, length($2) - 2);
			printf("%s %s %s %s\n", dir, type, special, options);
		} else if ($1 == "dir:") {
			dir=$2;
		} else if ($1 == "special:") {
			special=$2;
		} else if ($1 == "type:") {
			type=$2
		}
	}' >> $fstmpfile
}

#
# Mount zonecfg fs entries into the zonepath.
#
mnt_fs()
{
	if [ ! -s $fstmpfile ]; then
		return;
	fi

	# Sort the fs entries so we can handle nested mounts.
	sort $fstmpfile | nawk -v zonepath=$zonepath '{
		if (NF == 4)
			options="-o " $4;
		else
			options=""

		# Create the mount point.  Ignore errors since we might have
		# a nested mount with a pre-existing mount point.
		cmd="/bin/mkdir -p " zonepath "/root" $1 " >/dev/null 2>&1"
		system(cmd);

		cmd="/sbin/mount -F " $2 " " options " " $3 " " \
		    zonepath "/root" $1;
		if (system(cmd) != 0) {
			printf("command failed: %s\n", cmd);
			exit 1;
		}
	}' >>$LOGFILE
}

#
# Unmount zonecfg fs entries from the zonepath.
#
umnt_fs()
{
	if [ ! -s $fstmpfile ]; then
		return;
	fi

	# Reverse sort the fs entries so we can handle nested unmounts.
	sort -r $fstmpfile | nawk -v zonepath=$zonepath '{
		cmd="/sbin/umount " zonepath "/root" $1
		if (system(cmd) != 0) {
			printf("command failed: %s\n", cmd);
		}
	}' >>$LOGFILE
}

# Find the dataset mounted on the zonepath.
get_zonepath_ds() {
	ZONEPATH_DS=`/sbin/zfs list -H -t filesystem -o name,mountpoint | \
	    /bin/nawk -v zonepath=$1 '{
		if ($2 == zonepath)
			print $1
	}'`

	if [ -z "$ZONEPATH_DS" ]; then
		fail_fatal "$f_no_ds"
	fi
}

#
# Perform validation and cleanup in the zoneroot after unpacking the archive.
#
post_unpack()
{
	#
	# Check if the image was created with a valid libc.so.1.
	#
	hwcap=`moe -v -32 $ZONEROOT/lib/libc.so.1 2>&1`
	if (( $? != 0 )); then
		vlog "$f_hwcap_info" "$hwcap"
		fail_fatal "$f_sanity_hwcap"
	fi

	( cd "$ZONEROOT" && \
	    find . \( -type b -o -type c \) -exec rm -f "{}" \; )
}

#
# Determine flar compression style from identification file.
#
get_compression()
{
	typeset ident=$1
	typeset line=$(grep "^files_compressed_method=" $ident)

	print ${line##*=}
}

#
# Determine flar archive style from identification file.
#
get_archiver()
{
        typeset ident=$1
        typeset line=$(grep "^files_archived_method=" $ident)

        print ${line##*=}
}

#
# Unpack flar into current directory (which should be zoneroot).  The flash
# archive is standard input.  See flash_archive(5) man page.
# 
# We can't use "flar split" since it will only unpack into a directory called
# "archive".  We need to unpack in place in order to properly handle nested
# fs mounts within the zone root.  This function does the unpacking into the
# current directory.
#
# This code is derived from the gen_split() function in /usr/sbin/flar so
# we keep the same style as the original.
#
install_flar()
{
	typeset result
        typeset archiver_command
        typeset archiver_arguments

	vlog "cd $ZONEROOT && $stage1 "$insrc" | install_flar"

	# Read cookie
	read -r input_line
	if (( $? != 0 )); then
		log "$not_readable" "$install_media"
		return 1
	fi
	# The cookie has format FlAsH-aRcHiVe-m.n where m and n are integers.
	if [[ ${input_line%%-[0-9]*.[0-9]*} != "FlAsH-aRcHiVe" ]]; then
		log "$not_flar"
		return 1
	fi

	while [ true ]
	do
		# We should always be at the start of a section here
		read -r input_line
		if [[ ${input_line%%=*} != "section_begin" ]]; then
			log "$bad_flar"
			return 1
		fi
		section_name=${input_line##*=}

		# If we're at the archive, we're done skipping sections.
		if [[ "$section_name" == "archive" ]]; then
			break
		fi
		
		#
		# Save identification section to a file so we can determine
		# how to unpack the archive.
		#
		if [[ "$section_name" == "identification" ]]; then
			/bin/rm -f identification
			while read -r input_line
			do
				if [[ ${input_line%%=*} == \
				    "section_begin" ]]; then
					/bin/rm -f identification
					log "$bad_flar"
					return 1
				fi

				if [[ $input_line == \
				    "section_end=$section_name" ]]; then
					break;
				fi
				echo $input_line >> identification
			done

			continue
		fi

		#
		# Otherwise skip past this section; read lines until detecting
		# section_end.  According to flash_archive(5) we can have
		# an arbitrary number of sections but the archive section
		# must be last.
		#
		success=0
		while read -r input_line
		do
			if [[ $input_line == "section_end=$section_name" ]];
			then
				success=1
				break
			fi
			# Fail if we miss the end of the section
			if [[ ${input_line%%=*} == "section_begin" ]]; then
				/bin/rm -f identification
				log "$bad_flar"
				return 1
			fi
		done
		if (( $success == 0 )); then
			#
			# If we get here we read to the end of the file before
			# seeing the end of the section we were reading.
			#
			/bin/rm -f identification
			log "$bad_flar"
			return 1
		fi
	done

	# Check for an archive made from a ZFS root pool.
	egrep -s "^rootpool=" identification
        if (( $? == 0 )); then
		/bin/rm -f identification
                log "$bad_zfs_flar"
                return 1
        fi

	# Get the information needed to unpack the archive.
	archiver=$(get_archiver identification)
	if [[ $archiver == "pax" ]]; then
		# pax archiver specified
		archiver_command="/usr/bin/pax"
		if [[ -s $fspaxfile ]]; then
			archiver_arguments="-r -p e -c \
			    $(/bin/cat $fspaxfile)"
		else
			archiver_arguments="-r -p e"
		fi
	elif [[ $archiver == "cpio" || -z $archiver ]]; then
		# cpio archived specified OR no archiver specified - use default
		archiver_command="/usr/bin/cpio"
		archiver_arguments="-icdumfE $fscpiofile"
	else
		# unknown archiver specified
		log "$unknown_archiver" $archiver
		return 1
	fi

	if [[ ! -x $archiver_command ]]; then
		/bin/rm -f identification
		log "$cmd_not_exec" $archiver_command
		return 1
	fi 

	compression=$(get_compression identification)

	# We're done with the identification file
	/bin/rm -f identification

	# Extract archive
	if [[ $compression == "compress" ]]; then
		/usr/bin/zcat | \
		    $archiver_command $archiver_arguments 2>/dev/null
	else
		$archiver_command $archiver_arguments 2>/dev/null
	fi
	result=$?

	post_unpack

	(( $result != 0 )) && return 1

	return 0 
}

#
# Get the archive base.
#
# We must unpack the archive in the right place within the zonepath so
# that files are installed into the various mounted filesystems that are set
# up in the zone's configuration.  These are already mounted for us by the
# mntfs function.
#
# Archives can be made of either a physical host's root file system or a
# zone's zonepath.  For a physical system, if the archive is made using an
# absolute path (/...) we can't use it.  For a zone the admin can make the
# archive from a variety of locations;
#
#   a) zonepath itself: This will be a single dir, probably named with the
#      zone name, it will contain a root dir and under the root we'll see all
#      the top level dirs; etc, var, usr...  We must be above the ZONEPATH
#      when we unpack the archive but this will only work if the the archive's
#      top-level dir name matches the ZONEPATH base-level dir name.  If not,
#      this is an error.
#
#   b) inside the zonepath: We'll see root and it will contain all the top
#      level dirs; etc, var, usr....  We must be in the ZONEPATH when we unpack
#      the archive.
#
#   c) inside the zonepath root: We'll see all the top level dirs, ./etc,
#      ./var, ./usr....  This is also the case we see when we get an archive
#      of a physical system.  We must be in ZONEROOT when we unpack the archive.
#
# Note that there can be a directory named "root" under the ZONEPATH/root
# directory.
#
# This function handles the above possibilities so that we reject absolute
# path archives and figure out where in the file system we need to be to
# properly unpack the archive into the zone.  It sets the ARCHIVE_BASE
# variable to the location where the achive should be unpacked.
#
get_archive_base()
{
	stage1=$1
	archive=$2
	stage2=$3

	vlog "$m_analyse_archive"

	base=`$stage1 $archive | $stage2 2>/dev/null | nawk -F/ '{
		# Check for an absolute path archive
		if (substr($0, 1, 1) == "/")
			exit 1

		if ($1 != ".")
			dirs[$1] = 1
		else
			dirs[$2] = 1
	}
	END {
		for (d in dirs) {
			cnt++
			if (d == "bin")  sawbin = 1
			if (d == "etc")  sawetc = 1
			if (d == "root") sawroot = 1
			if (d == "var")  sawvar = 1
                }

		if (cnt == 1) {
			# If only one top-level dir named root, we are in the
			# zonepath, otherwise this must be an archive *of*
			# the zonepath so print the top-level dir name.
			if (sawroot)
				print "*zonepath*"
			else
				for (d in dirs) print d
		} else {
			# We are either in the zonepath or in the zonepath/root
			# (or at the top level of a full system archive which
			# looks like the zonepath/root case).  Figure out which
			# one.
			if (sawroot && !sawbin && !sawetc && !sawvar)
				print "*zonepath*"
			else
				print "*zoneroot*"
		}
	}'`

	if (( $? != 0 )); then
		umnt_fs
		fatal "$e_absolute_archive"
	fi

	if [[ "$base" == "*zoneroot*" ]]; then
		ARCHIVE_BASE=$ZONEROOT
	elif [[ "$base" == "*zonepath*" ]]; then
		ARCHIVE_BASE=$ZONEPATH
	else
		# We need to be in the dir above the ZONEPATH but we need to
		# validate that $base matches the final component of ZONEPATH.
		bname=`basename $ZONEPATH`

		if [[ "$bname" != "$base" ]]; then
			umnt_fs
			fatal "$e_mismatch_archive" "$base" "$bname"
		fi
		ARCHIVE_BASE=`dirname $ZONEPATH`
	fi
}

#
# Unpack cpio archive into zoneroot.
#
install_cpio()
{
	stage1=$1
	archive=$2

	get_archive_base "$stage1" "$archive" "cpio -it"

	cpioopts="-idmfE $fscpiofile"

	vlog "cd \"$ARCHIVE_BASE\" && $stage1 \"$archive\" | cpio $cpioopts"

	# Ignore errors from cpio since we expect some errors depending on
	# how the archive was made.
	( cd "$ARCHIVE_BASE" && $stage1 "$archive" | cpio $cpioopts )

	post_unpack

	return 0
}

#
# Unpack pax archive into zoneroot.
#
install_pax()
{
	archive=$1

	get_archive_base "cat" "$archive" "pax"

	if [[ -s $fspaxfile ]]; then
		filtopt="-c $(/bin/cat $fspaxfile)"
	fi

	vlog "cd \"$ARCHIVE_BASE\" && pax -r -f \"$archive\" $filtopt"

	# Ignore errors from pax since we expect some errors depending on
	# how the archive was made.
	( cd "$ARCHIVE_BASE" && pax -r -f "$archive" $filtopt )

	post_unpack

	return 0
}

#
# Unpack UFS dump into zoneroot.
#
install_ufsdump()
{
	archive=$1

	vlog "cd \"$ZONEROOT\" && ufsrestore rf \"$archive\""

	#
	# ufsrestore goes interactive if you ^C it.  To prevent that,
	# we make sure its stdin is not a terminal.
	#
	( cd "$ZONEROOT" && ufsrestore rf "$archive" < /dev/null )
	result=$?

	post_unpack

	return $result
}

#
# Copy directory hierarchy into zoneroot.
#
install_dir()
{
	source_dir=$1

	cpioopts="-pdm"

	first=1
	filt=$(for i in $(cat $fspaxfile)
		do
			echo $i | egrep -s "/" && continue
			if [[ $first == 1 ]]; then
				printf "^%s" $i
				first=0
			else
				printf "|^%s" $i
			fi
		done)

	list=$(cd "$source_dir" && ls -d * | egrep -v "$filt")
	flist=$(for i in $list
	do
		printf "%s " "$i"
	done)
	findopts="-xdev ( -type d -o -type f -o -type l ) -print"

	vlog "cd \"$source_dir\" && find $flist $findopts | "
	vlog "cpio $cpioopts \"$ZONEROOT\""

	# Ignore errors from cpio since we expect some errors depending on
	# how the archive was made.
	( cd "$source_dir" && find $flist $findopts | \
	    cpio $cpioopts "$ZONEROOT" )

	post_unpack

	return 0
}

#
# This is a common function for laying down a zone image from a variety of
# different sources.  This can be used to either install a fresh zone or as
# part of zone migration during attach.
#
# The first argument specifies the type of image: archive, directory or stdin.
# The second argument specifies the image itself.  In the case of stdin, the
# second argument specifies the format of the stream (cpio, flar, etc.).
# Any validation or post-processing on the image is done elsewhere.
#
# This function calls a 'sanity_check' function which must be provided by
# the script which includes this code.
#
install_image()
{
	intype=$1
	insrc=$2

	if [[ -z "$intype" || -z "$insrc" ]]; then
		return 1
	fi

	filetype="unknown"
	filetypename="unknown"
	stage1="cat"

	if [[ "$intype" == "directory" ]]; then
		if [[ "$insrc" == "-" ]]; then
			# Indicates that the existing zonepath is prepopulated.
			filetype="existing"
			filetypename="existing"
		else
			if [[ "$(echo $insrc | cut -c 1)" != "/" ]]; then
				fatal "$e_path_abs" "$insrc"
			fi

			if [[ ! -e "$insrc" ]]; then
				log "$e_not_found" "$insrc"
				fatal "$e_install_abort"
			fi

			if [[ ! -r "$insrc" ]]; then
				log "$e_not_readable" "$insrc"
				fatal "$e_install_abort"
			fi

			if [[ ! -d "$insrc" ]]; then
				log "$e_not_dir"
				fatal "$e_install_abort"
			fi

			sanity_check $insrc

			filetype="directory"
			filetypename="directory"
		fi

	else
		# Common code for both archive and stdin stream.

		if [[ "$intype" == "archive" ]]; then
			if [[ ! -f "$insrc" ]]; then
				log "$e_unknown_archive"
				fatal "$e_install_abort"
			fi
			ftype="$(LC_ALL=C file $insrc | cut -d: -f 2)"
		else
			# For intype == stdin, the insrc parameter specifies
			# the stream format coming on stdin.
			ftype="$insrc"
			insrc="-"
		fi

		# Setup vars for the archive type we have.
		case "$ftype" in
		*cpio*)		filetype="cpio"
				filetypename="cpio archive"
			;;
		*bzip2*)	filetype="bzip2"
				filetypename="bzipped cpio archive"
			;;
		*gzip*)		filetype="gzip"
				filetypename="gzipped cpio archive"
			;;
		*ufsdump*)	filetype="ufsdump"
				filetypename="ufsdump archive"
			;;
		"flar")
				filetype="flar"
				filetypename="flash archive"
			;;
		"flash")
				filetype="flar"
				filetypename="flash archive"
			;;
		*Flash\ Archive*)
				filetype="flar"
				filetypename="flash archive"
			;;
		"tar")
				filetype="tar"
				filetypename="tar archive"
			;;
		*USTAR\ tar\ archive)
				filetype="tar"
				filetypename="tar archive"
			;;
		"pax")
				filetype="xustar"
				filetypename="pax (xustar) archive"
			;;
		*USTAR\ tar\ archive\ extended\ format*)
				filetype="xustar"
				filetypename="pax (xustar) archive"
			;;
		"zfs")
				filetype="zfs"
				filetypename="ZFS send stream"
			;;
		*ZFS\ snapshot\ stream*)
				filetype="zfs"
				filetypename="ZFS send stream"
			;;
		*)		log "$e_unknown_archive"
				fatal "$e_install_abort"
			;;
		esac
	fi

	vlog "$filetypename"

	# Check for a non-empty root if no '-d -' option. 
	if [[ "$filetype" != "existing" ]]; then
		cnt=$(ls $ZONEROOT | wc -l)
		if (( $cnt != 0 )); then
			fatal "$e_root_full" "$ZONEROOT"
		fi
	fi

	fstmpfile=$(/usr/bin/mktemp -t -p /var/tmp)
	if [[ -z "$fstmpfile" ]]; then
		fatal "$e_tmpfile"
	fi

	# Make sure we always have the files holding the directories to filter
	# out when extracting from a CPIO or PAX archive.  We'll add the fs
	# entries to these files in get_fs_info()
	fscpiofile=$(/usr/bin/mktemp -t -p /var/tmp fs.cpio.XXXXXX)
	if [[ -z "$fscpiofile" ]]; then
		rm -f $fstmpfile
		fatal "$e_tmpfile"
	fi

	# Filter out these directories.
	echo 'dev/*' >>$fscpiofile
	echo 'devices/*' >>$fscpiofile
	echo 'devices' >>$fscpiofile
	echo 'proc/*' >>$fscpiofile
	echo 'tmp/*' >>$fscpiofile
	echo 'var/run/*' >>$fscpiofile
	echo 'system/contract/*' >>$fscpiofile
	echo 'system/object/*' >>$fscpiofile

	fspaxfile=$(/usr/bin/mktemp -t -p /var/tmp fs.pax.XXXXXX)
	if [[ -z "$fspaxfile" ]]; then
		rm -f $fstmpfile $fscpiofile
		fatal "$e_tmpfile"
	fi

	printf "%s " \
	    "dev devices proc tmp var/run system/contract system/object" \
	    >>$fspaxfile

	# Set up any fs mounts so the archive will install into the correct
	# locations.
	get_fs_info
	mnt_fs
	if (( $? != 0 )); then
		umnt_fs >/dev/null 2>&1
		rm -f $fstmpfile $fscpiofile $fspaxfile
		fatal "$mount_failed"
	fi

	if [[ "$filetype" == "existing" ]]; then
		log "$no_installing"
	else
		log "$installing"
	fi

	#
	# Install the image into the zonepath.
	#
	unpack_result=0
	stage1="cat"
	if [[ "$filetype" == "gzip" ]]; then
		stage1="gzcat"
		filetype="cpio"
	elif [[ "$filetype" == "bzip2" ]]; then
		stage1="bzcat"
		filetype="cpio"
	fi

	if [[ "$filetype" == "cpio" ]]; then
		install_cpio "$stage1" "$insrc"
		unpack_result=$?

	elif [[ "$filetype" == "flar" ]]; then
		( cd "$ZONEROOT" && $stage1 $insrc | install_flar )
		unpack_result=$?

	elif [[ "$filetype" == "xustar" ]]; then
		install_pax "$insrc"
		unpack_result=$?

	elif [[ "$filetype" = "tar" ]]; then
		vlog "cd \"$ZONEROOT\" && tar -xf \"$insrc\""
		# Ignore errors from tar since we expect some errors depending
		# on how the archive was made.
		( cd "$ZONEROOT" && tar -xf "$insrc" )
		unpack_result=0
		post_unpack

	elif [[ "$filetype" == "ufsdump" ]]; then
		install_ufsdump "$insrc"
		unpack_result=$?

	elif [[ "$filetype" == "directory" ]]; then
		install_dir "$insrc"
		unpack_result=$?

	elif [[ "$filetype" == "zfs" ]]; then
		#
		# Given a 'zfs send' stream file, receive the snapshot into
		# the zone's dataset.  We're getting the original system's
		# zonepath dataset.  Destroy the existing dataset created
		# above since this recreates it.
		#
		if [[ -z "$DATASET" ]]; then
			fatal "$f_nodataset"
		fi
		/sbin/zfs destroy "$DATASET"
		if (( $? != 0 )); then
			log "$f_zfsdestroy" "$DATASET"
		fi

		vlog "$stage1 $insrc | zfs receive -F $DATASET"
		( $stage1 $insrc | /sbin/zfs receive -F $DATASET )
		unpack_result=$?
	fi

	# Clean up any fs mounts used during unpacking.
	umnt_fs
	rm -f $fstmpfile $fscpiofile $fspaxfile

	chmod 700 $zonepath

	(( $unpack_result != 0 )) && fatal "$f_unpack_failed"

	# Verify this is a valid image.
	sanity_check $ZONEROOT

	return 0
}

# Setup i18n output
TEXTDOMAIN="SUNW_OST_OSCMD"
export TEXTDOMAIN

e_cannot_wrap=$(gettext "%s: error: wrapper file already exists")
e_baddir=$(gettext "Invalid '%s' directory within the zone")
e_badfile=$(gettext "Invalid '%s' file within the zone")
e_path_abs=$(gettext "Pathname specified to -a '%s' must be absolute.")
e_not_found=$(gettext "%s: error: file or directory not found.")
e_install_abort=$(gettext "Installation aborted.")
e_not_readable=$(gettext "Cannot read directory '%s'")
e_not_dir=$(gettext "Error: must be a directory")
e_unknown_archive=$(gettext "Error: Unknown archive format. Must be a flash archive, a cpio archive (can also be gzipped or bzipped), a pax XUSTAR archive, or a level 0 ufsdump archive.")
e_absolute_archive=$(gettext "Error: archive contains absolute paths instead of relative paths.")
e_mismatch_archive=$(gettext "Error: the archive top-level directory (%s) does not match the zonepath (%s).")
e_tmpfile=$(gettext "Unable to create temporary file")
e_root_full=$(gettext "Zonepath root %s exists and contains data; remove or move aside prior to install.")
f_mkdir=$(gettext "Unable to create directory %s.")
f_chmod=$(gettext "Unable to chmod directory %s.")
f_chown=$(gettext "Unable to chown directory %s.")
f_hwcap_info=$(gettext "HWCAP: %s\n")
f_sanity_hwcap=$(gettext \
"The image was created with an incompatible libc.so.1 hwcap lofs mount.\n"\
"       The zone will not boot on this platform.  See the zone's\n"\
"       documentation for the recommended way to create the archive.")

m_analyse_archive=$(gettext "Analysing the archive")

not_readable=$(gettext "Cannot read file '%s'")
not_flar=$(gettext "Input is not a flash archive")
bad_flar=$(gettext "Flash archive is a corrupt")
bad_zfs_flar=$(gettext "Flash archive contains a ZFS send stream.\n\tRecreate the flar using the -L option with cpio or pax.")
f_unpack_failed=$(gettext "Unpacking the archive failed")
unknown_archiver=$(gettext "Archiver %s is not supported")
cmd_not_exec=$(gettext "Required command '%s' not executable!")

#
# Exit values used by the script, as #defined in <sys/zone.h>
#
#	ZONE_SUBPROC_OK
#	===============
#	Installation was successful
#
#	ZONE_SUBPROC_USAGE
#	==================
#	Improper arguments were passed, so print a usage message before exiting
#
#	ZONE_SUBPROC_NOTCOMPLETE
#	========================
#	Installation did not complete, but another installation attempt can be
#	made without an uninstall
#
#	ZONE_SUBPROC_FATAL
#	==================
#	Installation failed and an uninstall will be required before another
#	install can be attempted
#
ZONE_SUBPROC_OK=0
ZONE_SUBPROC_USAGE=253
ZONE_SUBPROC_NOTCOMPLETE=254
ZONE_SUBPROC_FATAL=255

#!/bin/ksh -p
#
# 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) 2010, Oracle and/or its affiliates. All rights reserved.
#

PATH=/usr/bin:/usr/sbin
export PATH

. /usr/lib/brand/shared/common.ksh

zonename=$1
zonepath=$2
cmd=$3

if [ $3 == "datasets" ]; then
	get_zonepath_ds $zonepath

	DS=`/sbin/zfs list -H -t filesystem -o name $ZONEPATH_DS/ROOT`
	if [ ! -z "$DS" ]; then
		echo "$DS\c"
	else
		fail_fatal "$f_no_ds"
	fi
fi

exit $ZONE_SUBPROC_OK
#
# 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) 2010, Oracle and/or its affiliates. All rights reserved.
#

#
# get script name (bname)
#
bname=`basename $0`

#
# common shell script functions
#
. /usr/lib/brand/shared/common.ksh

#
# error messages
#
m_usage=$(gettext "Usage: %s: [-hFn]")

m_1_zfs_promote=$(gettext "promoting '%s'.")
m_1_zfs_destroy=$(gettext "destroying '%s'.")
m_2_zfs_rename=$(gettext "renaming '%s' to '%s'.")
m_3_zfs_set=$(gettext "setting property %s='%s' for '%s'.")
m_rm_r=$(gettext "recursively deleting '%s'.")
m_rm=$(gettext "deleting '%s'.")

w_no_ds=$(gettext "Warning: no zonepath dataset found.")

f_usage_err=$(gettext "Error: invalid usage")
f_abort=$(gettext "Error: internal error detected, aborting.")
f_1_zfs_promote=$(gettext "Error: promoting ZFS dataset '%s'.")
f_2_zfs_rename=$(gettext "Error: renaming ZFS dataset '%s' to '%s'.")
f_3_zfs_set=$(gettext "Error: setting ZFS propery %s='%s' for '%s'.")
f_1_zfs_destroy=$(gettext "Error: destroying ZFS dataset.")
f_2_zfs_get=$(gettext "Error: reading ZFS dataset property '%s' from '%s'.")
f_user_snap=$(gettext "Error: user snapshot(s) detected.")
f_stray_snap=$(gettext "Error: uncloned snapshot(s) detected.")
f_stray_clone=$(gettext "Error: cloned zone datasets found outsize of zone.")
f_rm_snap=$(gettext "Error: please delete snapshot(s) and retry uninstall.")
f_rm_clone=$(gettext "Error: please delete clone(s) and retry uninstall.")
f_iu_clone=$(gettext "Error: cloned zone dataset(s) in use.")
f_dis_clone=$(gettext "Error: please stop using clone(s) and retry uninstall.")

#
# functions
#
print_array()
{
	typeset -n pa_array=$1

	(( pa_i = 0 ))
	while (( $pa_i < ${#pa_array[@]} )); do
		printf "\t${pa_array[$pa_i]}\n"
		(( pa_i = $pa_i + 1 ))
	done
}

usage()
{
	printf "$m_usage\n" "$bname"
	exit $ZONE_SUBPROC_USAGE
}

usage_err()
{
	printf "$f_usage_err\n" >&2
	usage >&2
}

rm_zonepath()
{
	# cleanup stuff we know about and leave any user data alone

	[[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
		printf "$m_rm\n" "$zonepath/SUNWattached.xml"
	$nop /bin/rm -f "$zonepath/SUNWattached.xml"

	[[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
		printf "$m_rm_r\n" "$zonepath/lu"
	$nop /bin/rm -rf "$zonepath/lu"

	[[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
		printf "$m_rm_r\n" "$zonepath/dev"
	$nop /bin/rm -rf "$zonepath/dev"

	[[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
		printf "$m_rm_r\n" "$zonepath/root"
	$nop /bin/rm -rf "$zonepath/root"

	[[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
		printf "$m_rm\n" "$zonepath"
	$nop /bin/rmdir "$zonepath" 2>/dev/null
}

zfs_destroy()
{
	zd_fs1="$1"

	# first figure out if the target fs has an origin snapshot
	zd_origin=`/sbin/zfs get -H -o value origin "$zd_fs1"`
	if [[ $? != 0 ]]; then
		printf "$f_2_zfs_get\n" origin "$zd_fs1" >&2
		exit $ZONE_SUBPROC_FATAL
	fi

	[[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
		printf "$m_1_zfs_destroy\n" "$zd_fs1"

	#
	# note that we specify the '-r' flag so that we destroy any
	# descendants (filesystems and snapshot) of the specified
	# filesystem.
	#
	$nop /sbin/zfs destroy -r "$zd_fs1"
	if [[ $? != 0 ]]; then
		printf "$f_1_zfs_destroy\n" "$zd_fs1" >&2
		exit $ZONE_SUBPROC_FATAL
	fi

	[[ "$zd_origin" == "-" ]] && return

	[[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
		printf "$m_1_zfs_destroy\n" "$zd_origin"

	$nop /sbin/zfs destroy "$zd_origin" 2>/dev/null
	#
	# we ignore errors while trying to destroy the origin since
	# the origin could have been used as the source for other
	# clones
	#
}

zfs_promote()
{
	zp_fs1="$1"

	[[ -z "$opt_n" ]] &&
		printf "$m_1_zfs_promote\n" "$zp_fs1"

	$nop /sbin/zfs promote "$zp_fs1"
	if [[ $? != 0 ]]; then
		printf "$f_1_zfs_promote\n" "$zp_fs1" >&2
		exit $ZONE_SUBPROC_FATAL
	fi
}

zfs_rename()
{
	zr_fs1="$1"
	zr_fs2="$2"

	[[ -z "$opt_n" ]] &&
		printf "$m_2_zfs_rename\n" "$zr_fs1" "$zr_fs2"

	$nop /sbin/zfs rename "$zr_fs1" "$zr_fs2"
	if [[ $? != 0 ]]; then
		printf "$f_2_zfs_rename\n" "$zr_fs1" "$zr_fs2" >&2
		return 1
	fi
	return 0
}

zfs_set()
{
	zs_prop=$1
	zs_value=$2
	zs_fs1=$3

	[[ -z "$opt_n" ]] && [[ -n "$opt_v" ]] &&
		printf "$m_3_zfs_set\n" "$zs_prop" "$zs_value" "$zs_fs1"

	$nop /sbin/zfs set "$zs_prop"="$zs_value" "$zs_fs1"
	if [[ $? != 0 ]]; then
		printf "$f_3_zfs_set\n" "$zs_prop" "$zs_value" "$zs_fs1"
		return 1
	fi
	return 0
}

zfs_set_array()
{
	zsa_prop=$1
	zsa_value=$2
	typeset -n zsa_array=$3
	zsa_ignore_errors=$4

	(( zsa_i = 0 ))
	while (( $zsa_i < ${#zsa_array[@]} )); do
		zfs_set "$zsa_prop" "$zsa_value" "${zsa_array[$zsa_i]}"
		[[ $? != 0 ]] && [[ -z "$zsa_ignore_errors" ]] &&
			return 1
		(( zsa_i = $zsa_i + 1 ))
	done
	return 0
}


(( snap_rename_zbe_i = 1 ))
(( snap_rename_snap_i = 1 ))
snap_rename_init()
{
	(( snap_rename_zbe_i = 1 ))
	(( snap_rename_snap_i = 1 ))
}

snap_rename()
{
	eval sr_fs=\${$1}
	eval sr_snap=\${$2}

	if [[ "$sr_snap" == ~(Elr)(zbe-[0-9][0-9]*) ]]; then
		sr_snap="zbe-$snap_rename_zbe_i"
		(( snap_rename_zbe_i = $snap_rename_zbe_i + 1 ))
	elif [[ "$sr_snap" == ~(Er)(_snap[0-9]*) ]]; then
		sr_snap=${sr_snap##~(Er)([0-9]*)}
		sr_snap="${sr_snap}${snap_rename_snap_i}"
		(( snap_rename_snap_i = $snap_rename_snap_i + 1 ))
	else
		printf "$f_user_snap\n" >&2
		printf "\t$sr_fs@$sr_snap\n" >&2
		printf "$f_rm_snap\n" >&2
		exit $ZONE_SUBPROC_FATAL
	fi

	eval $2="$sr_snap"
}

# find the dataset associated with $zonepath
uninstall_get_zonepath_ds()
{
	ZONEPATH_DS=`/sbin/zfs list -t filesystem -o name,mountpoint | \
	    /bin/nawk -v zonepath=$zonepath '{
		if ($2 == zonepath)
			print $1
	}'`

	if [ -z "$ZONEPATH_DS" ]; then
		# there is no $zonepath dataset
		rm_zonepath
		exit $ZONE_SUBPROC_OK
	fi
}

# find the dataset associated with $ZONEPATH_DS/ROOT
uninstall_get_zonepath_root_ds()
{
	ZONEPATH_RDS=`/sbin/zfs list -H -t filesystem -o name \
		$ZONEPATH_DS/ROOT 2>/dev/null`

	if [ -z "$ZONEPATH_RDS" ]; then
		# there is no $ZONEPATH_DS/ROOT dataset
		c=`/sbin/zfs list -H -t filesystem -r $ZONEPATH_DS | wc -l`
		if [ $c = 1 ]; then
			# $zonepath dataset has no descendents
			zfs_destroy "$ZONEPATH_DS"
		fi
		rm_zonepath
		exit $ZONE_SUBPROC_OK
	fi
}

destroy_zone_dataset()
{
	fs=$1

	pool=${fs%%/*}

	# Fastpath.  if there are no snapshots of $fs then just delete it.
	c=`/sbin/zfs list -H -t snapshot -o name -r $fs | grep "^$fs@" |
	    LC_ALL=C LANG=C wc -l`
	if (( $c == 0 )) ; then
		zfs_destroy "$fs"
		return
	fi

	#
	# This zone BE has snapshots.  This can happen if a zone has
	# multiple BEs (in which case we have snapshots named "zbe-XXX"),
	# if this zone has been used as the source for a clone of
	# another zone (in which case we have snapshots named
	# "XXX_snap"), or if an administrator has been doing manual
	# snapshotting.
	#
	# To be able to destroy this dataset (which we'll call the
	# origin) we need to get rid of all it's snapshots.  The "easiest"
	# way to do this is to:
	#
	# - delete any uncloned origin snapshots
	# - find the oldest clone of the youngest origin snapshot (which
	#   we'll call the oldest clone)
	# - check if there are any snapshots naming conflicts between
	#   the origin and the oldest clone.
	# - if so, find any clones of those conflicting origin snapshots
	# - make sure that those clones are not zoned an in-use.
	# - if any of those clones are zoned, unzone them.
	# - rename origin snapshots to eliminate naming conflicts
	# - for any clones that we unzoned, rezone them.
	# - promote the oldest clone
	# - destroy the origin and all it's descendants
	#

	#
	# Get a list of all the cloned datasets within the zpool
	# containing the origin filesystem.  Filter out any filesystems
	# that are descendants of origin because we are planning to
	# destroy them anyway.
	#
	unset clones clones_origin
	(( clones_c = 0 ))
	pool=${fs%%/*}
	LANG=C LC_ALL=C /sbin/zfs list -H -t filesystem -s creation \
	    -o name,origin -r "$pool" |
	    while IFS="	" read name origin; do

		# skip non-clone filesystems
		[[ "$origin" == "-" ]] &&
			continue

		# skip desendents of the origin we plan to destroy
		[[ "$name" == ~()(${fs}/*) ]] &&
			continue

		# record this clone and it's origin
		clones[$clones_c]="$name"
		clones_origin[$clones_c]="$origin"
		(( clones_c = $clones_c + 1 ))
	done

	#
	# Now do a sanity check.  Search for clones of a child datasets
	# of the dataset we want to destroy, that are not themselves
	# children of the dataset we're going to destroy).  This should
	# really never happen unless the global zone admin has cloned a
	# snapshot of a zone filesystem to a location outside of that
	# zone.  bad admin...
	#
	unset stray_clones
	(( stray_clones_c = 0 ))
	(( j = 0 ))
	while (( $j < $clones_c )); do
		# is the clone origin a descendant of $fs?
		if [[ "${clones_origin[$j]}" != ~()(${fs}/*) ]]; then
			# we don't care.
			(( j = $j + 1 ))
			continue
		fi
		stray_clones[$stray_clones_c]=${clones[$j]}
		(( stray_clones_c = $stray_clones_c + 1 ))
		(( j = $j + 1 ))
	done
	if (( stray_clones_c > 0 )); then
		#
		# sigh.  the admin has done something strange.
		# tell them to clean it up and retry.
		#
		printf "$f_stray_clone\n" >&2
		print_array stray_clones >&2
		printf "$f_rm_clone\n" >&2
		exit $ZONE_SUBPROC_FATAL
	fi

	# Find all the snapshots of the origin filesystem.
	unset s_origin
	(( s_origin_c = 0 ))
	/sbin/zfs list -H -t snapshot -s creation -o name -r $fs |
	    grep "^$fs@" | while read name; do
		s_origin[$s_origin_c]=$name
		(( s_origin_c = $s_origin_c + 1 ))
	done

	#
	# Now go through the origin snapshots and find those which don't
	# have clones.  We're going to explicity delete these snapshots
	# before we do the promotion.
	#
	unset s_delete
	(( s_delete_c = 0 ))
	(( j = 0 ))
	while (( $j < $s_origin_c )); do
		(( k = 0 ))
		while (( $k < $clones_c )); do
			# if we have a match then break out of this loop
			[[ "${s_origin[$j]}" == "${clones_origin[$k]}" ]] &&
				break
			(( k = $k + 1 ))
		done
		if (( $k != $clones_c )); then
			# this snapshot has a clone, move on to the next one
			(( j = $j + 1 ))
			continue
		fi

		# snapshot has no clones so add it to our delete list
		s_delete[$s_delete_c]=${s_origin[$j]}
		(( s_delete_c = $s_delete_c + 1 ))
		# remove it from the origin snapshot list
		(( k = $j + 1 ))
		while (( $k < $s_origin_c )); do
			s_origin[(( $k - 1 ))]=${s_origin[$k]}
			(( k = $k + 1 ))
		done
		(( s_origin_c = $s_origin_c - 1 ))
	done

	#
	# Fastpath.  If there are no remaining snapshots then just
	# delete the origin filesystem (and all it's descendents) and
	# move onto the next zone BE.
	#
	if (( $s_origin_c == 0 )); then
		zfs_destroy "$fs"
		return
	fi

	# find the youngest snapshot of $fs
	s_youngest=${s_origin[(( $s_origin_c - 1 ))]}

	# Find the oldest clone of the youngest snapshot of $fs
	unset s_clone
	(( j = $clones_c - 1 ))
	while (( $j >= 0 )); do
		if [[ "$s_youngest" == "${clones_origin[$j]}" ]]; then
			s_clone=${clones[$j]}
			break
		fi
		(( j = $j - 1 ))
	done
	if [[ -z "$s_clone" ]]; then
		# uh oh.  something has gone wrong.  bail.
		printf "$f_stray_snap\n" >&2
		printf "\t$s_youngest\n" >&2
		printf "$f_rm_snap\n" >&2
		exit $ZONE_SUBPROC_FATAL
	fi

	# create an array of clone snapshot names
	unset s_clone_s
	(( s_clone_s_c = 0 ))
	/sbin/zfs list -H -t snapshot -s creation -o name -r $s_clone |
	    grep "^$s_clone@" | while read name; do
		s_clone_s[$s_clone_s_c]=${name##*@}
		(( s_clone_s_c = $s_clone_s_c + 1 ))
	done

	# create an arrays of possible origin snapshot renames
	unset s_origin_snap
	unset s_rename
	(( j = 0 ))
	while (( $j < $s_origin_c )); do
		s_origin_snap[$j]=${s_origin[$j]##*@}
		s_rename[$j]=${s_origin[$j]##*@}
		(( j = $j + 1 ))
	done

	#
	# Search for snapshot name collisions between the origin and
	# oldest clone.  If we find one, generate a new name for the
	# origin snapshot and re-do the collision check.
	#
	snap_rename_init
	(( j = 0 ))
	while (( $j < $s_origin_c )); do
		(( k = 0 ))
		while (( $k < $s_clone_s_c )); do

			# if there's no naming conflict continue
			if [[ "${s_rename[$j]}" != "${s_clone_s[$k]}" ]]; then
				(( k = $k + 1 ))
				continue
			fi

			#
			# The origin snapshot conflicts with a clone
			# snapshot.  Choose a new name and then restart
			# then check that against clone snapshot names.
			#
			snap_rename fs "s_rename[$j]"
			(( k = 0 ))
			continue;
		done

		# if we didn't rename this snapshot then continue
		if [[ "${s_rename[$j]}" == "${s_origin_snap[$j]}" ]]; then
			(( j = $j + 1 ))
			continue
		fi

		#
		# We need to rename this origin snapshot because it
		# conflicts with a clone snapshot name.  So above we
		# chose a name that didn't conflict with any other clone
		# snapshot names.  But we also have to avoid naming
		# conflicts with any other origin snapshot names.  So
		# check for that now.
		#
		(( k = 0 ))
		while (( $k < $s_origin_c )); do

			# don't compare against ourself
			if (( $j == $k )); then
				(( k = $k + 1 ))
				continue
			fi

			# if there's no naming conflict continue
			if [[ "${s_rename[$j]}" != "${s_rename[$k]}" ]]; then
				(( k = $k + 1 ))
				continue
			fi

			#
			# The new origin snapshot name conflicts with
			# another origin snapshot name.  Choose a new
			# name and then go back to check the new name
			# for uniqueness against all the clone snapshot
			# names.
			#
			snap_rename fs "s_rename[$j]"
			continue 2;
		done

		#
		# A new unique name has been chosen.  Move on to the
		# next origin snapshot.
		#
		(( j = $j + 1 ))
		snap_rename_init
	done

	#
	# So now we know what snapshots need to be renamed before the
	# promotion.  But there's an additional problem.  If any of the
	# filesystems cloned from these snapshots have the "zoned"
	# attribute set (which is highly likely) or if they are in use
	# (and can't be unmounted and re-mounted) then the snapshot
	# rename will fail.  So now we'll search for all the clones of
	# snapshots we plan to rename and look for ones that are zoned.
	#
	# We'll ignore any snapshot clones that may be in use but are
	# not zoned.  If these clones are in-use, the rename will fail
	# and we'll abort, there's not much else we can do about it.
	# But if they are not in use the snapshot rename will unmount
	# and remount the clone.  This is ok because when the zoned
	# attribute is off, we know that the clone was originally
	# mounted from the global zone.  (So unmounting and remounting
	# it from the global zone is ok.)
	#
	# But we'll abort this whole operation if we find any clones
	# that that are zoned and in use.  (This can happen if another
	# zone has been cloned from this one and is now booted.)  The
	# reason we do this is because those zoned filesystems could
	# have originally mounted from within the zone.  So if we
	# cleared the zone attribute and did the rename, we'd be
	# remounting the filesystem from the global zone.  This would
	# result in the zone losing the ability to unmount the
	# filesystem, which would be bad.
	#
	unset zoned_clones zoned_iu_clones
	(( zoned_clones_c = 0 ))
	(( zoned_iu_clones_c = 0 ))
	(( j = 0 ))
	# walk through all the clones
	while (( $j < $clones_c )); do
		# walk through all the origin snapshots
		(( k = 0 ))
		while (( $k < $s_origin_c )); do
			#
			# check if this clone originated from a snapshot that
			# we need to rename.
			#
			[[ "${clones_origin[$j]}" == "${s_origin[$k]}" ]] &&
			    [[ "${s_origin_snap[$k]}" != "${s_rename[$k]}" ]] &&
				break
			(( k = $k + 1 ))
			continue
		done
		if (( $k == $s_origin_c )); then
			# This isn't a clone of a snapshot we want to rename.
			(( j = $j + 1 ))
			continue;
		fi

		# get the zoned attr for this clone.
		zoned=`LC_ALL=C LANG=C \
		    /sbin/zfs get -H -o value zoned ${clones[$j]}`
		if [[ "$zoned" != on ]]; then
			# This clone isn't zoned so ignore it.
			(( j = $j + 1 ))
			continue
		fi

		# remember this clone so we can muck with it's zoned attr.
		zoned_clones[$zoned_clones_c]=${clones[$j]}
		(( zoned_clones_c = $zoned_clones_c + 1 ))

		# check if it's in use
		mounted=`LC_ALL=C LANG=C \
		    /sbin/zfs get -H -o value mounted ${clones[$j]}`
		if [[ "$mounted" != yes ]]; then
			# Good news.  This clone isn't in use.
			(( j = $j + 1 ))
			continue
		fi

		# Sigh.  This clone is in use so we're destined to fail.
		zoned_iu_clones[$zoned_iu_clones_c]=${clones[$j]}
		(( zoned_iu_clones_c = $zoned_iu_clones_c + 1 ))

		# keep looking for errors so we can report them all at once.
		(( j = $j + 1 ))
	done
	if (( zoned_iu_clones_c > 0 )); then
		#
		# Tell the admin
		#
		printf "$f_iu_clone\n" >&2
		print_array zoned_iu_clones >&2
		printf "$f_dis_clone\n" >&2
		exit $ZONE_SUBPROC_FATAL
	fi

	#
	# Ok.  So we're finally done with planning and we can do some
	# damage.  We're going to:
	# - destroy unused snapshots
	# - unzone clones which originate from snapshots we need to rename
	# - rename conflicting snapshots
	# - rezone any clones which we unzoned
	# - promote the oldest clone of the youngest snapshot
	# - finally destroy the origin filesystem.
	#

	# delete any unsed snapshot
	(( j = 0 ))
	while (( $j < $s_delete_c )); do
		zfs_destroy "${s_delete[$j]}"
		(( j = $j + 1 ))
	done

	# unzone clones
	zfs_set_array zoned off zoned_clones ||
		zfs_set_array zoned on zoned_clones 1

	# rename conflicting snapshots
	(( j = 0 ))
	while (( $j < $s_origin_c )); do
		if [[ "${s_origin_snap[$j]}" != "${s_rename[$j]}" ]]; then
			zfs_rename "${s_origin[$j]}" "$fs@${s_rename[$j]}"
			if [[ $? != 0 ]]; then
				# re-zone the clones before aborting
				zfs_set_array zoned on zoned_clones 1
				exit $ZONE_SUBPROC_FATAL
			fi
		fi
		(( j = $j + 1 ))
	done

	# re-zone the clones
	zfs_set_array zoned on zoned_clones 1

	# promote the youngest clone of the oldest snapshot
	zfs_promote "$s_clone"

	# destroy the origin filesystem and it's descendants
	zfs_destroy "$fs"
}

#
# This function expects an array named fs_all to exist which is initialized
# with the zone's ZFS datasets that should be destroyed.  fs_all_c is the
# count of the number of elements in the array.  ZONEPATH_RDS is the
# zonepath/root dataset and ZONEPATH_DS is the zonepath dataset.
#
destroy_zone_datasets()
{
	# Destroy the zone BEs datasets one by one.
	(( i = 0 ))
	while (( $i < $fs_all_c )); do
		fs=${fs_all[$i]}

		destroy_zone_dataset "$fs"
		(( i = $i + 1 ))
	done

	#
	# Check if there are any other datasets left.  There may be datasets
	# associated with other GZ BEs, so we need to leave things alone in
	# that case.
	#
	c=`/sbin/zfs list -H -t filesystem -r $ZONEPATH_RDS | wc -l`
	if [ $c = 1 ]; then
		zfs_destroy "$ZONEPATH_RDS"
	fi
	c=`/sbin/zfs list -H -t filesystem -r $ZONEPATH_DS | wc -l`
	if [ $c = 1 ]; then
		zfs_destroy "$ZONEPATH_DS"
	fi

	rm_zonepath
}