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 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679 3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941 3942 3943 3944 3945 3946 3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052 4053 4054 4055 4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133 4134 4135 4136 4137 4138 4139 4140 4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157 4158 4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274 4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286 4287 4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422 4423 4424 4425 4426 4427 4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846 4847 4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168 5169 5170 5171 5172 5173 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370 5371 5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858 5859 5860 5861 5862 5863 5864 5865 5866 5867 5868 5869 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138 6139 6140 6141 6142 6143 6144 6145 6146 6147 6148 6149 6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201 6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413 6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444 6445 6446 6447 6448 6449 6450 6451 6452 6453 6454 6455 6456 6457 6458 6459 6460 6461 6462 6463 6464 6465 6466 6467 6468 6469 6470 6471 6472 6473 6474 6475 6476 6477 6478 6479 6480 6481 6482 6483 6484 6485 6486 6487 6488 6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501 6502 6503 6504 6505 6506 6507 6508 6509 6510 6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540 6541 6542 6543 6544 6545 6546 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 6562 6563 6564 6565 6566 6567 6568 6569 6570 6571 6572 6573 6574 6575 6576 6577 6578 6579 6580 6581 6582 6583 6584 6585 6586 6587 6588 6589 6590 6591 6592 6593 6594 6595 6596 6597 6598 6599 6600 6601 6602 6603 6604 6605 6606 6607 6608 6609 6610 6611 6612 6613 6614 6615 6616 6617 6618 6619 6620 6621 6622 6623 6624 6625 6626 6627 6628 6629 6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662 6663 6664 6665 6666 6667 6668 6669 6670 6671 6672 6673 6674 6675 6676 6677 6678 6679 6680 6681 6682 6683 6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776 6777 6778 6779 6780 6781 6782 6783 6784 6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860 6861 6862 6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896 6897 6898 6899 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 6915 6916 6917 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 6945 6946 6947 6948 6949 6950 6951 6952 6953 6954 6955 6956 6957 6958 6959 6960 6961 6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 6987 6988 6989 6990 6991 6992 6993 6994 6995 6996 6997 6998 6999 7000 7001 7002 7003 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013 7014 7015 7016 7017 7018 7019 7020 7021 7022 7023 7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051 7052 7053 7054 7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355 7356 7357 7358 7359 7360 7361 7362 7363 7364 7365 7366 7367 7368 7369 7370 7371 7372 7373 7374 7375 7376 7377 7378 7379 7380 7381 7382 7383 7384 7385 7386 7387 7388 7389 7390 7391 7392 7393 7394 7395 7396 7397 7398 7399 7400 7401 7402 7403 7404 7405 7406 7407 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 7434 7435 7436 7437 7438 7439 7440 7441 7442 7443 7444 7445 7446 7447 7448 7449 7450 7451 7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466 7467 7468 7469 7470 7471 7472 7473 7474 7475 7476 7477 7478 7479 7480 7481 7482 7483 7484 7485 7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516 7517 7518 7519 7520 7521 7522 7523 7524 7525 7526 7527 7528 7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567 7568 7569 7570 7571 7572 7573 7574 7575 7576 7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592 7593 7594 7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610 7611 7612 7613 7614 7615 7616 7617 7618 7619 7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669 7670 7671 7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686 7687 7688 7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 8203 8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256 8257 8258 8259 8260 8261 8262 8263 8264 8265 8266 8267 8268 8269 8270 8271 8272 8273 8274 8275 8276 8277 8278 8279 8280 8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 8472 8473 8474 8475 8476 8477 8478 8479 8480 8481 8482 8483 8484 8485 8486 8487 8488 8489 8490 8491 8492 8493 8494 8495 8496 8497 8498 8499 8500 8501 8502 8503 8504 8505 8506 8507 8508 8509 8510 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 8644 8645 8646 8647 8648 8649 8650 8651 8652 8653 8654 8655 8656 8657 8658 8659 8660 8661 8662 8663 8664 8665 8666 8667 8668 8669 8670 8671 8672 8673 8674 8675 8676 8677 8678 8679 8680 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 8701 8702 8703 8704 8705 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717 8718 8719 8720 8721 8722 8723 8724 8725 8726 8727 8728 8729 8730 8731 8732 8733 8734 8735 8736 8737 8738 8739 8740 8741 8742 8743 8744 8745 8746 8747 8748 8749 8750 8751 8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791 8792 8793 8794 8795 8796 8797 8798 8799 8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823 8824 8825 8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935 8936 8937 8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980 8981 8982 8983 8984 8985 8986 8987 8988 8989 8990 8991 8992 8993 8994 8995 8996 8997 8998 8999 9000 9001 9002 9003 9004 9005 9006 9007 9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025 9026 9027 9028 9029 9030 9031 9032 9033 9034 9035 9036 9037 9038 9039 9040 9041 9042 9043 9044 9045 9046 9047 9048 9049 9050 9051 9052 9053 9054 9055 9056 9057 9058 9059 9060 9061 9062 9063 9064 9065 9066 9067 9068 9069 9070 9071 9072 9073 9074 9075 9076 9077 9078 9079 9080 9081 9082 9083 9084 9085 9086 9087 9088 9089 9090 9091 9092 9093 9094 9095 9096 9097 9098 9099 9100 9101 9102 9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116 9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133 9134 9135 9136 9137 9138 9139 9140 9141 9142 9143 9144 9145 9146 9147 9148 9149 9150 9151 9152 9153 9154 9155 9156 9157 9158 9159 9160 9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178 9179 9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192 9193 9194 9195 9196 9197 9198 9199 9200 9201 9202 9203 9204 9205 9206 9207 9208 9209 9210 9211 9212 9213 9214 9215 9216 9217 9218 9219 9220 9221 9222 9223 9224 9225 9226 9227 9228 9229 9230 9231 9232 9233 9234 9235 9236 9237 9238 9239 9240 9241 9242 9243 9244 9245 9246 9247 9248 9249 9250 9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268 9269 9270 9271 9272 9273 9274 9275 9276 9277 9278 9279 9280 9281 9282 9283 9284 9285 9286 9287 9288 9289 9290 9291 9292 9293 9294 9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323 9324 9325 9326 9327 9328 9329 9330 9331 9332 9333 9334 9335 9336 9337 9338 9339 9340 9341 9342 9343 9344 9345 9346 9347 9348 9349 9350 9351 9352 9353 9354 9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366 9367 9368 9369 9370 9371 9372 9373 9374 9375 9376 9377 9378 9379 9380 9381 9382 9383 9384 9385 9386 9387 9388 9389 9390 9391 9392 9393 9394 9395 9396 9397 9398 9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414 9415 9416 9417 9418 9419 9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433 9434 9435 9436 9437 9438 9439 9440 9441 9442 9443 9444 9445 9446 9447 9448 9449 9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 9460 9461 9462 9463 9464 9465 9466 9467 9468 9469 9470 9471 9472 9473 9474 9475 9476 9477 9478 9479 9480 9481 9482 9483 9484 9485 9486 9487 9488 9489 9490 9491 9492 9493 9494 9495 9496 9497 9498 9499 9500 9501 9502 9503 9504 9505 9506 9507 9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528 9529 9530 9531 9532 9533 9534 9535 9536 9537 9538 9539 9540 9541 9542 9543 9544 9545 9546 9547 9548 9549 9550 9551 9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572 9573 9574 9575 9576 9577 9578 9579 9580 9581 9582 9583 9584 9585 9586 9587 9588 9589 9590 9591 9592 9593 9594 9595 9596 9597 9598 9599 9600 9601 9602 9603 9604 9605 9606 9607 9608 9609 9610 9611 9612 9613 9614 9615 9616 9617 9618 9619 9620 9621 9622 9623 9624 9625 9626 9627 9628 9629 9630 9631 9632 9633 9634 9635 9636 9637 9638 9639 9640 9641 9642 9643 9644 9645 9646 9647 9648 9649 9650 9651 9652 9653 9654 9655 9656 9657 9658 9659 9660 9661 9662 9663 9664 9665 9666 9667 9668 9669 9670 9671 9672 9673 9674 9675 9676 9677 9678 9679 9680 9681 9682 9683 9684 9685 9686 9687 9688 9689 9690 9691 9692 9693 9694 9695 9696 9697 9698 9699 9700 9701 9702 9703 9704 9705 9706 9707 9708 9709 9710 9711 9712 9713 9714 9715 9716 9717 9718 9719 9720 9721 9722 9723 9724 9725 9726 9727 9728 9729 9730 9731 9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 9756 9757 9758 9759 9760 9761 9762 9763 9764 9765 9766 9767 9768 9769 9770 9771 9772 9773 9774 9775 9776 9777 9778 9779 9780 9781 9782 9783 9784 9785 9786 9787 9788 9789 9790 9791 9792 9793 9794 9795 9796 9797 9798 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 9821 9822 9823 9824 9825 9826 9827 9828 9829 9830 9831 9832 9833 9834 9835 9836 9837 9838 9839 9840 9841 9842 9843 9844 9845 9846 9847 9848 9849 9850 9851 9852 9853 9854 9855 9856 9857 9858 9859 9860 9861 9862 9863 9864 9865 9866 9867 9868 9869 9870 9871 9872 9873 9874 9875 9876 9877 9878 9879 9880 9881 9882 9883 9884 9885 9886 9887 9888 9889 9890 9891 9892 9893 9894 9895 9896 9897 9898 9899 9900 9901 9902 9903 9904 9905 9906 9907 9908 9909 9910 9911 9912 9913 9914 9915 9916 9917 9918 9919 9920 9921 9922 9923 9924 9925 9926 9927 9928 9929 9930 9931 9932 9933 9934 9935 9936 9937 9938 9939 9940 9941 9942 9943 9944 9945 9946 9947 9948 9949 9950 9951 9952 9953 9954 9955 9956 9957 9958 9959 9960 9961 9962 9963 9964 9965 9966 9967 9968 9969 9970 9971 9972 9973 9974 9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 9994 9995 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024 10025 10026 10027 10028 10029 10030 10031 10032 10033 10034 10035 10036 10037 10038 10039 10040 10041 10042 10043 10044 10045 10046 10047 10048 10049 10050 10051 10052 10053 10054 10055 10056 10057 10058 10059 10060 10061 10062 10063 10064 10065 10066 10067 10068 10069 10070 10071 10072 10073 10074 10075 10076 10077 10078 10079 10080 10081 10082 10083 10084 10085 10086 10087 10088 10089 10090 10091 10092 10093 10094 10095 10096 10097 10098 10099 10100 10101 10102 10103 10104 10105 10106 10107 10108 10109 10110 10111 10112 10113 10114 10115 10116 10117 10118 10119 10120 10121 10122 10123 10124 10125 10126 10127 10128 10129 10130 10131 10132 10133 10134 10135 10136 10137 10138 10139 10140 10141 10142 10143 10144 10145 10146 10147 10148 10149 10150 10151 10152 10153 10154 10155 10156 10157 10158 10159 10160 10161 10162 10163 10164 10165 10166 10167 10168 10169 10170 10171 10172 10173 10174 10175 10176 10177 10178 10179 10180 10181 10182 10183 10184 10185 10186 10187 10188 10189 10190 10191 10192 10193 10194 10195 10196 10197 10198 10199 10200 10201 10202 10203 10204 10205 10206 10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218 10219 10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230 10231 10232 10233 10234 10235 10236 10237 10238 10239 10240 10241 10242 10243 10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256 10257 10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268 10269 10270 10271 10272 10273 10274 10275 10276 10277 10278 10279 10280 10281 10282 10283 10284 10285 10286 10287 10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300 10301 10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312 10313 10314 10315 10316 10317 10318 10319 10320 10321 10322 10323 10324 10325 10326 10327 10328 10329 10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343 10344 10345 10346 10347 10348 10349 10350 10351 10352 10353 10354 10355 10356 10357 10358 10359 10360 10361 10362 10363 10364 10365 10366 10367 10368 10369 10370 10371 10372 10373 10374 10375 10376 10377 10378 10379 10380 10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392 10393 10394 10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408 10409 10410 10411 10412 10413 10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440 10441 10442 10443 10444 10445 10446 10447 10448 10449 10450 10451 10452 10453 10454 10455 10456 10457 10458 10459 10460 10461 10462 10463 10464 10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476 10477 10478 10479 10480 10481 10482 10483 10484 10485 10486 10487 10488 10489 10490 10491 10492 10493 10494 10495 10496 10497 10498 10499 10500 10501 10502 10503 10504 10505 10506 10507 10508 10509 10510 10511 10512 10513 10514 10515 10516 10517 10518 10519 10520 10521 10522 10523 10524 10525 10526 10527 10528 10529 10530 10531 10532 10533 10534 10535 10536 10537 10538 10539 10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550 10551 10552 10553 10554 10555 10556 10557 10558 10559 10560 10561 10562 10563 10564 10565 10566 10567 10568 10569 10570 10571 10572 10573 10574 10575 10576 10577 10578 10579 10580 10581 10582 10583 10584 10585 10586 10587 10588 10589 10590 10591 10592 10593 10594 10595 10596 10597 10598 10599 10600 10601 10602 10603 10604 10605 10606 10607 10608 10609 10610 10611 10612 10613 10614 10615 10616 10617 10618 10619 10620 10621 10622 10623 10624 10625 10626 10627 10628 10629 10630 10631 10632 10633 10634 10635 10636 10637 10638 10639 10640 10641 10642 10643 10644 10645 10646 10647 10648 10649 10650 10651 10652 10653 10654 10655 10656 10657 10658 10659 10660 10661 10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672 10673 10674 10675 10676 10677 10678 10679 10680 10681 10682 10683 10684 10685 10686 10687 10688 10689 10690 10691 10692 10693 10694
|
#ifdef aegis
char *ckxv = "Aegis Communications support, 6.1.190, 4 May 1998";
#else
#ifdef Plan9
char *ckxv = "Plan 9 Communications support, 6.1.190, 4 May 1998";
#else
char *ckxv = "UNIX Communications support, 6.1.190, 4 May 1998";
#endif /* Plan9 */
#endif /* aegis */
/* C K U T I O */
/* C-Kermit interrupt, communications control and I/O functions for UNIX */
/*
NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
compatible with C preprocessors that support only #ifdef, #else, #endif,
#define, and #undef. Please do not use #if, logical operators, or other
preprocessor features in any of the portable C-Kermit modules. You can,
of course, use these constructions in system-specific modules when they
are supported.
*/
/*
Author: Frank da Cruz (fdc@columbia.edu),
Columbia University Academic Information Systems, New York City.
Copyright (C) 1985, 1998, Trustees of Columbia University in the City of New
York. All rights reserved.
*/
/* Includes */
#include "ckcsym.h" /* This must go first */
#include "ckcdeb.h" /* This must go second */
#include <errno.h> /* System error numbers */
#ifdef __386BSD__
#define ENOTCONN 57
#else
#ifdef __bsdi__
#define ENOTCONN 57
#else
#ifdef __FreeBSD__
#define ENOTCONN 57
#endif /* __FreeBSD__ */
#endif /* __bsdi__ */
#endif /* __386BSD__ */
#ifdef SCO_OSR504
#define NBBY 8
#endif /* SCO_OSR504 */
#ifdef Plan9
#define SELECT
#include <sys/time.h>
#include <select.h>
#define FD_SETSIZE (3 * sizeof(long) * 8)
static struct timeval tv;
#endif /* Plan9 */
#include "ckcnet.h" /* Symbols for network types. */
/*
The directory-related includes are here because we need to test some
file-system-related symbols to find out which system we're being compiled
under. For example, MAXNAMLEN is defined in BSD4.2 but not 4.1.
*/
#ifdef SDIRENT /* Directory bits... */
#define DIRENT
#endif /* SDIRENT */
#ifdef XNDIR
#include <sys/ndir.h>
#else /* !XNDIR */
#ifdef NDIR
#include <ndir.h>
#else /* !NDIR, !XNDIR */
#ifdef RTU
#include "/usr/lib/ndir.h"
#else /* !RTU, !NDIR, !XNDIR */
#ifdef DIRENT
#ifdef SDIRENT
#include <sys/dirent.h>
#else
#include <dirent.h>
#endif /* SDIRENT */
#else /* !RTU, !NDIR, !XNDIR, !DIRENT, i.e. all others */
#include <sys/dir.h>
#endif /* DIRENT */
#endif /* RTU */
#endif /* NDIR */
#endif /* XNDIR */
/* Definition of HZ, used in msleep() */
#ifdef MIPS
#define HZ ( 1000 / CLOCK_TICK )
#else
#ifdef ATTSV
#ifndef NAP
#ifndef TRS16
#include <sys/param.h>
#else
#define HZ ( 1000 / CLOCK_TICK )
#endif /* TRS16 */
#ifdef NAPHACK
#define nap(x) (void)syscall(3112, (x))
#define NAP
#endif /* NAPHACK */
#endif /* NAP */
#endif /* ATTSV */
#endif /* MIPS */
#ifdef M_UNIX
#undef NGROUPS_MAX /* Prevent multiple definition warnings */
#endif /* M_UNIX */
/*
NOTE: HP-UX 8.0 has a <sys/poll.h>, but there is no corresponding
library routine, so _poll comes up undefined at link time.
*/
#ifdef CK_POLL
#ifndef AIXRS /* IBM AIX needs special handling */
#include <poll.h> /* "standard" (SVID) i/o multiplexing, etc */
#else /* AIXRS */
#ifdef SVR4 /* AIX 3.2 is like SVID... */
#include <poll.h>
#else /* But AIX 3.1 is not ... */
#include <sys/poll.h> /* The include file is in include/sys */
#define events reqevents /* And it does not map IBM-specific member */
#define revents rtnevents /* names to the System V equivalents */
#endif /* SVR4 */
#endif /* AIXRS */
#endif /* CK_POLL */
#include <signal.h> /* Signals */
/* For setjmp and longjmp */
#ifndef ZILOG
#include <setjmp.h>
#else
#include <setret.h>
#endif /* ZILOG */
/* Maximum length for the name of a tty device */
#ifndef DEVNAMLEN
#define DEVNAMLEN 32
#endif /* DEVNAMLEN */
#ifdef NETCONN
#undef DEVNAMLEN
#define DEVNAMLEN 256 /* Longer field for host:service */
#endif /* NETCONN */
/*
The following test differentiates between 4.1 BSD and 4.2 & later.
If you have a 4.1BSD system with the DIRENT library, this test could
mistakenly diagnose 4.2BSD and then later enable the use of system calls
that aren't defined. If indeed there are such systems, we can use some
other way of testing for 4.1BSD, or add yet another compile-time switch.
*/
#ifdef BSD4
#ifdef MAXNAMLEN
#ifndef FT21 /* Except for Fortune. */
#ifndef FT18
#ifndef BELLV10 /* And Bell Labs Research UNIX V10 */
#define BSD42
#endif /* BELLV10 */
#endif /* FT18 */
#endif /* FT21 */
#endif /* MAXNAMLEN */
#endif /* BSD4 */
/*
Minix 2.0 support added by Terry McConnell,
Syracuse University <tmc@barnyard.syr.edu>
No more sgtty interface, posix compliant.
*/
#ifdef MINIX2
#define _MINIX /* Needed for some Minix header files */
#undef MINIX /* Old minix 1.0: used sgtty interface */
#define BSD44ORPOSIX
#define SVORPOSIX
#define NOFILEH
#include <sys/types.h>
#include <sys/ioctl.h>
#include <termios.h>
#include <limits.h>
#undef TIOCGETC /* defined in sys/ioctl.h, but not really supported */
#define TANDEM 0
#endif /* MINIX2 */
/*
MINIX 1.0 support added by Charles Hedrick,
Rutgers University <hedrick@aramis.rutgers.edu>.
MINIX also has V7 enabled.
*/
#ifdef MINIX
#define TANDEM 0
#define MYREAD
#define NOSYSIOCTLH
#include <limits.h>
#endif /* MINIX */
#ifdef CK_REDIR /* <sys/wait.h> needed only for REDIRECT command. */
/*
If anybody can figure out how to make this work with NeXTSTEP, be
my guest! (NeXTBlah/NeXTBlah/bsd/sys/wait.h does not define WEXITSTATUS)
*/
#ifndef CK_WAIT_H /* If wait.h not already included... */
#include <sys/wait.h> /* Include it */
#endif /* CK_WAIT_H */
#endif /* CK_REDIR */
#include "ckuver.h" /* Version herald */
char *ckxsys = HERALD;
#ifdef CK_UTSNAME
#include <sys/utsname.h>
static int hpis800 = 0;
#ifdef SYS_NMLN
#define CK_SYSNMLN SYS_NMLN
#else
#ifdef _SYS_NMLN
#define CK_SYSNMLN SYS_NMLN
#else
#ifdef UTSLEN
#define CK_SYSNMLN UTSLEN
#else
#define CK_SYSNMLN 31
#endif /* UTSLEN */
#endif /* _SYS_NMLN */
#endif /* SYS_NMLN */
char unm_mch[CK_SYSNMLN+1] = { '\0', '\0' };
char unm_mod[CK_SYSNMLN+1] = { '\0', '\0' };
char unm_nam[CK_SYSNMLN+1] = { '\0', '\0' };
char unm_rel[CK_SYSNMLN+1] = { '\0', '\0' };
char unm_ver[CK_SYSNMLN+1] = { '\0', '\0' };
#endif /* CK_UTSNAME */
/* UUCP lockfile material... */
#ifndef NOUUCP
#ifndef USETTYLOCK
/* Name of UUCP tty device lockfile */
#ifdef LINUXFSSTND
#ifndef HDBUUCP
#define HDBUUCP
#endif /* HDBUUCP */
#endif /* LINUXFSSTND */
#ifdef ACUCNTRL
#define LCKDIR
#endif /* ACUCNTRL */
/*
PIDSTRING means use ASCII string to represent pid in lockfile.
*/
#ifndef PIDSTRING
#ifdef HDBUUCP
#define PIDSTRING
#else
#ifdef BSD44
#define PIDSTRING
#else
#ifdef RTAIX
#define PIDSTRING
#else
#ifdef AIXRS
#define PIDSTRING
#else
#ifdef COHERENT
#define PIDSTRING
#endif /* COHERENT */
#endif /* AIXRS */
#endif /* RTAIX */
#endif /* BSD44 */
#endif /* HDBUUCP */
#endif /* PIDSTRING */
/* Now the PIDSTRING exceptions... */
#ifdef PIDSTRING
#ifdef HPUX
#undef PIDSTRING
#endif /* HPUX */
#endif /* PIDSTRING */
#ifdef __bsdi__ /* BSDI (at least thru 1.1) */
#ifdef PIDSTRING
#undef PIDSTRING
#endif /* PIDSTRING */
#endif /* __bsdi__ */
#ifdef OSF32 /* Digital UNIX (OSF/1) 3.2 */
#ifdef PIDSTRING
#undef PIDSTRING
#endif /* PIDSTRING */
#endif /* OSF32 */
/*
LOCK_DIR is the name of the lockfile directory.
If LOCK_DIR is already defined (e.g. on command line), we don't change it.
*/
#ifndef LOCK_DIR
#ifdef BSD44
#ifdef __386BSD__
#define LOCK_DIR "/var/spool/lock";
#else
#ifdef __FreeBSD__
#define LOCK_DIR "/var/spool/lock";
#else
#ifdef __NetBSD__
#define LOCK_DIR "/var/spool/lock";
#else
#define LOCK_DIR "/var/spool/uucp";
#endif /* __NetBSD__ */
#endif /* __FreeBSD__ */
#endif /* __386BSD__ */
#else
#ifdef DGUX430
#define LOCK_DIR "/var/spool/locks";
#else
#ifdef HPUX10
#define LOCK_DIR "/var/spool/locks";
#else
#ifdef RTAIX /* IBM RT PC AIX 2.2.1 */
#define LOCK_DIR "/etc/locks";
#else
#ifdef AIXRS
#define LOCK_DIR "/etc/locks";
#else
#ifdef ISIII
#define LOCK_DIR "/etc/locks";
#else
#ifdef HDBUUCP
#ifdef M_SYS5
#define LOCK_DIR "/usr/spool/uucp";
#else
#ifdef M_UNIX
#define LOCK_DIR "/usr/spool/uucp";
#else
#ifdef SVR4
#define LOCK_DIR "/var/spool/locks";
#else
#ifdef SUNOS4
#define LOCK_DIR "/var/spool/locks";
#else
#ifdef LINUXFSSTND
#define LOCK_DIR "/var/lock";
#else
#define LOCK_DIR "/usr/spool/locks";
#endif /* LINUXFSSTND */
#endif /* SUNOS4 */
#endif /* SVR4 */
#endif /* M_UNIX */
#endif /* M_SYS5 */
#else
#ifdef LCKDIR
#define LOCK_DIR "/usr/spool/uucp/LCK";
#else
#ifdef COHERENT
#define LOCK_DIR "/usr/spool/uucp";
#else
#define LOCK_DIR "/usr/spool/uucp";
#endif /* COHERENT */
#endif /* LCKDIR */
#endif /* HDBUUCP */
#endif /* ISIII */
#endif /* AIXRS */
#endif /* RTAIX */
#endif /* HPUX10 */
#endif /* DGUX430 */
#endif /* BSD44 */
#endif /* !LOCK_DIR (outside ifndef) */
#ifdef OSF2 /* OSF/1 2.0 or later */
#ifdef LOCK_DIR /* (maybe 1.x too, who knows...) */
#undef LOCK_DIR
#define LOCK_DIR "/var/spool/locks";
#endif /* LOCK_DIR */
#endif /* OSF2 */
#ifdef SVR4
#ifndef BSD44
#ifndef LOCKF
#define LOCKF /* Use lockf() on tty device in SVR4 */
#endif /* LOCKF */
#endif /* BSD44 */
#endif /* SVR4 */
#ifdef NOLOCKF /* But NOLOCKF cancels LOCKF */
#ifdef LOCKF
#undef LOCKF
#endif /* LOCKF */
#endif /* NOLOCKF */
/* More about this below... */
#endif /* USETTYLOCK */
#endif /* NOUUCP */
/*
MYREAD means use our internally defined nonblocking buffered read routine.
*/
#ifdef ATTSV
#define MYREAD
#endif /* ATTSV */
#ifdef ATT7300
#ifndef MYREAD
#define MYREAD
#endif /* MYREAD */
/* bits for attmodem: internal modem in use, restart getty */
#define ISMODEM 1
#define DOGETY 512
#endif /* ATT7300 */
#ifdef BSD42
#define MYREAD
#endif /* BSD42 */
#ifdef POSIX
#define MYREAD
#endif /* POSIX */
#ifdef __bsdi__
#ifndef O_NDELAY
#define O_NDELAY O_NONBLOCK
#endif /* O_NDELAY */
#endif /* __bsdi__ */
/*
Variables available to outside world:
dftty -- Pointer to default tty name string, like "/dev/tty".
dfloc -- 0 if dftty is console, 1 if external line.
dfprty -- Default parity
dfflow -- Default flow control
ckxech -- Flag for who echoes console typein:
1 - The program (system echo is turned off)
0 - The system (or front end, or terminal).
functions that want to do their own echoing should check this flag
before doing so.
flfnam -- Name of lock file, including its path, e.g.,
"/usr/spool/uucp/LCK..cul0" or "/etc/locks/tty77"
lkflfn -- Name of link to lock file, including its paths
haslock -- Flag set if this kermit established a uucp lock.
backgrd -- Flag indicating program executing in background ( & on
end of shell command). Used to ignore INT and QUIT signals.
rtu_bug -- Set by stptrap(). RTU treats ^Z as EOF (but only when we handle
SIGTSTP)
Functions for assigned communication line (either external or console tty):
sysinit() -- System dependent program initialization
syscleanup() -- System dependent program shutdown
ttopen(ttname,local,mdmtyp,timo) -- Open the named tty for exclusive access.
ttclos() -- Close & reset the tty, releasing any access lock.
ttsspd(cps) -- Set the transmission speed of the tty.
ttgspd() -- Get (read) the the transmission speed of the tty.
ttpkt(speed,flow,parity) -- Put the tty in packet mode and set the speed.
ttvt(speed,flow) -- Put the tty in virtual terminal mode.
or in DIALING or CONNECTED modem control state.
ttres() -- Restore original tty modes.
ttscarr(carrier) -- Set carrier control mode, on/off/auto.
ttinl(dest,max,timo) -- Timed read line from the tty.
ttinc(timo) -- Timed read character from tty.
myread() -- Raw mode bulk buffer read, gives subsequent
chars one at a time and simulates FIONREAD.
myunrd(c) -- Places c back in buffer to be read (one only)
ttchk() -- See how many characters in tty input buffer.
ttxin(n,buf) -- Read n characters from tty (untimed).
ttol(string,length) -- Write a string to the tty.
ttoc(c) -- Write a character to the tty.
ttflui() -- Flush tty input buffer.
ttsndb() -- Send BREAK signal.
ttsndlb() -- Send Long BREAK signal.
ttlock(ttname) -- "Lock" tty device against uucp collisions.
ttunlck() -- Unlock tty device.
For ATT7300/Unix PC, System V:
attdial(ttname,speed,telnbr) -- dials ATT7300/Unix PC internal modem
offgetty(ttname) -- Turns off getty(1m) for comms line
ongetty(ttname) -- Restores getty() to comms line
*/
/*
Functions for console terminal:
congm() -- Get console terminal modes.
concb(esc) -- Put the console in single-character wakeup mode with no echo.
conbin(esc) -- Put the console in binary (raw) mode.
conres() -- Restore the console to mode obtained by congm().
conoc(c) -- Unbuffered output, one character to console.
conol(s) -- Unbuffered output, null-terminated string to the console.
conola(s) -- Unbuffered output, array of strings to the console.
conxo(n,s) -- Unbuffered output, n characters to the console.
conchk() -- Check if characters available at console (bsd 4.2).
Check if escape char (^\) typed at console (System III/V).
coninc(timo) -- Timed get a character from the console.
congks(timo) -- Timed get keyboard scan code.
conint() -- Enable terminal interrupts on the console if not background.
connoi() -- Disable terminal interrupts on the console if not background.
Time functions
msleep(m) -- Millisecond sleep
ztime(&s) -- Return pointer to date/time string
rtimer() -- Reset timer
gtimer() -- Get elapsed time since last call to rtimer()
*/
/* Conditional Includes */
/* Whether to include <sys/file.h> */
#ifdef RTU /* RTU doesn't */
#define NOFILEH
#endif /* RTU */
#ifdef CIE /* CIE does. */
#undef NOFILEH
#endif /* CIE */
#ifdef BSD41 /* 4.1 BSD doesn't */
#define NOFILEH
#endif /* BSD41 */
#ifdef is68k /* is68k (whatever that is) */
#define NOFILEH
#endif /* is68k */
#ifdef MINIX /* MINIX */
#define NOFILEH
#endif /* MINIX */
#ifdef COHERENT /* Coherent */
#define NOFILEH
#endif /* COHERENT */
#ifndef NOFILEH /* Now include if selected. */
#include <sys/file.h>
#endif /* NOFILEH */
/* POSIX */
#ifdef BSD44ORPOSIX /* POSIX uses termios.h */
#define TERMIOS
#ifdef __bsdi__
#ifdef POSIX
#undef _POSIX_SOURCE /* Get extra stuff from termios.h */
#endif /* POSIX */
#endif /* __bsdi__ */
#include <termios.h>
#ifdef __bsdi__
#ifdef POSIX
#define _POSIX_SOURCE
#endif /* POSIX */
#endif /* __bsdi__ */
#ifndef BSD44 /* Really POSIX */
#ifndef CK_QNX32
#define NOSYSIOCTLH /* No ioctl's allowed. */
#undef ultrix /* Turn off any ultrix features. */
#endif /* CK_QNX32 */
#endif /* BSD44 */
#endif /* POSIX */
/* System III, System V */
#ifdef ATTSV
#ifndef BSD44
#ifndef POSIX
#include <termio.h>
#endif /* POSIX */
#endif /* BSD44 */
#ifdef TERMIOX
/* Need this for termiox structure, RTS/CTS and DTR/CD flow control */
#include <termiox.h>
struct termiox rctsx;
#else
#ifdef STERMIOX
#ifdef SCO_OSR504
/* Sorry, this is truly disgusting but it's SCO's fault. */
#ifndef _SVID3
#define _CK_SVID3_X
#define _SVID3
#endif /* _SVID3 */
#endif /* SCO_OSR504 */
#include <sys/termiox.h>
struct termiox rctsx;
#ifdef CK_SVID3_X
#undef _SVID3
#undef CK_SVID3_X
#endif /* CK_SVID3_X */
#endif /* STERMIOX */
#endif /* TERMIOX */
#endif /* ATTSV */
#ifdef COHERENT /* Use termio.h, not sgtty.h for Coherent */
#include <termio.h>
#endif /* COHERENT */
#ifdef MINIX /* MINIX uses ioctl's */
#define NOSYSIOCTLH /* but has no <sys/ioctl.h> */
#endif /* MINIX */
/* Others */
#ifndef NOSYSIOCTLH /* Others use ioctl() */
#ifdef SUN4S5
/*
This is to get rid of cpp warning messages that occur because all of
these symbols are defined by both termios.h and ioctl.h on the SUN.
*/
#undef ECHO
#undef NL0
#undef NL1
#undef TAB0
#undef TAB1
#undef TAB2
#undef XTABS
#undef CR0
#undef CR1
#undef CR2
#undef CR3
#undef FF0
#undef FF1
#undef BS0
#undef BS1
#undef TOSTOP
#undef FLUSHO
#undef PENDIN
#undef NOFLSH
#endif /* SUN4S5 */
#include <sys/ioctl.h>
#endif /* NOSYSIOCTLH */
/*
We really, really, REALLY want FIONREAD, because it is the only way to find
out not just *if* stuff is waiting to be read, but how much, which is
critical to our sliding-window and streaming procedures. If
*/
#ifdef BELLV10
#include <sys/filio.h> /* For FIONREAD */
#ifdef FIONREAD
#define MYREAD
#endif /* MYREAD */
#endif /* BELLV10 */
#ifndef FIONREAD
/* It wasn't found in ioctl.h or term*.h - try these places: */
#ifdef UNIXWARE
#include <sys/filio.h>
#else
#ifdef SOLARIS
#include <sys/filio.h>
#endif /* SOLARIS */
#endif /* UNIXWARE */
#endif /* FIONREAD */
#ifdef XENIX /* Was M_UNIX but XENIX implies M_UNIX and applies to XENIX too */
/*
<sys/socket.h> included above via "ckcnet.h" defines FIONREAD as
something. Due to this, in_chk() uses the FIONREAD instead of RDCHK
and the hot keys during file transfer (X to cancel file etc) do not
work because FIONREAD doesn't work even though it is defined.
NOTE: This might also be true elsewhere.
*/
#ifdef FIONREAD
#undef FIONREAD
#endif /* FIONREAD */
#endif /* XENIX */
#ifdef CK_SCOV5 /* Ditto for SCO OpenServer 5.0 */
#ifdef FIONREAD
#undef FIONREAD
#endif /* FIONREAD */
#endif /* XENIX */
/* Whether to include <fcntl.h> */
#ifndef is68k /* Only a few don't have this one. */
#ifndef BSD41
#ifndef FT21
#ifndef FT18
#ifndef COHERENT
#include <fcntl.h>
#endif /* COHERENT */
#endif /* FT18 */
#endif /* FT21 */
#endif /* BSD41 */
#endif /* not is68k */
#ifdef COHERENT
#ifdef _I386
#include <fcntl.h>
#else
#include <sys/fcntl.h>
#endif /* _I386 */
#endif /* COHERENT */
#ifdef ATT7300 /* Unix PC, internal modem dialer */
#include <sys/phone.h>
#endif /* ATT7300 */
#ifdef HPUX /* HP-UX variations. */
#define HPUXJOBCTL
#include <sys/modem.h> /* HP-UX modem signals */
#ifdef hp9000s500 /* Model 500 */
#undef HPUXJOBCTL
#endif /* hp9000s500 */
#ifdef HPUXPRE65
#undef HPUXJOBCTL
typedef long mflag;
#endif /* HPUXPRE65 */
#ifdef HPUXJOBCTL
#include <sys/bsdtty.h> /* HP-UX Berkeley tty support */
#endif /* HPUXJOBCTL */
#endif /* HPUX */
/* AT&T Sys V or POSIX */
#ifdef SVORPOSIX /* Sys V or POSIX */
#ifdef M_UNIX /* SCO */
#include <sys/time.h>
#else
#ifdef OXOS /* Olivetti X/OS */
#include <sys/time.h>
#else
#ifdef BSD44 /* 4.4BSD */
#include <sys/time.h>
#else
#ifdef __linux__ /* Linux */
/* Kludge to fix redefinition in <linux/wait.h> */
#ifdef COMMENT
/* No it interferes with __GLIBC__ */
/* So let's see what happens if we leave it out */
/* No problem, at least on Linux 1.2.13... */
#undef WNOHANG
#undef WUNTRACED
#include <ioctls.h>
#include <ioctl-types.h>
#include <linux/tty.h>
#endif /* COMMENT */
#include <sys/time.h>
#ifdef OLINUXHISPEED
#include <linux/serial.h>
#endif /* OLINUXHISPEED */
#ifdef __alpha__ /* Linux on DEC Alpha */
#include <asm/termios.h>
#endif /* __alpha__ */
#else /* not Linux */
#ifdef AIXRS /* IBM AIX */
#include <sys/time.h>
#else
#ifdef IRIX60
#include <sys/time.h>
#endif /* IRIX60 */
#endif /* AIXRS */
#endif /* __linux__ */
#endif /* BSD44 */
#endif /* OXOS */
#endif /* M_UNIX */
#ifdef NOIEXTEN /* This is broken on some systems */
#undef IEXTEN /* like Convex/OS 9.1 */
#endif /* NOIEXTEN */
#ifndef IEXTEN /* Turn off ^O/^V processing. */
#define IEXTEN 0 /* Needed, at least, on BSDI. */
#endif /* IEXTEN */
#ifdef I386IX
#include <sys/time.h> /* Sunsoft Interactive UNIX 4.1 */
#endif /* I386IX */
#else /* BSD, V7, Coherent, Minix, et al. */
#ifndef MINIX2 /* Minix 2.0 uses termios.h */
#include <sgtty.h> /* Otherwise we use <sgtty.h> */
#endif /* MINIX2 */
#ifndef BELLV10
#ifndef PROVX1 /* Now <sys/time.h> ... */
#ifndef V7
#ifndef BSD41
#ifndef COHERENT
#include <sys/time.h> /* Clock info (for break generation) */
#endif /* COHERENT */
#endif /* BSD41 */
#endif /* V7 */
#endif /* PROVX1 */
#endif /* BELLV10 */
#endif /* SVORPOSIX */
#ifdef BELLV10
#include <sys/timeb.h>
#endif /* BELLV10 */
#ifdef PS2AIX10
#include <sys/time.h> /* Clock info for PS/2 AIX 1.x */
#endif /* PS2AIX10 */
#ifdef OSF /* DEC OSF/1 1.0 */
#include <sys/timeb.h>
#endif /* OSF */
#ifdef BSD41 /* BSD 4.1 */
#include <sys/timeb.h>
#endif /* BSD41 */
#ifdef FT21 /* For:Pro 2.1 */
#include <sys/timeb.h>
#endif /* FT21 */
#ifdef BSD29 /* BSD 2.9 */
#include <sys/timeb.h>
#endif /* BSD29 */
#ifdef TOWER1
#include <sys/timeb.h> /* Clock info for NCR Tower */
#endif /* TOWER1 */
#ifdef COHERENT
#include <sys/timeb.h> /* Clock info for NCR Tower */
#endif /* COHERENT */
/*
Pick up definitions needed for select() if we don't have them already.
Normally they come from <sys/types.h> but some systems get them from
<sys/select.h>... Rather than hardwire all of them into the source, we
include it if SELECT_H is defined in compile-time CFLAGS.
*/
#ifndef SCO_OSR504
#ifdef SELECT_H
#include <sys/select.h>
#endif /* SELECT_H */
#endif /* SCO_OSR504 */
#ifdef aegis
#include "/sys/ins/base.ins.c"
#include "/sys/ins/error.ins.c"
#include "/sys/ins/ios.ins.c"
#include "/sys/ins/sio.ins.c"
#include "/sys/ins/pad.ins.c"
#include "/sys/ins/time.ins.c"
#include "/sys/ins/pfm.ins.c"
#include "/sys/ins/pgm.ins.c"
#include "/sys/ins/ec2.ins.c"
#include "/sys/ins/type_uids.ins.c"
#include <default_acl.h>
#undef TIOCEXCL
#undef FIONREAD
#endif /* aegis */
#ifdef sxaE50 /* PFU Compact A SX/A TISP V10/L50 */
#undef FIONREAD
#endif /* sxaE50 */
/* The following #defines are catch-alls for those systems */
/* that didn't have or couldn't find <file.h>... */
#ifndef FREAD
#define FREAD 0x01
#endif /* FREAD */
#ifndef FWRITE
#define FWRITE 0x10
#endif /* FWRITE */
#ifndef O_RDONLY
#define O_RDONLY 000
#endif /* O_RDONLY */
/* Declarations */
#ifdef OXOS
#undef TCGETA
#undef TCSETA
#undef TCSETAW
#undef TCSETAF
#define TCGETA TCGETS
#define TCSETA TCSETS
#define TCSETAW TCSETSW
#define TCSETAF TCSETSF
#define termio termios
#endif /* OXOS */
#ifdef HPUX
#include <time.h>
#else
#ifdef _POSIX_SOURCE /* This includes MINIX */
#ifndef AIXRS
#include <time.h>
#endif /* AIXRS */
#ifdef __GNUC__
#ifdef XENIX
/*
Because Xenix <time.h> doesn't declare time() if we're using gcc.
*/
time_t time();
#endif /* XENIX */
#endif /* __GNUC__ */
#else
time_t time(); /* All Unixes should have this... */
#endif /* _POSIX_SOURCE */
#endif /* HPUX */
/* Special stuff for V7 input buffer peeking */
#ifdef V7
int kmem[2] = { -1, -1};
char *initrawq(), *qaddr[2]={0,0};
#define CON 0
#define TTY 1
#endif /* V7 */
/* dftty is the device name of the default device for file transfer */
/* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
#ifndef DFTTY
#ifdef PROVX1
char *dftty = "/dev/com1.dout"; /* Only example so far of a system */
char *dfmdm = "none";
int dfloc = 1; /* that goes in local mode by default */
#else
char *dftty = CTTNAM; /* Remote by default, use normal */
char *dfmdm = "none";
int dfloc = 0; /* controlling terminal name. */
#endif /* PROVX1 */
#else
char *dftty = DFTTY; /* Default location specified on */
char *dfmdm = "none"; /* command line. */
int dfloc = 1; /* controlling terminal name. */
#endif /* DFTTY */
#ifdef RTU
int rtu_bug = 0; /* set to 1 when returning from SIGTSTP */
#endif /* RTU */
int dfprty = DEFPAR; /* Default parity (0 = none) */
int ttprty = 0; /* The parity that is in use. */
static int ttpmsk = 0xff; /* Parity stripping mask. */
int ttmdm = 0; /* Modem in use. */
int ttcarr = CAR_AUT; /* Carrier handling mode. */
int dfflow = FLO_XONX; /* Default is Xon/Xoff */
int backgrd = 0; /* Assume in foreground (no '&' ) */
#ifdef ultrix
int iniflags = 0; /* fcntl flags for ttyfd */
#endif /* ultrix */
int fdflag = 0; /* Flag for redirected stdio */
int ttfdflg = 0; /* Open File descriptor was given */
int tvtflg = 0; /* Flag that ttvt has been called */
long ttspeed = -1L; /* For saving speed */
int ttflow = -9; /* For saving flow */
int ttld = -1; /* Line discipline */
#ifdef sony_news
static int km_con = -1; /* Kanji mode for console tty */
static int km_ext = -1; /* Kanji mode for external device */
#endif /* sony_news */
static int needpchk = 0;
#ifdef TCPSOCKET
static int nodelay_sav = -1;
#endif /* TCPSOCKET */
/*
Having this module rely on external globals is bad, but fixing this
requires overhaul of the ck*tio.c modules for all the different operating
systems supported by C-Kermit. Left for a future release.
*/
extern int ttnproto; /* Defined in ckcnet.c */
extern int ttnet; /* Defined in ckcnet.c */
extern int xfrcan, xfrchr, xfrnum; /* Defined in ckcmai.c */
extern int suspend;
extern int nettype; /* defined in ckcmai.c */
int ckxech = 0; /* 0 if system normally echoes console characters, else 1 */
#ifdef CK_ENCRYPTION /* Kerberos */
#include "ckuath.h"
extern int me_encrypt, u_encrypt;
#endif /* CK_ENCRYPTION */
/* Declarations of variables global within this module */
static time_t tcount = (time_t)0; /* Elapsed time counter */
static SIGTYP (*saval)() = NULL; /* For saving alarm() handler */
#ifndef NOJC
static SIGTYP (*jchdlr)() = NULL; /* For checking suspend handler */
#endif /* NOJC */
static int jcshell = -1; /* And flag for result */
/*
BREAKNULS is defined for systems that simulate sending a BREAK signal
by sending a bunch of NUL characters at low speed.
*/
#ifdef PROVX1
#ifndef BREAKNULS
#define BREAKNULS
#endif /* BREAKNULS */
#endif /* PROVX1 */
#ifdef V7
#ifndef BREAKNULS
#define BREAKNULS
#endif /* BREAKNULS */
#endif /* V7 */
#ifdef BREAKNULS
static char /* A string of nulls */
*brnuls = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
#endif /* BREAKNULS */
#ifdef CK_POSIX_SIG /* Longjump buffers */
static sigjmp_buf sjbuf; /* POSIX signal handling */
#else
static jmp_buf sjbuf;
#endif /* CK_POSIX_SIG */
#ifdef V7
static jmp_buf jjbuf;
#endif /* V7 */
/* static */ /* (Not static any more) */
int ttyfd = -1; /* TTY file descriptor */
int ttpipe = 0; /* NETCMD: Use pipe instead of ttyfd */
#ifdef NETCMD
static int pipe0[2], pipe1[2]; /* Pipes for net i/o */
static PID_T ttpid = 0; /* Process ID for fork */
static int fdin, fdout; /* File descriptors for pipe */
static FILE * ttout = NULL; /* File pointer for output pipe */
#endif /* NETCMD */
extern int pexitstat;
#ifdef Plan9
int ttyctlfd = -1; /* TTY control channel - What? UNIX doesn't have one? */
int consctlfd = -1; /* Console control channel */
int noisefd = -1; /* tone channel */
static int ttylastspeed = -1; /* So we can lie about the speed */
#endif /* Plan9 */
int telnetfd = 0; /* File descriptor is for telnet */
int x25fd = 0; /* File descriptor is for X.25 */
static int lkf = 0, /* Line lock flag */
cgmf = 0, /* Flag that console modes saved */
xlocal = 0, /* Flag for tty local or remote */
curcarr = 0; /* Carrier mode: require/ignore. */
static int netconn = 0; /* 1 if network connection active */
static char escchr; /* Escape or attn character */
#ifdef COHERENT
#ifdef SELECT
static struct timeval tv; /* Needed for -DSELECT in makefile */
#endif /* SELECT */
#endif /* COHERENT */
#ifdef QNX
static struct timeval tv; /* For getting time, from sys/time.h */
static struct timezone tz;
#else
#ifdef SOLARIS
static struct timeval tv; /* For getting time, from sys/time.h */
static struct timezone tz;
#else
#ifdef HPUX
static struct timeval tv; /* For getting time, from sys/time.h */
static struct timezone tz;
#else
#ifdef __linux__
static struct timeval tv; /* For getting time, from sys/time.h */
static struct timezone tz;
#else
#ifdef PS2AIX10
static struct timeval tv; /* For getting time, from sys/time.h */
static struct timezone tz;
#else
#ifdef AIXRS
static struct timeval tv; /* For getting time, from sys/time.h */
static struct timezone tz;
#else
#ifdef BSD44
static struct timeval tv; /* For getting time, from sys/time.h */
static struct timezone tz;
#else
#ifdef BSD42
static struct timeval tv; /* For getting time, from sys/time.h */
static struct timezone tz;
#ifdef OSF
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* OSF */
#else
#ifdef OXOS
static struct timeval tv; /* For getting time, from sys/time.h */
static struct timezone tz;
#else
#ifdef SELECT
#ifndef BELLV10
static struct timeval tv;
static struct timezone tz;
#endif /* BELLV10 */
#endif /* SELECT */
#endif /* OXOS */
#endif /* BSD42 */
#endif /* BSD44 */
#endif /* AIXRS */
#endif /* PS2AIX10 */
#endif /* __linux__ */
#endif /* HPUX */
#endif /* SOLARIS */
#endif /* QNX */
#ifdef BSD29
static long xclock; /* For getting time from sys/time.h */
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* BSD29 */
#ifdef BSD41
static long xclock; /* For getting time from sys/time.h */
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* BSD41 */
#ifdef BELLV10
static long xclock; /* For getting time from sys/time.h */
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* BELLV10 */
#ifdef FT21
static long xclock; /* For getting time from sys/time.h */
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* FT21 */
#ifdef TOWER1
static long xclock; /* For getting time from sys/time.h */
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* TOWER1 */
#ifdef COHERENT
static long xclock; /* For getting time from sys/time.h */
static struct timeb ftp; /* And from sys/timeb.h */
#endif /* COHERENT */
#ifdef V7
static long xclock;
#endif /* V7 */
/* sgtty/termio information... */
#ifdef BSD44ORPOSIX /* POSIX or BSD44 */
static struct termios
ttold, ttraw, tttvt, ttcur,
ccold, ccraw, cccbrk;
#else /* BSD, V7, etc */
#ifdef COHERENT /* Hack alert... */
#define ATTSV
#endif /* COHERENT */
#ifdef ATTSV
static struct termio ttold = {0}; /* Init'd for word alignment, */
static struct termio ttraw = {0}; /* which is important for some */
static struct termio tttvt = {0}; /* systems, like Zilog... */
static struct termio ttcur = {0};
static struct termio ccold = {0};
static struct termio ccraw = {0};
static struct termio cccbrk = {0};
#else
static struct sgttyb /* sgtty info... */
ttold, ttraw, tttvt, ttcur, /* for communication line */
ccold, ccraw, cccbrk; /* and for console */
#ifdef BELLV10
static struct ttydevb /* Device info... */
tdold, tdcur; /* for communication device */
#endif /* BELLV10 */
#ifdef TIOCGETC
static struct tchars tchold, tchnoi;
static int tcharf;
#endif /* TIOCGETC */
#ifdef TIOCGLTC
static struct ltchars ltchold, ltchnoi;
static int ltcharf;
#endif /* TIOCGLTC */
int lmodef = 0; /* Local modes */
int lmode = 0;
#endif /* ATTSV */
#endif /* BSD44ORPOSIX */
#ifdef PROVX1
static struct sgttyb ttbuf;
#endif /* PROVX1 */
#ifdef ultrix
/* do we really need this? */
static struct sgttyb vanilla;
#endif /* ultrix */
#ifdef ATT7300
static int attmodem = 0; /* ATT7300 internal-modem status */
struct updata dialer = {0}; /* Condition dialer for data call */
#endif /* ATT7300 */
#ifndef NOUUCP
char flfnam[128] = { '\0', '\0' }; /* UUCP lock file path name */
#ifndef USETTYLOCK
#ifdef RTAIX
char lkflfn[128] = { '\0', '\0' }; /* and possible link to it */
#endif /* RTAIX */
#ifdef HPUX
char lock2[128] = { '\0', '\0' }; /* Name of second lockfile */
#endif /* HPUX */
#endif /* USETTYLOCK */
#else
char flfnam[8] = { '\0', '\0' };
#endif /* NOUUCP */
int haslock = 0; /* =1 if this kermit locked uucp */
#ifndef OXOS
#ifdef SVORPOSIX
static int conesc = 0; /* set to 1 if esc char (^\) typed */
#else
#ifdef V7
static int conesc = 0;
#else
#ifdef C70
static int conesc = 0;
#endif /* C70 */
#endif /* V7 */
#endif /* SVORPOSIX */
#endif /* OXOS */
static char ttnmsv[DEVNAMLEN+1]; /* Local copy of comm device name */
static char lockname[DEVNAMLEN+1]; /* Ditto, the part after "/dev/". */
#ifdef aegis
static status_$t st; /* error status return value */
static short concrp = 0; /* true if console is CRP pad */
#define CONBUFSIZ 10
static char conbuf[CONBUFSIZ]; /* console readahead buffer */
static int conbufn = 0; /* # chars in readahead buffer */
static char *conbufp; /* next char in readahead buffer */
static uid_$t ttyuid; /* tty type uid */
static uid_$t conuid; /* stdout type uid */
/* APOLLO Aegis main()
* establish acl usage and cleanup handling
* this makes sure that CRP pads
* get restored to a usable mode
*/
main(argc,argv) int argc; char **argv; {
status_$t status;
pfm_$cleanup_rec dirty;
PID_T pid = getpid();
/* acl usage according to invoking environment */
default_acl(USE_DEFENV);
/* establish a cleanup continuation */
status = pfm_$cleanup(dirty);
if (status.all != pfm_$cleanup_set) {
/* only handle faults for the original process */
if (pid == getpid() && status.all > pgm_$max_severity) {
/* blew up in main process */
status_$t quo;
pfm_$cleanup_rec clean;
/* restore the console in any case */
conres();
/* attempt a clean exit */
debug(F101, "cleanup fault status", "", status.all);
/* doexit(), then send status to continuation */
quo = pfm_$cleanup(clean);
if (quo.all == pfm_$cleanup_set)
doexit(pgm_$program_faulted,-1);
else if (quo.all > pgm_$max_severity)
pfm_$signal(quo); /* blew up in doexit() */
}
/* send to the original continuation */
pfm_$signal(status);
/*NOTREACHED*/
}
return(ckcmai(argc, argv));
}
#endif /* aegis */
/* ANSI-style prototypes for internal functions. */
/* Functions used outside this module are prototyped in ckcker.h. */
#ifdef apollo
_PROTOTYP( SIGTYP timerh, () );
_PROTOTYP( SIGTYP cctrap, () );
_PROTOTYP( SIGTYP esctrp, () );
_PROTOTYP( SIGTYP sig_ign, () );
#else
_PROTOTYP( SIGTYP timerh, (int) );
_PROTOTYP( SIGTYP cctrap, (int) );
_PROTOTYP( SIGTYP esctrp, (int) );
#endif /* apollo */
_PROTOTYP( int do_open, (char *) );
_PROTOTYP( static int in_chk, (int, int) );
_PROTOTYP( static int ttrpid, (char *) );
_PROTOTYP( static int ttchkpid, (char *) );
_PROTOTYP( static int ttlock, (char *) );
_PROTOTYP( static int ttunlck, (void) );
_PROTOTYP( int mygetbuf, (void) );
_PROTOTYP( int myfillbuf, (void) );
_PROTOTYP( VOID conbgt, (int) );
#ifdef ACUCNTRL
_PROTOTYP( VOID acucntrl, (char *, char *) );
#endif /* ACUCNTRL */
#ifdef BSD44ORPOSIX
_PROTOTYP( int carrctl, (struct termios *, int) );
#else
#ifdef ATTSV
_PROTOTYP( int carrctl, (struct termio *, int) );
#else
_PROTOTYP( int carrctl, (struct sgttyb *, int) );
#endif /* ATTSV */
#endif /* BSD44ORPOSIX */
#ifdef ATT7300
_PROTOTYP( int attdial, (char *, long, char *) );
_PROTOTYP( int offgetty, (char *) );
_PROTOTYP( int ongetty, (char *) );
#endif /* ATT7300 */
#ifdef BEBOX
#ifdef SELECT
/* BeOS is not capable of using SELECT on anything but sockets */
#undef SELECT
#endif /* SELECT */
#include <kernel/OS.h>
#ifdef BE_DR_7
static double time_started = 0.0;
struct ALARM_STRUCT {
thread_id thread;
int time;
};
static thread_id alarm_thread = -1;
static struct ALARM_STRUCT alarm_struct;
_PROTOTYP( long do_alarm, (void *) );
_PROTOTYP( unsigned int alarm, (unsigned int) );
_PROTOTYP( void alarm_expired, (void) );
#endif /* BE_DR_7 */
#endif /* BEBOX */
#ifndef xunchar
#define xunchar(ch) (((ch) - 32 ) & 0xFF ) /* Character to number */
#endif /* xunchar */
#ifdef CK_ANSIC
static char *
xxlast(char *s, char c)
#else
static char *
xxlast(s,c) char *s; char c;
#endif /* CK_ANSIC */
/* xxlast */ { /* Last occurrence of character c in string s. */
int i;
for (i = (int)strlen(s); i > 0; i--)
if ( s[i-1] == c ) return( s + (i - 1) );
return(NULL);
}
/* Timeout handler for communication line input functions */
SIGTYP
timerh(foo) int foo; {
ttimoff();
#ifdef BEBOX
#ifdef BE_DR_7
alarm_expired();
#endif /* BE_DR_7 */
#endif /* BEBOX */
#ifdef CK_POSIX_SIG
siglongjmp(sjbuf,1);
#else
longjmp(sjbuf,1);
#endif /* CK_POSIX_SIG */
}
/* Control-C trap for communication line input functions */
int cc_int; /* Flag */
SIGTYP (* occt)(); /* For saving old SIGINT handler */
SIGTYP
cctrap(foo) int foo; { /* Needs arg for ANSI C */
cc_int = 1; /* signal() prototype. */
return;
}
/* S Y S I N I T -- System-dependent program initialization. */
/*
* ttgwsiz() returns:
* 1 tt_rows and tt_cols are known, both altered, both > 0
* 0 tt_rows and/or tt_cols are known, both altered, one or both <= 0
* -1 tt_rows and tt_cols are unknown and unaltered
*/
#ifndef NONAWS
extern int tt_rows, tt_cols;
#endif /* NONAWS */
static int
xttgwsiz() {
char *p;
int rows = 0, cols = 0;
p = getenv("LINES");
debug(F110,"xttgwsiz LINES",p,0);
if (p) {
rows = atol(p);
if (rows > 0) {
p = getenv("COLUMNS");
debug(F110,"xttgwsiz COLUMNS",p,0);
if (p) {
cols = atol(p);
if (cols > 0) {
tt_rows = rows;
tt_cols = cols;
return(1);
}
return(0);
}
}
}
return(-1);
}
int
ttgwsiz() {
int x = 0;
#ifndef NONAWS
#ifdef QNX
/*
NOTE: TIOCGWSIZ works here too, but only in the 32-bit version.
This code works for both the 16- and 32-bit versions.
*/
extern int dev_size(int, int, int, int *, int *);
int r, c;
if (dev_size(0, -1, -1, &r, &c) == 0) {
debug(F101,"ttgwsiz QNX r","",r);
debug(F101,"ttgwsiz QNX c","",c);
tt_rows = r;
tt_cols = c;
return ((r > 0 && c > 0) ? 1 : 0);
} else return(xttgwsiz());
#else /* QNX */
#ifdef TIOCGWINSZ
/* Note, this was M_UNIX, changed to XENIX to allow cross compilation... */
#ifdef XENIX /* SCO UNIX 3.2v4.0 */
#include <sys/stream.h> /* typedef mblk_t needed by ptem.h */
#include <sys/ptem.h> /* for ttgwsiz() */
#endif /* XENIX */
#ifdef I386IX /* Ditto for Interactive */
#include <sys/stream.h>
#include <sys/ptem.h>
#endif /* I386IX */
/* Note, the above might be needed for some other older SVR3 Intel makes... */
struct winsize w;
x = ioctl(0, (int)TIOCGWINSZ, (char *)&w);
debug(F101,"ttgwsiz TIOCGWINSZ","",x);
if (x < 0) {
return(xttgwsiz());
} else if (w.ws_row > 0 && w.ws_col > 0) {
tt_rows = w.ws_row;
tt_cols = w.ws_col;
debug(F101,"ttgwsiz tt_rows","",tt_rows);
debug(F101,"ttgwsiz tt_cols","",tt_cols);
return(1);
} else {
debug(F100,"ttgwsiz TIOCGWINSZ 00","",0);
return(xttgwsiz());
}
#else
return(xttgwsiz());
#endif /* TIOCGWINSZ */
#endif /* QNX */
#endif /* NONAWS */
}
int
sysinit() {
int x;
#ifdef CK_UTSNAME
struct utsname name;
#endif /* CK_UTSNAME */
extern char startupdir[];
/*
BEFORE ANYTHING ELSE: Initialize the setuid package.
Change to the user's real user and group ID.
If this can't be done, don't run at all.
*/
debug(F100,"sysinit calling priv_ini","",0);
if (x = priv_ini()) {
if (x & 1) fprintf(stderr,"Fatal: setuid failure.\n");
if (x & 2) fprintf(stderr,"Fatal: setgid failure.\n");
if (x & 4) fprintf(stderr,"Fatal: C-Kermit setuid to root!\n");
exit(1);
}
#ifndef NOJC
/*
Get the initial job control state.
If it is SIG_IGN, that means the shell does not support job control,
and so we'd better not suspend ourselves.
*/
#ifdef SIGTSTP
jchdlr = signal(SIGTSTP,SIG_IGN);
if (jchdlr == SIG_IGN) {
jcshell = 0;
debug(F100,"sysinit jchdlr: SIG_IGN","",0);
} else if (jchdlr == SIG_DFL) {
debug(F100,"sysinit jchdlr: SIG_DFL","",0);
jcshell = 1;
} else {
debug(F100,"sysinit jchdlr: other","",0);
jcshell = 3;
}
(VOID) signal(SIGTSTP,jchdlr); /* Put it back... */
#endif /* SIGTSTP */
#endif /* NOJC */
conbgt(0); /* See if we're in the background */
congm(); /* Get console modes */
(VOID) signal(SIGALRM,SIG_IGN); /* Ignore alarms */
#ifndef SIGUSR1 /* User-defined signals */
#define SIGUSR1 30
#endif /* SIGUSR1 */
#ifndef SIGUSR2
#define SIGUSR2 31
#endif /* SIGUSR2 */
(VOID) signal(SIGUSR1,SIG_IGN); /* Ignore user-defined signals */
(VOID) signal(SIGUSR2,SIG_IGN); /* */
#ifdef SIGDANGER /* Ignore danger signals */
/*
This signal is sent when the system is low on swap space. Processes
that don't handle it are candidates for termination. If swap space doesn't
clear out enough, we still might be terminated via kill() -- nothing we can
do about that! Conceivably, this could be improved by installing a real
signal handler that warns the user, but that would be pretty complicated,
since we are not always in control of the screen -- e.g. during remote-mode
file transfer.
*/
(VOID) signal(SIGDANGER,SIG_IGN); /* e.g. on RS/6000 AIX */
#endif /* SIGDANGER */
#ifdef SIGPIPE
/*
This one comes when a TCP/IP connection is broken by the remote.
We prefer to catch this situation by examining error codes from write().
*/
(VOID) signal(SIGPIPE,SIG_IGN);
#endif /* SIGPIPE */
#ifdef ultrix
gtty(0,&vanilla); /* Get sgtty info */
iniflags = fcntl(0,F_GETFL,0); /* Get flags */
#else
#ifdef AUX
set42sig(); /* Don't ask! (hakanson@cs.orst.edu) */
#endif /* AUX */
#endif /* ultrix */
ttgwsiz(); /* Get window (screen) dimensions. */
#ifdef Plan9
if (!backgrd) {
consctlfd = open("/dev/consctl", O_WRONLY);
/*noisefd = open("/dev/noise", O_WRONLY)*/
}
ckxech = 1;
#endif /* Plan9 */
#ifdef CK_UTSNAME
if (uname(&name) > -1) {
strncpy(unm_mch,name.machine,CK_SYSNMLN);
strncpy(unm_nam,name.sysname,CK_SYSNMLN);
strncpy(unm_rel,name.release,CK_SYSNMLN);
strncpy(unm_ver,name.version,CK_SYSNMLN);
#ifdef DEBUG
if (deblog) {
debug(F110,"sysinit uname machine",unm_mch,0);
debug(F110,"sysinit uname sysname",unm_nam,0);
debug(F110,"sysinit uname release",unm_rel,0);
debug(F110,"sysinit uname version",unm_ver,0);
}
#endif /* DEBUG */
#ifdef HPUX9PLUS
if (name.machine[5] == '8')
hpis800 = 1;
else
hpis800 = 0;
debug(F101,"sysinit hpis800","",hpis800);
#endif /* HPUX9PLUS */
}
#endif /* CK_UTSNAME */
#ifdef CK_ENVIRONMENT
{
extern char tn_env_acct[], tn_env_disp[], tn_env_job[],
tn_env_prnt[], tn_env_sys[], uidbuf[];
char *p;
if (p = getenv("USER")) strncpy(uidbuf,p,63);
if (p = getenv("JOB")) strncpy(tn_env_job,p,63);
if (p = getenv("ACCT")) strncpy(tn_env_acct,p,63);
if (p = getenv("PRINTER")) strncpy(tn_env_prnt,p,63);
if (p = getenv("DISPLAY")) strncpy(tn_env_disp,p,63);
#ifdef aegis
strcpy(tn_env_sys,"Aegis");
#else
#ifdef Plan9
strcpy(tn_env_sys,"Plan9");
#else
strcpy(tn_env_sys,"UNIX");
#endif /* Plan9 */
#endif /* aegis */
}
#endif /* CK_ENVIRONMENT */
#ifdef CK_SNDLOC
{
extern char * tn_loc;
char *p;
if (p = getenv("LOCATION"))
if (tn_loc = (char *)malloc((int)strlen(p)+1))
strcpy(tn_loc,p);
}
#endif /* CK_SNDLOC */
strcpy(startupdir, zgtdir());
x = strlen(startupdir);
if (x <= 0) {
startupdir[0] = '/';
startupdir[1] = '\0';
} else if (startupdir[x-1] != '/') {
startupdir[x] = '/';
startupdir[x+1] = '\0';
}
debug(F110,"sysinit startupdir",startupdir,0);
return(0);
}
/* S Y S C L E A N U P -- System-dependent program cleanup. */
int
syscleanup() {
#ifdef ultrix
stty(0,&vanilla); /* Get sgtty info */
fcntl(0,F_SETFL,iniflags); /* Restore flags */
#endif /* ultrix */
#ifdef NETCMD
if (ttpid) kill(ttpid,9);
#endif /* NETCMD */
return(0);
}
/* T T O P E N -- Open a tty for exclusive access. */
/*
Call with:
ttname: character string - device name or network host name.
lcl:
If called with lcl < 0, sets value of lcl as follows:
0: the terminal named by ttname is the job's controlling terminal.
1: the terminal named by ttname is not the job's controlling terminal.
But watch out: if a line is already open, or if requested line can't
be opened, then lcl remains (and is returned as) -1.
modem:
Less than zero: ttname is a network host name.
Zero or greater: ttname is a terminal device name.
Zero means a local connection (don't use modem signals).
Positive means use modem signals.
timo:
0 = no timer.
nonzero = number of seconds to wait for open() to return before timing out.
Returns:
0 on success
-5 if device is in use
-4 if access to device is denied
-3 if access to lock directory denied
-2 upon timeout waiting for device to open
-1 on other error
*/
static int ttotmo = 0; /* Timeout flag */
/* Flag kept here to avoid being clobbered by longjmp. */
int
ttopen(ttname,lcl,modem,timo) char *ttname; int *lcl, modem, timo; {
#ifdef BSD44
#define ctermid(x) strcpy(x,"")
#else
#ifdef SVORPOSIX
#ifndef CIE
extern char *ctermid(); /* Wish they all had this! */
#else /* CIE Regulus */
#define ctermid(x) strcpy(x,"")
#endif /* CIE */
#endif /* SVORPOSIX */
#endif /* BSD44 */
#ifdef ultrix
int temp = 0;
#endif /* ultrix */
char *x; /* Worker string pointer */
int y;
#ifndef MINIX
extern char* ttyname();
#endif /* MINIX */
char cname[DEVNAMLEN+4];
#ifndef pdp11
#define NAMEFD /* Feature to allow name to be an open file descriptor */
#endif /* pdp11 */
#ifdef NAMEFD
char *p;
debug(F101,"ttopen telnetfd","",telnetfd);
#endif /* NAMEFD */
debug(F111,"ttopen entry modem",ttname,modem);
debug(F101," ttyfd","",ttyfd);
debug(F101," lcl","",*lcl);
#ifdef MAXNAMLEN
debug(F100,"ttopen MAXNAMLEN defined","",0);
#else
debug(F100,"ttopen MAXNAMLEN *NOT* defined","",0);
#endif
#ifdef BSD4
debug(F100,"ttopen BSD4 defined","",0);
#else
debug(F100,"ttopen BSD4 *NOT* defined","",0);
#endif /* BSD4 */
#ifdef BSD42
debug(F100,"ttopen BSD42 defined","",0);
#else
debug(F100,"ttopen BSD42 *NOT* defined","",0);
#endif /* BSD42 */
#ifdef MYREAD
debug(F100,"ttopen MYREAD defined","",0);
#else
debug(F100,"ttopen MYREAD *NOT* defined","",0);
#endif /* MYREAD */
ttpmsk = 0xff;
if (ttyfd > -1) { /* if device already opened */
if (strncmp(ttname,ttnmsv,DEVNAMLEN)) /* are new & old names equal? */
ttclos(ttyfd); /* no, close old ttname, open new */
else /* else same, ignore this call, */
return(0); /* and return. */
}
ttpipe = 0; /* Assume it's not a pipe */
#ifdef NETCONN
if (modem < 0) { /* modem < 0 = special code for net */
int x;
ttmdm = modem;
modem = -modem; /* Positive network type number */
fdflag = 0; /* Stdio not redirected. */
netconn = 1; /* And it's a network connection */
debug(F111,"ttopen net",ttname,modem);
#ifdef NAMEFD
for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
if (*p == '\0' && (telnetfd || x25fd)) { /* Avoid X.121 addresses */
ttyfd = atoi(ttname); /* Is there a way to test it's open? */
ttfdflg = 1; /* We got an open file descriptor */
debug(F111,"ttopen got open network fd",ttname,ttyfd);
strncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
x = 1; /* Return code is "good". */
if (telnetfd) {
ttnet = NET_TCPB;
if (ttnproto != NP_TCPRAW)
ttnproto = NP_TELNET;
#ifdef SUNX25
} else if (x25fd) {
ttnet = NET_SX25;
ttnproto = NP_NONE;
#endif /* SUNX25 */
}
} else { /* Host name or address given */
#ifdef NETCMD
/*
dup2() is not available on older System V platforms like AT&T 3Bx. For
those systems we punt by not defining NETCMD, but we might be able to do
better -- see workarounds for this problem in ckufio.c (search for dup2).
*/
if (modem == NET_CMD) {
if (pipe(pipe0) || pipe(pipe1)) {
perror("Pipe error");
return(-1);
}
ttpid = fork(); /* Make a fork */
switch (ttpid) {
case -1: /* Error making fork */
close(pipe0[0]);
close(pipe0[1]);
close(pipe1[0]);
close(pipe1[1]);
perror("Fork error");
return(-1);
case 0: /* Child. */
close(pipe0[0]);
close(pipe1[1]);
dup2(pipe0[1], 1);
close(pipe0[1]);
dup2(pipe1[0], 0);
close(pipe1[0]);
system(ttname);
_exit(0);
default: /* Parent */
close(pipe0[1]);
close(pipe1[0]);
fdin = pipe0[0]; /* Read from pipe */
fdout = pipe1[1]; /* Write to pipe */
ttout = fdopen(fdout,"w"); /* Get stream so we can */
if (!ttout) { /* make it unbuffered. */
perror("fdopen failure");
return(-1);
}
setbuf(ttout,NULL);
strncpy(ttnmsv,ttname,DEVNAMLEN);
xlocal = *lcl = 1; /* It's local */
netconn = 1; /* Call it a network connection */
ttmdm = modem; /* Remember network type */
ttyfd = fdin;
ttpipe = 1;
return(0);
}
}
#endif /* NETCMD */
#endif /* NAMEFD */
x = netopen(ttname, lcl, modem); /* (see ckcnet.h) */
if (x > -1) {
strncpy(ttnmsv,ttname,DEVNAMLEN);
} else netconn = 0;
#ifdef NAMEFD
}
#endif /* NAMEFD */
#ifdef sony_news /* Sony NEWS */
if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get Kanji mode */
perror("ttopen error getting Kanji mode (network)");
debug(F111,"ttopen error getting Kanji mode","network",0);
km_ext = -1; /* Make sure this stays undefined. */
}
#endif /* sony_news */
xlocal = *lcl = 1; /* Network connections are local. */
debug(F101,"ttopen net x","",x);
#ifdef COMMENT
/* Let netopen() do this */
if (x > -1 && !x25fd)
x = tn_ini(); /* Initialize TELNET protocol */
#endif /* COMMENT */
return(x);
} else { /* Terminal device */
#endif /* NETCONN */
#ifdef NAMEFD
/*
This code lets you give Kermit an open file descriptor for a serial
communication device, rather than a device name. Kermit assumes that the
line is already open, locked, conditioned with the right parameters, etc.
*/
for (p = ttname; isdigit(*p); p++) ; /* Check for all digits */
if (*p == '\0') {
ttyfd = atoi(ttname); /* Is there a way to test it's open? */
debug(F111,"ttopen got open fd",ttname,ttyfd);
strncpy(ttnmsv,ttname,DEVNAMLEN); /* Remember the "name". */
xlocal = *lcl = 1; /* Assume it's local. */
netconn = 0; /* Assume it's not a network. */
tvtflg = 0; /* Might need to initialize modes. */
ttmdm = modem; /* Remember modem type. */
fdflag = 0; /* Stdio not redirected. */
ttfdflg = 1; /* Flag we were opened this way. */
#ifdef sony_news /* Sony NEWS */
/* Get device Kanji mode */
if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) {
perror("ttopen error getting Kanji mode");
debug(F101,"ttopen error getting Kanji mode","",0);
km_ext = -1; /* Make sure this stays undefined. */
}
#endif /* sony_news */
return(0); /* Return success */
}
#endif /* NAMEFD */
#ifdef NETCONN
}
#endif /* NETCONN */
/* Here we have to open a serial device of the given name. */
occt = signal(SIGINT, cctrap); /* Set Control-C trap, save old one */
tvtflg = 0; /* Flag for use by ttvt(). */
/* 0 = ttvt not called yet for this device */
fdflag = (!isatty(0) || !isatty(1)); /* Flag for stdio redirected */
debug(F101,"ttopen fdflag","",fdflag);
ttmdm = modem; /* Make this available to other fns */
xlocal = *lcl; /* Make this available to other fns */
/* Code for handling bidirectional tty lines goes here. */
/* Use specified method for turning off logins and suppressing getty. */
#ifdef ACUCNTRL
/* Should put call to priv_on() here, but that would be very risky! */
acucntrl("disable",ttname); /* acucntrl() program. */
/* and priv_off() here... */
#else
#ifdef ATT7300
if ((attmodem & DOGETY) == 0) /* offgetty() program. */
attmodem |= offgetty(ttname); /* Remember response. */
#endif /* ATT7300 */
#endif /* ACUCNTRL */
/*
In the following section, we open the tty device for read/write.
If a modem has been specified via "set modem" prior to "set line"
then the O_NDELAY parameter is used in the open, provided this symbol
is defined (e.g. in fcntl.h), so that the program does not hang waiting
for carrier (which in most cases won't be present because a connection
has not been dialed yet). O_NDELAY is removed later on in ttopen(). It
would make more sense to first determine if the line is local before
doing this, but because ttyname() requires a file descriptor, we have
to open it first. See do_open().
Now open the device using the desired treatment of carrier.
If carrier is REQUIRED, then open could hang forever, so an optional
timer is provided. If carrier is not required, the timer should never
go off, and should do no harm...
*/
ttotmo = 0; /* Flag no timeout */
debug(F101,"ttopen timo","",timo);
if (timo > 0) {
int xx;
saval = signal(SIGALRM,timerh); /* Timed, set up timer. */
xx = alarm(timo); /* Timed open() */
debug(F101,"ttopen alarm","",xx);
if (
#ifdef CK_POSIX_SIG
sigsetjmp(sjbuf,1)
#else
setjmp(sjbuf)
#endif /* CK_POSIX_SIG */
) {
ttotmo = 1; /* Flag timeout. */
} else ttyfd = do_open(ttname);
ttimoff();
debug(F111,"ttopen","modem",modem);
debug(F101,"ttopen ttyfd","",ttyfd);
debug(F101,"ttopen alarm return","",ttotmo);
} else {
errno = 0;
ttyfd = do_open(ttname);
}
debug(F111,"ttopen ttyfd",ttname,ttyfd);
if (ttyfd < 0) { /* If couldn't open, fail. */
debug(F101,"ttopen errno","",errno);
if (errno > 0)
perror(ttname); /* Print message */
#ifdef ATT7300
if (attmodem & DOGETY) /* was getty(1m) running before us? */
ongetty(ttnmsv); /* yes, restart on tty line */
attmodem &= ~DOGETY; /* no phone in use, getty restored */
#else
#ifdef ACUCNTRL
/* Should put call to priv_on() here, but that would be risky! */
acucntrl("enable",ttname); /* acucntrl() program. */
/* and priv_off() here... */
#endif /* ACUNTRL */
#endif /* ATT7300 */
signal(SIGINT,occt); /* Put old Ctrl-C trap back. */
if (errno == EACCES) { /* Device is protected against user */
debug(F110,"ttopen EACCESS",ttname,0); /* Return -4 */
return(-4);
} else return(ttotmo ? -2 : -1); /* Otherwise -2 if timeout, or -1 */
}
#ifdef Plan9
/* take this opportunity to open the control channel */
if (p9openttyctl(ttname) < 0)
#else
/* Make sure it's a real tty. */
if (!isatty(ttyfd) && strcmp(ttname,"/dev/null"))
#endif /* Plan9 */
{
fprintf(stderr,"%s is not a terminal device\n",ttname);
debug(F110,"ttopen not a tty",ttname,0);
close(ttyfd);
ttyfd = -1;
signal(SIGINT,occt);
return(-1);
}
#ifdef aegis
/* Apollo C runtime claims that console pads are tty devices, which
* is reasonable, but they aren't any good for packet transfer. */
ios_$inq_type_uid((short)ttyfd, ttyuid, st);
if (st.all != status_$ok) {
fprintf(stderr, "problem getting tty object type: ");
error_$print(st);
} else if (ttyuid != sio_$uid) { /* reject non-SIO lines */
close(ttyfd); ttyfd = -1;
errno = ENOTTY; perror(ttname);
signal(SIGINT,occt);
return(-1);
}
#endif /* aegis */
strncpy(ttnmsv,ttname,DEVNAMLEN); /* Keep copy of name locally. */
/* Caller wants us to figure out if line is controlling tty */
if (*lcl < 0) {
int x0 = 0, x1 = 0;
if (strcmp(ttname,CTTNAM) == 0) { /* "/dev/tty" always remote */
xlocal = 0;
debug(F111," ttname=CTTNAM",ttname,xlocal);
/* If any of 0, 1, or 2 not redirected, we can use ttyname() to get */
/* the name of the controlling terminal... */
/*
Warning: on some UNIX systems (SVR4?), ttyname() reportedly opens /dev but
never closes it. If it is called often enough, we run out of file
descriptors and subsequent open()'s of other devices or files can fail.
*/
} else if ((x0 = isatty(0)) || (x1 = isatty(1)) || isatty(2)) {
#ifndef MINIX
if (x0)
x = ttyname(0); /* and compare it with the */
else if (x1) /* tty device name. */
x = ttyname(1);
else x = ttyname(2);
strncpy(cname,x,DEVNAMLEN); /* (copy from internal static buf) */
debug(F110," cname",x,0);
#ifdef BEBOX_DR7
x = ttnmsv; /* ttyname() is broken */
#else
x = ttyname(ttyfd); /* Get real name of ttname. */
#endif /* BEBOX_DR7 */
if (x) {
if (*x) {
xlocal = (strncmp(x,cname,DEVNAMLEN) == 0) ? 0 : 1;
debug(F111," ttyname",x,xlocal);
}
} else xlocal = 1;
#else
xlocal = 1; /* Can't do this test in MINIX < 2.0 */
#endif /* MINIX */
} else { /* Else, if stdin redirected... */
#ifdef SVORPOSIX
/* System V provides nice ctermid() function to get name of controlling tty */
ctermid(cname); /* Get name of controlling terminal */
debug(F110," ctermid",cname,0);
x = ttyname(ttyfd); /* Compare with name of comm line. */
#ifdef BEBOX_DR7
xlocal = 1; /* ttyname always returns /dev/tty */
#else
xlocal = (strncmp(x,cname,DEVNAMLEN) == 0) ? 0 : 1;
#endif /* BEBOX_DR7 */
debug(F111," ttyname",x,xlocal);
#else
/* Just assume local */
xlocal = 1;
#endif /* SVORPOSIX */
debug(F101," redirected stdin","",xlocal);
}
}
#ifndef NOFDZERO
/* Note, the following code was added so that Unix "idle-line" snoopers */
/* would not think Kermit was idle when it was transferring files, and */
/* maybe log people out. */
if (xlocal == 0) { /* Remote mode */
if (fdflag == 0) { /* Standard i/o is not redirected */
debug(F100,"ttopen setting ttyfd = 0","",0);
#ifdef LYNXOS
/* On Lynx OS, fd 0 is open for read only. */
dup2(ttyfd,0);
#endif /* LYNXOS */
close(ttyfd); /* Use file descriptor 0 */
ttyfd = 0;
} else { /* Standard i/o is redirected */
debug(F101,"ttopen stdio redirected","",ttyfd);
}
}
#endif /* NOFDZERO */
/* Now check if line is locked -- if so fail, else lock for ourselves */
/* Note: After having done this, don't forget to delete the lock if you */
/* leave ttopen() with an error condition. */
lkf = 0; /* Check lock */
if (xlocal > 0) {
int xx; int xpid;
if ((xx = ttlock(ttname)) < 0) { /* Can't lock it. */
debug(F111,"ttopen ttlock fails",ttname,xx);
/* WARNING - This close() can hang if tty is an empty socket... */
close(ttyfd); /* Close the device. */
ttyfd = -1; /* Erase its file descriptor. */
signal(SIGINT,occt); /* Put old SIGINT back. */
if (xx == -2) { /* If lockfile says device in use, */
#ifndef NOUUCP
debug(F111,"ttopen reading lockfile pid",flfnam,xx);
xpid = ttrpid(flfnam); /* Try to read pid from lockfile */
if (xpid > -1) { /* If we got a pid */
printf("Locked by process %d\n",xpid); /* tell them. */
} else if (*flfnam) {
char *p = malloc(280); /* Print a directory listing. */
/*
Note: priv_on() won't help here, because we do not pass privs along to
to inferior processes, in this case ls. So if the real user does not have
directory-listing access to the lockfile directory, this will result in
something like "not found". That's why we try this only as a last resort.
*/
if (p) { /* If we got the space... */
extern char *DIRCMD;
sprintf(p,"%s %s",DIRCMD,flfnam);
zsyscmd(p); /* Get listing. */
if (p) { /* free the space */
free(p);
p = NULL;
}
}
}
#endif /* NOUUCP */
return(-5); /* Code for device in use */
} else return(-3); /* Access denied */
} else lkf = 1;
}
/* Got the line, now set the desired value for local. */
if (*lcl != 0) *lcl = xlocal;
/* Some special stuff for v7... */
#ifdef V7
#ifndef MINIX
if (kmem[TTY] < 0) { /* If open, then skip this. */
qaddr[TTY] = initrawq(ttyfd); /* Init the queue. */
if ((kmem[TTY] = open("/dev/kmem", 0)) < 0) {
fprintf(stderr, "Can't read /dev/kmem in ttopen.\n");
perror("/dev/kmem");
exit(1);
}
}
#endif /* !MINIX */
#endif /* V7 */
/* No failure returns after this point */
#ifdef ultrix
ioctl(ttyfd, TIOCMODEM, &temp);
#ifdef TIOCSINUSE
if (xlocal && ioctl(ttyfd, TIOCSINUSE, NULL) < 0) {
fprintf(stderr, "Can't set in-use flag on %s.\n",ttname);
perror("TIOCSINUSE");
}
#endif /* TIOCSINUSE */
#endif /* ultrix */
/* Get tty device settings */
#ifdef BSD44ORPOSIX /* POSIX */
tcgetattr(ttyfd,&ttold);
debug(F101,"ttopen tcgetattr ttold.c_lflag","",ttold.c_lflag);
tcgetattr(ttyfd,&ttraw);
debug(F101,"ttopen tcgetattr ttraw.c_lflag","",ttraw.c_lflag);
tcgetattr(ttyfd,&tttvt);
debug(F101,"ttopen tcgetattr tttvt.c_lflag","",tttvt.c_lflag);
#else /* BSD, V7, and all others */
#ifdef ATTSV /* AT&T UNIX */
ioctl(ttyfd,TCGETA,&ttold);
debug(F101,"ttopen ioctl TCGETA ttold.c_lflag","",ttold.c_lflag);
ioctl(ttyfd,TCGETA,&ttraw);
ioctl(ttyfd,TCGETA,&tttvt);
#else
#ifdef BELLV10
ioctl(ttyfd,TIOCGETP,&ttold);
debug(F101,"ttopen BELLV10 ttold.sg_flags","",ttold.sg_flags);
ioctl(ttyfd,TIOCGDEV,&tdold);
debug(F101,"ttopen BELLV10 tdold.flags","",tdold.flags);
#else
gtty(ttyfd,&ttold);
debug(F101,"ttopen gtty ttold.sg_flags","",ttold.sg_flags);
#endif /* BELLV10 */
#ifdef sony_news /* Sony NEWS */
if (ioctl(ttyfd,TIOCKGET,&km_ext) < 0) { /* Get console Kanji mode */
perror("ttopen error getting Kanji mode");
debug(F101,"ttopen error getting Kanji mode","",0);
km_ext = -1; /* Make sure this stays undefined. */
}
#endif /* sony_news */
#ifdef TIOCGETC
debug(F100,"ttopen TIOCGETC","",0);
tcharf = 0; /* In remote mode, also get */
if (xlocal == 0) { /* special characters */
if (ioctl(ttyfd,TIOCGETC,&tchold) < 0) {
debug(F100,"ttopen TIOCGETC failed","",0);
} else {
tcharf = 1; /* It worked. */
ioctl(ttyfd,TIOCGETC,&tchnoi); /* Get another copy */
debug(F100,"ttopen TIOCGETC ok","",0);
}
}
#else
debug(F100,"ttopen TIOCGETC not defined","",0);
#endif /* TIOCGETC */
#ifdef TIOCGLTC
debug(F100,"ttopen TIOCGLTC","",0);
ltcharf = 0; /* In remote mode, also get */
if (xlocal == 0) { /* local special characters */
if (ioctl(ttyfd,TIOCGLTC,<chold) < 0) {
debug(F100,"ttopen TIOCGLTC failed","",0);
} else {
ltcharf = 1; /* It worked. */
ioctl(ttyfd,TIOCGLTC,<chnoi); /* Get another copy */
debug(F100,"ttopen TIOCGLTC ok","",0);
}
}
#else
debug(F100,"ttopen TIOCGLTC not defined","",0);
#endif /* TIOCGLTC */
#ifdef TIOCLGET
debug(F100,"ttopen TIOCLGET","",0);
lmodef = 0;
if (ioctl(ttyfd,TIOCLGET,&lmode) < 0) {
debug(F100,"ttopen TIOCLGET failed","",0);
} else {
lmodef = 1;
debug(F100,"ttopen TIOCLGET ok","",0);
}
#endif /* TIOCLGET */
#ifdef BELLV10
ioctl(ttyfd,TIOCGETP,&ttraw);
ioctl(ttyfd,TIOCGETP,&tttvt);
#else
gtty(ttyfd,&ttraw); /* And a copy of it for packets*/
gtty(ttyfd,&tttvt); /* And one for virtual tty service */
#endif /* BELLV10 */
#endif /* ATTSV */
#endif /* BSD44ORPOSIX */
/* Section for changing line discipline. It's restored in ttres(). */
#ifdef AIXRS
#ifndef AIX41
{ union txname ld_name; int ld_idx = 0;
ttld = 0;
do {
ld_name.tx_which = ld_idx++;
ioctl(ttyfd, TXGETCD, &ld_name);
if (!strncmp(ld_name.tx_name, "rts", 3))
ttld |= 1;
} while (*ld_name.tx_name);
debug(F101,"AIX line discipline","",ttld);
}
#endif /* AIX41 */
#endif /* AIXRS */
#ifdef BSD41
/* For 4.1BSD only, force "old" tty driver, new one botches TANDEM. */
{ int k;
ioctl(ttyfd, TIOCGETD, &ttld); /* Get and save line discipline */
debug(F101,"4.1bsd line discipline","",ttld);
k = OTTYDISC; /* Switch to "old" discipline */
k = ioctl(ttyfd, TIOCSETD, &k);
debug(F101,"4.1bsd tiocsetd","",k);
}
#endif /* BSD41 */
#ifdef aegis
/* This was previously done before the last two TCGETA or gtty above,
* in both the ATTSV and not-ATTSV case. If it is not okay to have only
* one copy if it here instead, give us a shout!
*/
sio_$control((short)ttyfd, sio_$raw_nl, false, st);
if (xlocal) { /* ignore breaks from local line */
sio_$control((short)ttyfd, sio_$int_enable, false, st);
sio_$control((short)ttyfd, sio_$quit_enable, false, st);
}
#endif /* aegis */
#ifdef VXVE
ttraw.c_line = 0; /* STTY line 0 for VX/VE */
tttvt.c_line = 0; /* STTY line 0 for VX/VE */
ioctl(ttyfd,TCSETA,&ttraw);
#endif /* vxve */
/* If O_NDELAY was used during open(), then remove it now. */
#ifdef O_NDELAY
debug(F100,"ttopen O_NDELAY","",0);
if (fcntl(ttyfd, F_GETFL, 0) & O_NDELAY) {
debug(F100,"ttopen fcntl O_NDELAY","",0);
#ifndef aegis
if (fcntl(ttyfd,F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY) < 0) {
debug(F100,"ttopen fcntl failure to unset O_NDELAY","",0);
perror("Can't unset O_NDELAY");
}
#endif /* aegis */
/* Some systems, notably Xenix (don't know how common this is in
* other systems), need special treatment to get rid of the O_NDELAY
* behaviour on read() with respect to carrier presence (i.e. read()
* returning 0 when carrier absent), even though the above fcntl()
* is enough to make read() wait for input when carrier is present.
* This magic, in turn, requires CLOCAL for working when the carrier
* is absent. But if xlocal == 0, presumably you already have CLOCAL
* or you have a carrier, otherwise you wouldn't be running this.
*/
debug(F101,"ttopen xlocal","",xlocal);
#ifdef ATTSV
#ifdef BSD44ORPOSIX
#ifdef COMMENT /* 12 Aug 1997 */
#ifdef __bsdi__
if (xlocal)
ttraw.c_cflag |= CLOCAL;
#else
#ifdef __FreeBSD__
if (xlocal)
ttraw.c_cflag |= CLOCAL;
#endif /* __FreeBSD__ */
#endif /* __bsdi__ */
#else /* Not COMMENT */
#ifdef CLOCAL
if (xlocal) /* Unset this if it's defined. */
ttraw.c_cflag |= CLOCAL;
#endif /* CLOCAL */
#endif /* COMMENT */
debug(F100,"ttopen calling POSIX tcseattr","",0);
if (tcsetattr(ttyfd, TCSADRAIN, &ttraw) < 0) {
debug(F100,"ttopen POSIX tcseattr fails","",0);
perror("tcsetattr");
}
#else /* !BSD44ORPOSIX */
if (xlocal) {
ttraw.c_cflag |= CLOCAL;
ioctl(ttyfd, TCSETA, &ttraw);
}
#endif /* BSD44ORPOSIX */
#endif /* ATTSV */
#ifndef NOCOTFMC /* = NO Close(Open()) To Force Mode Change */
/* Reportedly lets uugetty grab the device in SCO UNIX 3.2 / XENIX 2.3 */
debug(F100,"ttopen executing close/open","",0);
close( priv_opn(ttname, O_RDWR) ); /* Magic to force change. */
#endif /* NOCOTFMC */
}
#endif /* O_NDELAY */
/* Instruct the system how to treat the carrier, and set a few other tty
* parameters.
*
* This also undoes the temporary setting of CLOCAL that may have been done
* for the close(open()) above (except in Xenix). Also throw in ~ECHO, to
* prevent the other end of the line from sitting there talking to itself,
* producing garbage when the user performs a connect.
*
* SCO Xenix unfortunately seems to ignore the actual state of CLOCAL.
* Now it thinks CLOCAL is always on. It seems the only real solution for
* Xenix is to switch between the lower and upper case device names.
*
* This section may at some future time expand into setting a complete
* collection of tty parameters, or call a function shared with ttpkt()/
* ttvt() that does so. On the other hand, the initial parameters are not
* that important, since ttpkt() or ttvt() should always fix that before
* any communication is done. Well, we'll see...
*/
if (xlocal) {
curcarr = -2;
debug(F100,"ttopen calling carrctl","",0);
carrctl(&ttraw, ttcarr == CAR_ON);
debug(F100,"ttopen carrctl ok","",0);
#ifdef COHERENT
#define SVORPOSIX
#endif /* COHERENT */
#ifdef SVORPOSIX
ttraw.c_lflag &= ~ECHO;
ttold.c_lflag &= ~ECHO;
#ifdef BSD44ORPOSIX
y = tcsetattr(ttyfd, TCSADRAIN, &ttraw);
debug(F101,"ttopen tcsetattr","",y);
#else
y = ioctl(ttyfd, TCSETA, &ttraw);
debug(F100,"ttopen ioctl","",y);
#endif /* BSD44ORPOSIX */
#else /* BSD, etc */
ttraw.sg_flags &= ~ECHO;
ttold.sg_flags &= ~ECHO;
#ifdef BELLV10
y = ioctl(ttyfd,TIOCSETP,&ttraw);
debug(F100,"ttopen ioctl","",y);
#else
y = stty(ttyfd,&ttraw);
debug(F100,"ttopen stty","",y);
#endif /* BELLV10 */
#endif /* SVORPOSIX */
#ifdef COHERENT
#undef SVORPOSIX
#endif /* COHERENT */
/* ttflui(); */ /* This fails for some reason. */
}
/* Get current speed */
#ifndef BEBOX
ttspeed = ttgspd();
#else
ttspeed = 19200;
#endif /* !BEBOX */
debug(F101,"ttopen ttspeed","",ttspeed);
/* Done, make entries in debug log, restore Ctrl-C trap, and return. */
debug(F101,"ttopen ttyfd","",ttyfd);
debug(F101,"ttopen *lcl","",*lcl);
debug(F111,"ttopen lock file",flfnam,lkf);
signal(SIGINT,occt);
return(0);
}
/* D O _ O P E N -- Do the right kind of open() call for the tty. */
int
do_open(ttname) char *ttname; {
#ifndef O_NDELAY /* O_NDELAY not defined */
return(priv_opn(ttname,2));
#else /* O_NDELAY defined */
#ifdef ATT7300
/*
Open comms line without waiting for carrier so initial call does not hang
because state of "modem" is likely unknown at the initial call -jrd.
If this is needed for the getty stuff to work, and the open would not work
without O_NDELAY when getty is still on, then this special case is ok.
Otherwise, get rid of it. -ske
*/
return(priv_opn(ttname, O_RDWR | O_NDELAY));
#else /* !ATT7300 */
/* Normal case. Use O_NDELAY according to SET CARRIER. See ttscarr(). */
return(priv_opn(ttname, O_RDWR | ((ttcarr != CAR_ON) ? O_NDELAY : 0) ));
#endif /* !ATT7300 */
#endif /* O_NDELAY */
}
/* T T C L O S -- Close the TTY, releasing any lock. */
int
ttclos(foo) int foo; { /* Arg req'd for signal() prototype */
int xx, x = 0;
debug(F101,"ttclos ttyfd","",ttyfd);
if (ttyfd < 0) return(0); /* Wasn't open. */
if (ttfdflg) /* If we inherited ttyfd from */
return(0); /* another process, don't close it. */
tvtflg = 0; /* (some day get rid of this...) */
#ifdef NETCMD
if (ttpipe) { /* We've been using a pipe */
/* ttpipe = 0; */
if (ttpid > 0) {
int wstat;
#ifdef OSF40
union wait statusp_w;
int statusp;
#else
int statusp;
#endif /* OSF40 */
close(fdin); /* Close these. */
close(fdout);
fdin = fdout = -1;
kill(ttpid,1); /* Kill fork with SIGHUP */
while (1) {
wstat = wait(
#ifdef OSF40
&statusp_w
#else
&statusp
#endif /* OSF40 */
);
if (wstat == ttpid || wstat == -1)
break;
#ifdef OSF40
statusp = (*(int *)&(statusp_w));
#endif /* OSF40 */
pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
}
ttpid = 0;
}
netconn = 0;
ttyfd = -1;
return(0);
}
#endif /* NETCMD */
#ifdef NETCONN
if (netconn) { /* If it's a network connection. */
debug(F100,"ttclos closing net","",0);
netclos(); /* Let the network module close it. */
netconn = 0; /* No more network connection. */
debug(F101,"ttclos ttyfd after netclos","",ttyfd); /* Should be -1 */
return(0);
}
#endif /* NETCONN */
if (xlocal) { /* We're closing a SET LINE device */
#ifdef FT21 /* Fortune 2.1-specific items ... */
ioctl(ttyfd,TIOCHPCL, NULL);
#endif /* FT21 */
#ifdef ultrix /* Ultrix-specific items ... */
#ifdef TIOCSINUSE
/* Unset the INUSE flag that we set in ttopen() */
ioctl(ttyfd, TIOCSINUSE, NULL);
#endif /* TIOCSINUSE */
ioctl(ttyfd, TIOCNMODEM, &x);
#ifdef COMMENT
/* What was this? */
ioctl(ttyfd, TIOCNCAR, NULL);
#endif /* COMMENT */
#endif /* ultrix */
debug(F100,"ttclos about to call ttunlck","",0);
if (ttunlck()) /* Release uucp-style lock */
fprintf(stderr,"Warning, problem releasing lock\r\n");
}
if (
xlocal
#ifdef NOFDZERO
|| ttyfd > 0
#endif /* NOFDZERO */
) {
saval = signal(SIGALRM,timerh); /* Enable timer interrupt. */
xx = alarm(8); /* Allow 8 seconds for this. */
debug(F101,"ttclos alarm","",xx);
if (
#ifdef CK_POSIX_SIG
sigsetjmp(sjbuf,1)
#else
setjmp(sjbuf)
#endif /* CK_POSIX_SIG */
) { /* Timer went off? */
x = -1;
} else { /* What we're really trying to do */
debug(F100,"ttclos calling tthang()","",0);
tthang(); /* Hang up first, then... */
debug(F100,"ttclos calling ttres()","",0);
ttres(); /* Reset device modes. */
}
debug(F101,"ttclos about to call close","",ttyfd);
close(ttyfd); /* Close the device. */
x = 1;
ttimoff(); /* Turn off timer. */
if (x < 0) {
fprintf(stderr,"?Timed out closing device: %s\n",ttnmsv);
debug(F100,"ttclos timed out","",0);
}
}
/* For bidirectional lines, restore getty if it was there before. */
if (xlocal) {
#ifdef ACUCNTRL /* 4.3BSD acucntrl() method. */
acucntrl("enable",ttnmsv); /* Enable getty on the device. */
#else
#ifdef ATT7300 /* ATT UNIX PC (3B1, 7300) method. */
if (attmodem & DOGETY) /* Was getty(1m) running before us? */
ongetty(ttnmsv); /* Yes, restart getty on tty line */
attmodem &= ~DOGETY; /* No phone in use, getty restored */
#endif /* ATT7300 */
#endif /* System-dependent getty-restoring methods */
}
#ifdef sony_news
km_ext = -1; /* Invalidate device's Kanji-mode */
#endif /* sony_news */
ttyfd = -1; /* Invalidate the file descriptor. */
debug(F100,"ttclos done","",0);
return(0);
}
/* T T H A N G -- Hangup phone line or network connection. */
/*
Returns:
0 if it does nothing.
1 if it believes that it hung up successfully.
-1 if it believes that the hangup attempt failed.
*/
#define HUPTIME 500 /* Milliseconds for hangup */
int
tthang() {
#ifdef NOLOCAL
return(0);
#else
int x = 0; /* Sometimes used as return code. */
#ifndef POSIX
int z; /* worker */
#endif /* POSIX */
#ifdef COHERENT
#define SVORPOSIX
#endif /* COHERENT */
#ifdef SVORPOSIX /* AT&T, POSIX, HPUX declarations. */
int spdsav; /* for saving speed */
#ifdef BSD44ORPOSIX
int spdsavi;
#endif /* BSD44ORPOSIX */
#ifdef HPUX
/*
Early versions of HP-UX omitted the mflag typedef. If you get complaints
about it, just change it to long (or better still, unsigned long).
*/
mflag
dtr_down = 00000000000,
modem_rtn,
modem_sav;
char modem_state[64];
#endif /* HPUX */
int flags; /* fcntl flags */
unsigned short ttc_save;
#endif /* SVORPOSIX */
#ifdef COHERENT
#undef SVORPOSIX
#endif /* COHERENT */
if (ttyfd < 0) return(0); /* Don't do this if not open */
if (xlocal < 1) return(0); /* Don't do this if not local */
#ifdef NETCMD
if (ttpipe)
return((ttclos(0) < 0) ? -1 : 1);
#endif /* NETCMD */
#ifdef NETCONN
if (netconn) /* Network connection. */
return((netclos() < 0) ? -1 : 1); /* Just close it. */
#endif /* NETCONN */
/* From here down, we handle real tty devices. */
#ifdef BSD44ORPOSIX
/* Should add some error checking here... */
/*
NOTE: This should work for QNX too, but in case it doesn't, it is also
possible to toggle DTR using qnx_ioctl(ttyfd,QCTL_DEV_CTL,&new,&old);
see <sys/qioctl.h> and QNX News V10, Sep 96, p44.
*/
debug(F100,"tthang POSIX style","",0);
tcgetattr(ttyfd, &ttcur); /* Get current attributes */
spdsav = cfgetospeed(&ttcur); /* Get current speed */
spdsavi = cfgetispeed(&ttcur); /* Get current speed */
cfsetospeed(&ttcur,B0); /* Replace by 0 */
cfsetispeed(&ttcur,B0);
if (tcsetattr(ttyfd,TCSADRAIN,&ttcur) == -1)
debug(F100,"tthang tcsetattr fails","",errno);
msleep(HUPTIME); /* Sleep */
cfsetospeed(&ttcur,spdsav); /* Restore previous speed */
cfsetispeed(&ttcur,spdsavi);
tcsetattr(ttyfd,TCSADRAIN,&ttcur);
return(1);
#else /* BSD44ORPOSIX */
#ifdef aegis /* Apollo Aegis */
sio_$control((short)ttyfd, sio_$dtr, false, st); /* DTR down */
msleep(HUPTIME); /* pause */
sio_$control((short)ttyfd, sio_$dtr, true, st); /* DTR up */
return(1);
#endif /* aegis */
#ifdef ANYBSD /* Any BSD version. */
#ifdef TIOCCDTR /* Except those that don't have this */
debug(F100,"tthang BSD style","",0);
if (ioctl(ttyfd,TIOCCDTR,0) < 0) { /* Clear DTR. */
debug(F101,"tthang TIOCCDTR fails","",errno);
return(-1);
}
msleep(HUPTIME); /* For about 1/2 sec */
errno = 0;
x = ioctl(ttyfd,TIOCSDTR,0); /* Restore DTR */
if (x < 0) {
/*
For some reason, this tends to fail with "no such device or address"
but the operation still works, probably because of the close/open
later on. So let's not scare the user unnecessarily here.
*/
debug(F101,"tthang TIOCSDTR errno","",errno); /* Log the error */
x = 1; /* Pretend we succeeded */
} else if (x == 0) x = 1; /* Success */
#ifdef COMMENT
#ifdef FT21
ioctl(ttyfd, TIOCSAVEMODES, 0);
ioctl(ttyfd, TIOCHPCL, 0);
close(ttyfd); /* Yes, must do this twice */
if ((ttyfd = open(ttnmsv,2)) < 0) /* on Fortune computers... */
return(-1); /* (but why?) */
else x = 1;
#endif /* FT21 */
#endif /* COMMENT */
#endif /* TIOCCDTR */
close(do_open(ttnmsv)); /* Clear i/o error condition */
errno = 0;
#ifdef COMMENT
/* This is definitely dangerous. Why was it here? */
z = ttvt(ttspeed,ttflow); /* Restore modes. */
debug(F101,"tthang ttvt returns","",z);
return(z < 0 ? -1 : 1);
#else
return(x);
#endif /* COMMENT */
#endif /* ANYBSD */
#ifdef ATTSV
/* AT&T UNIX section, includes HP-UX and generic AT&T System III/V... */
#ifdef HPUX
/* Hewlett Packard allows explicit manipulation of modem signals. */
#ifdef COMMENT
/* Old way... */
debug(F100,"tthang HP-UX style","",0);
if (ioctl(ttyfd,MCSETAF,&dtr_down) < 0) /* lower DTR */
return(-1); /* oops, can't. */
msleep(HUPTIME); /* Pause half a second. */
x = 1; /* Set return code */
if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */
if ((modem_rtn & MDCD) != 0) /* Check if CD is low. */
x = -1; /* CD didn't drop, fail. */
} else x = -1;
/* Even if above calls fail, RTS & DTR should be turned back on. */
modem_rtn = MRTS | MDTR;
if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) x = -1;
return(x);
#else
/* New way, from Hellmuth Michaelis */
debug(F100,"tthang HP-UX style, HPUXDEBUG","",0);
if (ioctl(ttyfd,MCGETA,&modem_rtn) == -1) { /* Get current status. */
debug(F100,"tthang HP-UX: can't get modem lines, NO HANGUP!","",0);
return(-1);
}
sprintf(modem_state,"%#lx",modem_rtn);
debug(F110,"tthang HP-UX: modem lines = ",modem_state,0);
modem_sav = modem_rtn; /* Save current modem signals */
modem_rtn &= ~MDTR; /* Turn DTR bit off */
sprintf(modem_state,"%#lx",modem_rtn);
debug(F110,"tthang HP-UX: DTR down = ",modem_state,0);
if (ioctl(ttyfd,MCSETAF,&modem_rtn) < 0) { /* lower DTR */
debug(F100,"tthang HP-UX: can't lower DTR!","",0);
return(-1); /* oops, can't. */
}
msleep(HUPTIME); /* Pause half a second. */
x = 1; /* Set return code */
if (ioctl(ttyfd,MCGETA,&modem_rtn) > -1) { /* Get line status. */
sprintf(modem_state,"%#lx",modem_rtn);
debug(F110,"tthang HP-UX: modem lines got = ",modem_state,0);
if ((modem_rtn & MDCD) != 0) { /* Check if CD is low. */
debug(F100,"tthang HP-UX: DCD not down","",0);
x = -1; /* CD didn't drop, fail. */
} else {
debug(F100,"tthang HP-UX: DCD down","",0);
}
} else {
x = -1;
debug(F100,"tthang HP-UX: can't get DCD status !","",0);
}
/* Even if above calls fail, DTR should be turned back on. */
modem_sav |= MDTR;
if (ioctl(ttyfd,MCSETAF,&modem_sav) < 0) {
x = -1;
debug(F100,"tthang HP-UX: can't set saved state","",0);
} else {
sprintf(modem_state,"%#lx",modem_sav);
debug(F110,"tthang HP-UX: final modem lines = ",modem_state,0);
}
return(x);
#endif /* COMMENT */
#else /* AT&T but not HP-UX */
/* SVID for AT&T System V R3 defines ioctl's for handling modem signals. */
/* It is not known how many, if any, systems actually implement them, */
/* so we include them here in ifdef's. */
#ifndef _IBMR2
/*
No modem-signal twiddling for IBM RT PC or RS/6000.
In AIX 3.1 and earlier, the ioctl() call is broken.
This code could be activated for AIX 3.1 with PTF 2006 or later
(e.g. AIX 3.2), but close/open does the job too, so why bother.
*/
#ifdef TIOCMBIS /* Bit Set */
#ifdef TIOCMBIC /* Bit Clear */
#ifdef TIOCM_DTR /* DTR */
/* Clear DTR, sleep 300 msec, turn it back on. */
/* If any of the ioctl's return failure, go on to the next section. */
z = TIOCM_DTR; /* Code for DTR. */
#ifdef COMMENT
/*
This was the cause of the troubles with the Solaris Port Monitor.
The problem is: RTS never comes back on. Moral: Don't do it!
(But why doesn't it come back on? See the TIOCMBIS call...)
*/
#ifdef TIOCM_RTS /* Lower RTS too if symbol is known. */
z |= TIOCM_RTS;
#endif /* TIOCM_RTS */
#endif /* COMMENT */
debug(F101,"tthang TIOCM signal mask","",z);
if (ioctl(ttyfd,TIOCMBIC,&z) > -1) { /* Try to lower DTR. */
debug(F100,"tthang TIOCMBIC ok","",0);
msleep(HUPTIME); /* Pause half a second. */
if (ioctl(ttyfd,TIOCMBIS,&z) > -1) { /* Try to turn it back on. */
debug(F100,"tthang TIOCMBIS ok","",0);
#ifndef CLSOPN
return(1); /* Success, done. */
#endif /* CLSOPN */
} else { /* Couldn't raise, continue. */
debug(F101,"tthang TIOCMBIS errno","",errno);
}
} else { /* Couldn't lower, continue. */
debug(F101,"tthang TIOCMBIC errno","",errno);
}
#endif /* TIOCM_DTR */
#endif /* TIOCMBIC */
#endif /* TIOCMBIS */
#endif /* _IBMR2 */
/*
General AT&T UNIX case, not HPUX. The following code is highly suspect. No
two AT&T-based systems seem to do this the same way. The object is simply
to turn off DTR and then turn it back on. SVID says the universal method
for turning off DTR is to set the speed to zero, and this does seem to do
the trick in all cases. But neither SVID nor any known man pages say how to
turn DTR back on again. Some variants, like most Xenix implementations,
raise DTR again when the speed is restored to a nonzero value. Others
require the device to be closed and opened again, but this is risky because
getty could seize the device during the instant it is closed.
*/
/* Return code for ioctl failures... */
#ifdef ATT6300
x = 1; /* ATT6300 doesn't want to fail... */
#else
x = -1;
#endif /* ATT6300 */
debug(F100,"tthang get settings","",0);
if (ioctl(ttyfd,TCGETA,&ttcur) < 0) /* Get current settings. */
return(x); /* Fail if this doesn't work. */
if ((flags = fcntl(ttyfd,F_GETFL,0)) < 0) /* Get device flags. */
return(x);
ttc_save = ttcur.c_cflag; /* Remember current speed. */
spdsav = ttc_save & CBAUD;
debug(F101,"tthang speed","",spdsav);
#ifdef O_NDELAY
debug(F100,"tthang turning O_NDELAY on","",0);
fcntl(ttyfd, F_SETFL, flags | O_NDELAY); /* Activate O_NDELAY */
#endif /* O_NDELAY */
#ifdef ATT7300 /* This is the way it is SUPPOSED to work */
ttcur.c_cflag &= ~CBAUD; /* Change the speed to zero. */
#else
#ifdef RTAIX
ttcur.c_cflag &= ~CBAUD; /* Change the speed to zero. */
#else /* This way really works but may be dangerous */
#ifdef u3b2
ttcur.c_cflag = ~(CBAUD|CLOCAL); /* Special for AT&T 3B2s */
/* (CLOCAL must be OFF) */
#else
#ifdef SCO3R2 /* SCO UNIX 3.2 */
/*
This is complete nonsense, but an SCO user claimed this change made
hanging up work. Comments from other SCO UNIX 3.2 users would be
appreciated.
*/
ttcur.c_cflag = CBAUD|B0;
#else
#ifdef AIXRS /* AIX on RS/6000 */
/*
Can't set speed to zero on AIX 3.1 on RS/6000 64-port adapter,
even though you can do it on the built-in port and the 8- and 16-port
adapters. (Untested on 128-port adapter.)
*/
ttcur.c_cflag = CLOCAL|HUPCL|spdsav; /* Speed 0 causes EINVAL */
#else /* None of the above */
/*
Set everything, including the speed, to zero, except for the CLOCAL
and HUPCL bits.
*/
ttcur.c_cflag = CLOCAL|HUPCL;
#endif /* AIXRS */
#endif /* SCO3R2 */
#endif /* u3b2 */
#endif /* RTAIX */
#endif /* ATT7300 */
#ifdef COMMENT
/* and if none of those work, try one of these... */
ttcur.c_cflag = 0;
ttcur.c_cflag = CLOCAL;
ttcur.c_cflag &= ~(CBAUD|HUPCL);
ttcur.c_cflag &= ~(CBAUD|CREAD);
ttcur.c_cflag &= ~(CBAUD|CREAD|HUPCL);
/* or other combinations */
#endif /* COMMENT */
#ifdef TCXONC
debug(F100,"tthang TCXONC","",0);
ioctl(ttyfd, TCXONC, 1);
#endif /* TCXONC */
#ifdef TIOCSTART
debug(F100,"tthang TIOCSTART","",0);
ioctl(ttyfd, TIOCSTART, 0);
#endif /* TIOCSTART */
if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) { /* Fail if we can't. */
fcntl(ttyfd, F_SETFL, flags); /* Restore flags */
return(-1); /* before returning. */
}
msleep(300); /* Give modem time to notice. */
/* Now, even though it doesn't say this in SVID or any man page, we have */
/* to close and reopen the device. This is not necessary for all systems, */
/* but it's impossible to predict which ones need it and which ones don't. */
#ifdef ATT7300
/*
Special handling for ATT 7300 UNIX PC and 3B1, which have "phone"
related ioctl's for their internal modems. attmodem has getty status and
modem-in-use bit. Reportedly the ATT7300/3B1 PIOCDISC call is necessary,
but also ruins the file descriptor, and no other phone(7) ioctl call can fix
it. Whateverit does, it seems to escape detection with PIOCGETA and TCGETA.
The only way to undo the damage is to close the fd and then reopen it.
*/
if (attmodem & ISMODEM) {
debug(F100,"tthang attmodem close/open","",0);
ioctl(ttyfd,PIOCUNHOLD,&dialer); /* Return call to handset. */
ioctl(ttyfd,PIOCDISC,&dialer); /* Disconnect phone. */
close(ttyfd); /* Close and reopen the fd. */
ttyfd = priv_opn(ttnmsv, O_RDWR | O_NDELAY);
attmodem &= ~ISMODEM; /* Phone no longer in use. */
}
#else /* !ATT7300 */
/* It seems we have to close and open the device for other AT&T systems */
/* too, and this is the place to do it. The following code does the */
/* famous close(open(...)) magic by default. If that doesn't work for you, */
/* then try uncommenting the following statement or putting -DCLSOPN in */
/* the makefile CFLAGS. */
/* #define CLSOPN */
#ifndef SCO32 /* Not needed by, and harmful to, SCO UNIX 3.2 / Xenix 2.3 */
#ifdef O_NDELAY
#define OPENFLGS O_RDWR | O_NDELAY
#else
#define OPENFLGS O_RDWR
#endif
#ifndef CLSOPN
/* This method is used by default, i.e. unless CLSOPN is defined. */
/* It is thought to be safer because there is no window where getty */
/* can seize control of the device. The drawback is that it might not work. */
debug(F101,"tthang close(open()), OPENFLGS","",OPENFLGS);
close(priv_opn(ttnmsv, OPENFLGS));
#else
/* This method is used if you #define CLSOPN. It is more likely to work */
/* than the previous method, but it's also more dangerous. */
debug(F101,"tthang close/open, OPENFLGS","",OPENFLGS);
close(ttyfd);
msleep(10);
ttyfd = priv_opn(ttnmsv, OPENFLGS); /* Open it again */
#endif /* CLSOPN */
#undef OPENFLGS
#endif /* SCO32 */
#endif /* ATT7300 */
/* Now put all flags & modes back the way we found them. */
/* (Does the order of ioctl & fcntl matter ? ) */
debug(F100,"tthang restore settings","",0);
ttcur.c_cflag = ttc_save; /* Get old speed back. */
if (ioctl(ttyfd,TCSETAF,&ttcur) < 0) /* ioctl parameters. */
return(-1);
#ifdef O_NDELAY
/*
This is required for IBM RT and RS/6000, probably helps elsewhere too (?).
After closing a modem line, the modem will probably not be asserting
carrier any more, so we should not require carrier any more. If this
causes trouble on non-IBM UNIXes, change the #ifdef to use _IBMR2 rather
than O_NDELAY.
*/
flags &= ~O_NDELAY; /* Don't require carrier on reopen */
#endif /* O_NDELAY */
if (fcntl(ttyfd,F_SETFL,flags) < 0) /* fcntl parameters */
return(-1);
return(1);
#endif /* not HPUX */
#endif /* ATTSV */
#endif /* BSD44ORPOSIX */
#endif /* NOLOCAL */
}
/*
Major change in 5A(174). We used to use LPASS8, if it was defined, to
allow 8-bit data and Xon/Xoff flow control at the same time. But this
LPASS8 business seems to have been causing trouble for everybody but me!
For example, Annex terminal servers, commonly used with Encore computers,
do not support LPASS8 even though the Encore itself does. Ditto for many
other terminal servers, TELNET connections, rlogin connections, etc etc.
Now, reportedly, even vanilla 4.3 BSD systems can't do this right on their
serial lines, even though LPASS8 is a feature of 4.3BSD. So let's turn it
off for everybody. That means we goes back to using raw mode, with no
flow control. Phooey.
NOTE: This must be done before the first reference to LPASS8 in this file,
and after the last #include statment.
*/
#ifdef LPASS8
#undef LPASS8
#endif /* LPASS8 */
/* T T R E S -- Restore terminal to "normal" mode. */
/* ske@pkmab.se: There are two choices for what this function should do.
* (1) Restore the tty to current "normal" mode, with carrier treatment
* according to ttcarr, to be used after every kermit command. (2) Restore
* the tty to the state it was in before kermit opened it. These choices
* conflict, since ttold can't hold both choices of tty parameters. ttres()
* is currently being called as in choice (1), but ttold basically holds
* the initial parameters, as in (2), and the description at the beginning
* of this file says (2).
*
* I don't think restoring tty parameters after all kermit commands makes
* much of a difference. Restoring them upon exit from kermit may be of
* some use in some cases (when the line is not restored automatically on
* close, by the operating system).
*
* I can't choose which one it should be, so I haven't changed it. It
* probably works as it is, too. It would probably even work even with
* ttres() entirely deleted...
*
* (from fdc: Actually, this function operates in remote mode too, so
* it restores the console (command) terminal to whatever mode it was
* in before packet operations began, so that commands work right again.)
*/
int
ttres() { /* Restore the tty to normal. */
int x;
if (ttyfd < 0) return(-1); /* Not open. */
if (ttfdflg) return(0); /* Don't mess with terminal modes if */
/* we got ttyfd from another process */
#ifdef NETCONN
if (netconn) { /* Network connection */
tvtflg = 0;
#ifdef TCPSOCKET
#ifdef TCP_NODELAY
{
extern int tcp_nodelay; /* Just put this back if necessary */
if (ttnet == NET_TCPB) {
if (nodelay_sav > -1) {
no_delay(nodelay_sav);
nodelay_sav = -1;
}
}
}
#endif /* TCP_NODELAY */
#endif /* TCPSOCKET */
return(0);
}
#endif /* NETCONN */
if (ttpipe) return(0);
/* Real terminal device, so restore its original modes */
#ifdef BSD44ORPOSIX /* For POSIX like this */
x = tcsetattr(ttyfd,TCSADRAIN,&ttold);
#else /* For all others... */
#ifdef ATTSV /* For AT&T versions... */
x = ioctl(ttyfd,TCSETAW,&ttold); /* Restore tty modes this way. */
#else
/* Here we restore the modes for BSD */
#ifdef LPASS8 /* Undo "pass8" if it were done */
if (lmodef) {
if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
debug(F100,"ttres TIOCLSET failed","",0);
else
debug(F100,"ttres TIOCLSET ok","",0);
}
#endif /* LPASS8 */
#ifdef CK_DTRCTS /* Undo hardware flow if it were done */
if (lmodef) {
if (ioctl(ttyfd,TIOCLSET,&lmode) < 0)
debug(F100,"ttres TIOCLSET failed","",0);
else
debug(F100,"ttres TIOCLSET ok","",0);
}
#endif /* CK_DTRCTS */
#ifdef TIOCGETC /* Put back special characters */
if (tcharf && (xlocal == 0)) {
if (ioctl(ttyfd,TIOCSETC,&tchold) < 0)
debug(F100,"ttres TIOCSETC failed","",0);
else
debug(F100,"ttres TIOCSETC ok","",0);
}
#endif /* TIOCGETC */
#ifdef TIOCGLTC /* Put back local special characters */
if (ltcharf && (xlocal == 0)) {
if (ioctl(ttyfd,TIOCSLTC,<chold) < 0)
debug(F100,"ttres TIOCSLTC failed","",0);
else
debug(F100,"ttres TIOCSLTC ok","",0);
}
#endif /* TIOCGLTC */
#ifdef BELLV10
x = ioctl(ttyfd,TIOCSETP,&ttold); /* Restore both structs */
x = ioctl(ttyfd,TIOCSDEV,&tdold);
#else
x = stty(ttyfd,&ttold); /* Restore tty modes the old way. */
#endif /* BELLV10 */
if (!xlocal)
msleep(100); /* This replaces sleep(1)... */
/* Put back sleep(1) if tty is */
/* messed up after close. */
#endif /* ATTSV */
#endif /* BSD44ORPOSIX */
debug(F101,"ttres tty modes restore","",x);
#ifndef QNX
if (x < 0) debug(F101,"ttres errno","",errno);
#endif /* QNX */
#ifdef AIXRS
#ifndef AIX41
x = ioctl(ttyfd, ttld & 1 ? TXADDCD : TXDELCD, "rts");
debug(F101,"ttres AIX line discipline rts restore","",x);
#endif /* AIX41 */
#endif /* AIXRS */
#ifdef BSD41
if (ttld > -1) { /* Put back line discipline */
x = ioctl(ttyfd, TIOCSETD, &ttld);
debug(F101,"ttres line discipline restore","",x);
if (x < 0) debug(F101,"...ioctl errno","",errno);
ttld = -1;
}
#endif /* BSD41 */
#ifdef sony_news
x = xlocal ? km_ext : km_con; /* Restore Kanji mode. */
if (x != -1) { /* Make sure we know original modes. */
if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
perror("ttres can't set Kanji mode");
debug(F101,"ttres error setting Kanji mode","",x);
return(-1);
}
}
debug(F100,"ttres set Kanji mode ok","",0);
#endif /* sony_news */
tvtflg = 0; /* Invalidate terminal mode settings */
return(x);
}
#ifndef NOUUCP
/* T T C H K P I D -- Check lockfile pid */
/*
Read pid from lockfile named f, check that it's still valid.
If so, return 1.
On failure to read pid, return 1.
Otherwise, try to delete lockfile f and return 0 if successful, else 1.
*/
static int
ttchkpid(f) char *f; {
int pid, mypid, x;
pid = ttrpid(f); /* Read pid from file. */
if (pid > -1) { /* If we were able to read the pid.. */
debug(F101,"ttchkpid lock pid","",pid);
errno = 0; /* See if process still exists. */
mypid = (int)getpid(); /* Get my own pid. */
debug(F101,"ttchkpid my pid","",mypid);
if (pid == mypid) { /* It's me! */
x = -1; /* So I can delete it */
errno = ESRCH; /* pretend it's invalid */
} else { /* It's not me */
x = kill((PID_T)pid, 0); /* See if it's a live process */
debug(F101,"ttchkpid kill errno","",errno);
}
debug(F101,"ttchkpid pid test","",x);
if (x < 0 && errno == ESRCH) { /* pid is invalid */
debug(F111,"removing stale lock",f,pid);
if (!backgrd)
printf("Removing stale lock %s (pid %d terminated)\n", f, pid);
priv_on();
x = unlink(f); /* Remove the lockfile. */
priv_off();
debug(F111,"ttchkpid unlink",f,x);
if (x > -1)
return(0); /* Device is not locked after all */
else if (!backgrd)
perror(f);
}
return(1);
}
return(1); /* Failure to read pid */
}
#ifdef HPUX
/* Aliases (different drivers) for HP-UX dialout devices: */
static char *devprefix[] = { "tty", "ttyd", "cul", "cua", "cuad", "culd", "" };
static int ttydexists = 0;
#endif /* HPUX */
/* T T R P I D -- Read pid from lockfile "name" */
static int
ttrpid(name) char *name; {
long len;
int x, i, fd, pid, flag;
short spid;
char buf[32];
debug(F110,"ttrpid",name,0);
if (!name) return(-1);
if (!*name) return(-1);
priv_on();
len = zchki(name); /* Get file length */
priv_off();
debug(F101,"ttrpid zchki","",len);
if (len < 0)
return(-1);
if (len > 31)
return(-1);
priv_on();
fd = open(name,O_RDONLY); /* Try to open lockfile. */
priv_off();
debug(F101,"ttrpid fd","",fd);
if (fd <= 0)
return(-1);
/*
Here we try to be flexible and allow for all different binary and string
formats at runtime, rather than a specific format for each configuration
hardwired at compile time.
*/
pid = -1;
#ifndef COHERENT
/*
COHERENT uses a string PID but without leading spaces or 0's, so there is
no way to tell from the file's length whether it contains a string or binary
pid. So for COHERENT only, we only allow string pids. For all others, we
decide based on the size of the lockfile.
*/
if (len > 4) { /* If file > 4 bytes it's a string */
#endif /* COHERENT */
x = read(fd,buf,len);
debug(F111,"ttrpid string read",buf,x);
if (x < 0) {
pid = -1;
} else {
buf[31] = '\0';
x = sscanf(buf,"%d",&pid); /* Get the integer pid from it. */
}
#ifndef COHERENT
} else if (len == 4) { /* 4 bytes so binary */
x = read(fd, (char *)&pid, 4); /* Read the bytes into an int */
debug(F101,"ttrpid integer read","",x);
if (x < 4)
pid = -1;
} else if (len == 2) { /* 2 bytes binary */
x = read(fd, (char *)&spid, 2); /* Read the bytes into a short */
debug(F101,"ttrpid short read","",x);
if (x < 2)
pid = -1;
else
pid = spid;
} else
pid = -1;
#endif /* COHERENT */
close(fd); /* Close the lockfile */
debug(F101,"ttrpid pid","",pid);
return(pid);
}
#endif /* NOUUCP */
/* T T L O C K */
/*
This function attempts to coordinate use of the communication device with
other copies of Kermit and any other program that follows the UUCP
device-locking conventions, which, unfortunately, vary among different UNIX
implementations. The idea is to look for a file of a certain name, the
"lockfile", in a certain directory. If such a file is found, then the line
is presumed to be in use, and Kermit should not use it. If no such file is
found, Kermit attempts to create one so that other programs will not use the
same line at the same time. Because the lockfile and/or the directory it's
in might lack write permission for the person running Kermit, Kermit could
find itself running setuid to uucp or other user that does have the
necessary permissions. At startup, Kermit has changed its effective uid to
the user's real uid, and so ttlock() must switch back to the original
effective uid in order to create the lockfile, and then back again to the
real uid to prevent unauthorized access to other directories or files owned
by the user the program is setuid to.
Totally rewritten for C-Kermit 5A to eliminate windows of vulnerability,
based on suggestions from Warren Tucker. Call with pointer to name of
tty device. Returns:
0 on success
-1 on failure
Note: Once privileges are turned on using priv_on(), it is essential that
they are turned off again before this function returns.
*/
#ifdef SVR4 /* Lockfile uses device numbers. */
/*
Although I can't find this in writing anywhere (e.g. in SVID for SVR4),
it is the behavior of the "reference version" of SVR4, i.e. the Intel
port from UNIX Systems Laboratories, then called Univel UnixWare,
then called Novell UnixWare, now called SCO Unixware...
*/
#ifndef LFDEVNO /* Define this for SVR4 */
#ifndef AIXRS /* But not for RS/6000 AIX 3.2, etc. */
#ifndef BSD44 /* If anybody else needs it... */
#ifndef __386BSD__
#ifndef __FreeBSD__
#ifndef HPUX10
#ifndef IRIX51 /* SGI IRIX 5.1 or later */
#ifndef CK_SCOV5 /* SCO Open Server 5.0 */
#define LFDEVNO
#endif /* CK_SCOV5 */
#endif /* IRIX51 */
#endif /* HPUX10 */
#endif /* __FreeBSD__ */
#endif /* __386BSD__ */
#endif /* BSD44 */
#endif /* AIXRS */
#endif /* LFDEVNO */ /* ... define it here or on CC */
#endif /* SVR4 */ /* command line. */
#ifdef COHERENT
#define LFDEVNO
#endif /* COHERENT */
#ifdef LFDEVNO
#include <sys/stat.h> /* For major() & minor() macros. */
/* Should be in <sys/types.h>. */
#ifndef major /* If we didn't find it */
#ifdef SVR4 /* then for Sys V R4 */
#include <sys/mkdev.h> /* look here */
#else /* or for SunOS versions */
#ifdef SUNOS4 /* ... */
#include <sys/sysmacros.h> /* look here */
#else /* Otherwise take a chance: */
#define major(dev) ( (int) ( ((unsigned)(dev) >> 8) & 0xff))
#define minor(dev) ( (int) ( (dev) & 0xff))
#endif /* SUNOS4 */
#endif /* SVR4 */
#endif /* major */
#endif /* LFDEVNO */
/* No advisory locks if F_TLOCK and F_ULOCK are not defined at this point */
#ifdef LOCKF
#ifndef F_TLOCK
#undef LOCKF
#ifndef NOLOCKF
#define NOLOCKF
#endif /* NOLOCKF */
#endif /* F_TLOCK */
#endif /* LOCKF */
#ifdef LOCKF
#ifndef F_ULOCK
#undef LOCKF
#ifndef NOLOCKF
#define NOLOCKF
#endif /* NOLOCKF */
#endif /* F_ULOCK */
#endif /* LOCKF */
static int
ttlock(ttdev) char *ttdev; {
int x, n;
#ifdef NOUUCP
strcpy(flfnam,"NOLOCK");
haslock = 1;
return(0);
#else /* !NOUUCP */
#ifdef USETTYLOCK
haslock = 0; /* Not locked yet. */
*flfnam = '\0'; /* Lockfile name is empty. */
if (!strncmp(ttdev,"/dev/",5) && ttdev[5])
strcpy(lockname,ttdev+5);
else
strcpy(lockname,ttdev);
/*
This might be overkill, but it's not clear from the man pages whether
ttylock() can be called without calling ttylocked() first, since the doc
says that ttylocked() removes any stale lockfiles, but it does not say this
about ttylock(). Also the docs don't say what ttylocked() returns in the
case when it finds and removes a stale lockfile. So one or both calls to
to ttylocked() might be superfluous, but they should do no harm. Also I'm
assuming that we have to do all the same ID swapping, etc, with these
routines as we do without them. Thus the priv_on/off() sandwich.
*/
priv_on(); /* Turn on privs */
if (ttylocked(lockname)) { /* This should remove any stale lock */
if (ttylocked(lockname)) { /* so check again. */
priv_off();
return(-5); /* Still locked, fail. */
}
}
x = ttylock(lockname); /* Lock it. */
priv_off(); /* Turn off privs */
debug(F111,"ttlock lockname",lockname,x);
if (x > -1) {
/*
We don't really know the name of the lockfile, but
this is what the man page says it is. In USETTYLOCK
builds, it is used only for display by SHOW COMM.
*/
sprintf(flfnam,"/etc/locks/LCK..%s",lockname);
haslock = 1;
}
return(x);
#else /* Systems that don't have ttylock()... */
#ifndef HPUX
int lockfd; /* File descriptor for lock file. */
PID_T pid; /* Process id of this process. */
int tries; /* How many times we've tried... */
#ifdef LFDEVNO
struct stat devbuf; /* For device numbers (SVR4). */
#endif /* LFDEVNO */
#ifdef PIDSTRING
char pid_str[12]; /* My pid in string format. */
#endif /* PIDSTRING */
char *device, *devname;
#define LFNAML 50 /* Max length for lock file name. */
char lockfil[LFNAML]; /* Lock file name */
#ifdef RTAIX
char lklockf[LFNAML]; /* Name for link to lock file */
#endif /* RTAIX */
char tmpnam[LFNAML+30]; /* Temporary lockfile name. */
char *lockdir = LOCK_DIR; /* Defined near top of this file, */
/* or on cc command line. */
haslock = 0; /* Not locked yet. */
*flfnam = '\0'; /* Lockfile name is empty. */
pid = getpid(); /* Get id of this process. */
/* Construct name of lockfile and temporary file */
/* device = name of tty device without the path, e.g. "ttyh8" */
/* lockfil = name of lock file, without path, e.g. "LCK..ttyh8" */
device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
#ifdef ISIII /* Interactive System III, PC/IX */
strcpy(lockfil, device);
#else
#ifdef LFDEVNO /* Lockfilename has device numbers. */
if (stat(ttdev,&devbuf) < 0)
return(-1);
#ifdef COHERENT
sprintf(lockfil,"LCK..%d.%d",
major(devbuf.st_rdev), /* major device number */
0x1f & minor(devbuf.st_rdev)); /* minor device number */
#else
sprintf(lockfil,"LK.%03d.%03d.%03d",
major(devbuf.st_dev), /* inode */
major(devbuf.st_rdev), /* major device number */
minor(devbuf.st_rdev)); /* minor device number */
#endif /* COHERENT */
#else /* Others... */
#ifdef PTX /* Dynix PTX */
if (device != &ttdev[5] && strncmp(ttdev,"/dev/",5)==0) {
sprintf(lockfil,"LCK..%.3s%s", &ttdev[5], device);
} else
#endif /* PTX */
sprintf(lockfil,"LCK..%s", device);
#ifdef RTAIX
strcpy(lklockf,device);
#endif /* RTAIX */
#endif /* LFDEVNO */
#endif /* ISIII */
#ifdef CK_SCOV5 /* SCO Open Server 5.0 */
{
/* Lowercase the entire filename. */
/* SCO says we must do this in V5.0 and later. */
/* BUT... watch out for devices -- like Digiboard Portserver */
/* That can have hundreds of ports... */
char *p = (char *)(lockfil + 5);
while (*p) { if (isupper(*p)) *p = (char) tolower(*p); p++; }
}
#else
#ifdef M_XENIX /* SCO Xenix */
{
int x; char c;
x = (int)strlen(lockfil) - 1; /* Get last letter of device name. */
if (x > 0) { /* If it's uppercase, lower it. */
c = lockfil[x];
if (c >= 'A' && c <= 'Z') lockfil[x] += ('a' - 'A');
}
}
#endif /* M_XENIX */
#endif /* CK_SCOV5 */
/* flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..ttyh8" */
/* tmpnam = temporary unique, e.g. "/usr/spool/uucp/LTMP..pid" */
sprintf(flfnam,"%s/%s",lockdir,lockfil);
#ifdef RTAIX
sprintf(lkflfn,"%s/%s",lockdir,lklockf);
#endif /* RTAIX */
sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid);
debug(F110,"ttlock flfnam",flfnam,0);
debug(F110,"ttlock tmpnam",tmpnam,0);
priv_on(); /* Turn on privileges if possible. */
lockfd = creat(tmpnam, 0444); /* Try to create temp lock file. */
if (lockfd < 0) { /* Create failed. */
debug(F111,"ttlock creat failed",tmpnam,errno);
if (errno == ENOENT) {
perror(lockdir);
printf("UUCP not installed or Kermit misconfigured\n");
} else {
perror(lockdir);
unlink(tmpnam); /* Get rid of the temporary file. */
}
priv_off(); /* Turn off privileges!!! */
return(-1); /* Return failure code. */
}
/* Now write the pid into the temp lockfile in the appropriate format */
#ifdef PIDSTRING /* For Honey DanBer UUCP, */
sprintf( /* write PID as decimal string */
pid_str,
#ifdef LINUXFSSTND /* The "Linux File System Standard" */
#ifdef FSSTND10 /* Version 1.0 calls for */
"%010d\n", /* leading zeros */
#else /* while version 1.2 calls for */
"%10d\n", /* leading spaces */
#endif /* FSSTND10 */
#else
#ifdef COHERENT
"%d\n", /* with leading nothing */
#else
"%10d\n", /* with leading blanks */
#endif /* COHERENT */
#endif /* LINUXFSSTND */
(int) pid
);
write(lockfd, pid_str, 11);
debug(F111,"ttlock hdb pid string",pid_str,(int) pid);
#else /* Not PIDSTRING, use integer PID */
write(lockfd, (char *)&pid, sizeof(pid) );
debug(F101,"ttlock pid","",(int) pid);
#endif /* PIDSTRING */
/* Now try to rename the temp file to the real lock file name. */
/* This will fail if a lock file of that name already exists. */
close(lockfd); /* Close the temp lockfile. */
chmod(tmpnam,0444); /* Permission for a valid lock. */
tries = 0;
while (!haslock && tries++ < 2) {
haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
if (haslock) { /* If we got the lockfile */
#ifdef RTAIX
link(flfnam,lkflfn);
#endif /* RTAIX */
#ifdef LOCKF
/*
Advisory file locking works on SVR4, so we use it. In fact, it is
necessary in some cases, e.g. when SLIP is involved. But it still doesn't
seem prevent multiple users accessing the same device by different names.
*/
while (lockf(ttyfd, F_TLOCK, 0L) != 0) {
debug(F111, "ttlock: lockf returns errno", "", errno);
if ((++tries >= 3) || (errno != EAGAIN)) {
x = unlink(flfnam); /* remove the lockfile */
debug(F111,"ttlock unlink",flfnam,x);
haslock = 0;
break;
}
sleep(2);
}
if (haslock) /* If we got an advisory lock */
#endif /* LOCKF */
break; /* We're done. */
} else { /* We didn't create a new lockfile. */
if (ttchkpid(flfnam)) { /* Check existing lockfile */
unlink(tmpnam); /* Delete the tempfile */
debug(F100,"ttlock found tty locked","",0);
return(-2); /* Code for device is in use. */
}
}
}
unlink(tmpnam); /* Unlink (remove) the temp file. */
priv_off(); /* Turn off privs */
return(haslock ? 0 : -1); /* Return link's return code. */
#else /* HPUX */
/*
HP-UX gets its own copy of this routine, modeled after the observed behavior
of the HP-UX 'cu' program. HP-UX serial device names consist of a base name
such as "tty", "ttyd", "cua", "cul", "cuad", or "culd", followed by a unit
designator which is a string of digits, possibly containing an imbedded
letter "p". Examples (for base name "tty"):
/dev/tty0, /dev/tty00, dev/ttyd00, /dev/tty0p0
According to the HP-UX UUCP manual of 1988, the "0p0" notation has been
used on Series 800 since HP-UX 2.00, and the "non-p" notation was used
on other models. In HP-UX 10.00, "0p0" notation was adopted for all models.
However, we make and enforce no such distinctions; either notation is
accepted on any model or HP-UX version as a valid unit designator.
If a valid unit is specified (as opposed to a designer name or symlink), we
check for all aliases of the given unit according to the devprefix[] array.
If no lockfiles are found for the given unit, we can have the device; we
create a lockfile LCK..name in the lockfile directory appropriate for the
HP-UX version (/var/spool/locks for 10.00 and later, /usr/spool/uucp for
9.xx and earlier). If it is a "cua" or "cul" device, a second lockfile is
created with the "ttyd" prefix. This is exactly what cu does.
If the "set line" device does not have a valid unit designator, then it is
used literally and no synomyms are searched for and only one lockfile is
created.
-fdc, March 1998.
*/
#define LFNAML 80 /* Max length for lock file name. */
int lockfd; /* File descriptor for lock file. */
PID_T pid; /* Process ID of this process. */
int fpid; /* pid found in existing lockfile. */
int tries; /* How many times we've tried... */
int i, k; /* Workers */
char *device, *devname; /* "/dev/xxx", "xxx" */
char *unit, *p; /* <instance>p<port> part of xxx */
char lockfil[LFNAML]; /* Lockfile name (no path) */
char tmpnam[LFNAML]; /* Temporary lockfile name. */
#ifdef HPUX10 /* Lockfile directory */
char *lockdir = "/var/spool/locks"; /* Always this for 10.00 and higher */
#else /* HP-UX 9.xx and below */
#ifdef LOCK_DIR
char *lockdir = LOCK_DIR; /* Defined near top of this file */
#else
char *lockdir = "/usr/spool/uucp"; /* or not... */
#endif /* LOCK_DIR */
#endif /* HPUX10 */
haslock = 0; /* Not locked yet. */
*flfnam = '\0'; /* Lockfile name is empty. */
lock2[0] = '\0'; /* Second one too. */
pid = getpid(); /* Get my process ID */
/*
Construct name of lockfile and temporary file...
device = name of tty device without the path, e.g. "tty0p0"
lockfil = name of lock file, without path, e.g. "LCK..tty0p0"
*/
device = ((devname = xxlast(ttdev,'/')) != NULL ? devname+1 : ttdev);
debug(F110,"TTLOCK device",device,0);
sprintf(lockfil,"LCK..%s", device);
k = 0; /* Assume device is not locked */
n = 0; /* Digit counter */
unit = device; /* Unit = <instance>p<port> */
while (*unit && !isdigit(*unit)) /* Search for digit... */
unit++;
p = unit; /* Verify <num>p<num> format... */
debug(F110,"TTLOCK unit 1",unit,0);
/*
The unit number is recognized as:
(a) any sequence of digits that runs to the end of the string.
(b) any (a) that includes one and only one letter "p", with at least
one digit before and after it.
*/
while (isdigit(*p)) p++, n++; /* Get a run of digits */
if (*p && n > 0) { /* Have a "p"? */
if (*p == 'p' && isdigit(*(p+1))) {
p++;
n = 0;
while (isdigit(*p)) p++, n++;
}
}
if (n == 0 || *p) unit = "";
debug(F110,"TTLOCK unit 2",unit,0);
if (*unit) { /* Device name has unit number. */
/* The following loop not only searches for the various lockfile */
/* synonyms, but also removes all -- not just one -- stale lockfile */
/* for the device, should there be more than one. See ttchkpid(). */
ttydexists = 0;
for (i = 0; *devprefix[i]; i++) { /* For each driver... */
/* Make device name */
sprintf(lock2,"/dev/%s%s",devprefix[i],unit);
priv_on(); /* Privs on */
k = zchki(lock2) != -1; /* See if device exists */
priv_off(); /* Privs off */
debug(F111,"TTLOCK exist",lock2,k);
if (k) {
if (!strcmp(devprefix[i],"ttyd")) /* ttyd device exists */
ttydexists = 1;
/* Make lockfile name */
sprintf(lock2,"%s/LCK..%s%s",lockdir,devprefix[i],unit);
debug(F110,"TTLOCK checking",lock2,0);
priv_on(); /* Privs on */
k = zchki(lock2) != -1; /* See if lockfile exists */
priv_off(); /* Privs off */
debug(F111,"TTLOCK check for lock A",lock2,k);
if (k) if (ttchkpid(lock2)) { /* If pid still active, fail. */
strcpy(flfnam,lock2);
return(-2);
}
}
}
} else { /* Some other device-name format */
/* This takes care of symbolic links, etc... */
/* But does not chase them down! */
sprintf(lock2,"%s/LCK..%s",lockdir,device); /* Use the name as-is */
priv_on();
k = zchki(lock2) != -1; /* Check for existing lockfile */
priv_off();
debug(F111,"TTLOCK check for lock B",lock2,k);
if (k) if (ttchkpid(lock2)) { /* Check pid from lockfile */
strcpy(flfnam,lock2);
debug(F110,"TTLOCK in use",device,0);
debug(F101,"TTLOCK returns","",-2);
return(-2);
}
}
/*
Get here only if there is no (more) lockfile, so now we make one (or two)...
flfnam = full lockfile pathname, e.g. "/usr/spool/uucp/LCK..cul0p0".
tmpnam = unique temporary filname, e.g. "/usr/spool/uucp/LTMP..pid".
*/
sprintf(flfnam,"%s/%s",lockdir,lockfil); /* Our SET LINE device */
/* If dialout device, also make one for corresponding dialin device */
lock2[0] = '\0';
if (!strncmp(device,"cu",2) && *unit && ttydexists)
sprintf(lock2, "%s/LCK..ttyd%s", lockdir, unit);
sprintf(tmpnam,"%s/LTMP.%05d",lockdir,(int) pid); /* Make temporary name */
#ifdef DEBUG
if (deblog) {
debug(F110,"TTLOCK flfnam",flfnam,0);
debug(F110,"TTLOCK lock2",lock2,0);
debug(F110,"TTLOCK tmpnam",tmpnam,0);
}
#endif /* DEBUG */
/*
Lockfile permissions...
444 is standard, HP-UX 10.00 uses 664. It doesn't matter.
Kermit uses 444; the difference lets us tell whether Kermit created
the lock file.
*/
priv_on(); /* Turn on privileges. */
lockfd = creat(tmpnam, 0444); /* Try to create temporary file. */
if (lockfd < 0) { /* Create failed. */
debug(F111,"TTLOCK creat failed",tmpnam,errno);
if (errno == ENOENT) {
perror(lockdir);
printf("UUCP not installed or Kermit misconfigured\n");
} else {
perror(lockdir);
unlink(tmpnam); /* Get rid of the temporary file. */
}
priv_off(); /* Turn off privileges!!! */
debug(F101,"TTLOCK returns","",-1);
return(-1); /* Return failure code. */
}
debug(F110,"TTLOCK temp ok",tmpnam,0);
/* Now write our pid into the temp lockfile in integer format. */
i = write(lockfd, (char *)&pid, sizeof(pid));
#ifdef DEBUG
if (deblog) {
debug(F101,"TTLOCK pid","",pid);
debug(F101,"TTLOCK sizeof pid","",sizeof(pid));
debug(F101,"TTLOCK write pid returns","",i);
}
#endif /* DEBUG */
/*
Now try to rename the temporary file to the real lockfile name.
This will fail if a lock file of that name already exists, which
will catch race conditions with other users.
*/
close(lockfd); /* Close the temp lockfile. */
chmod(tmpnam,0444);
tries = 0;
while (!haslock && tries++ < 2) {
haslock = (link(tmpnam,flfnam) == 0); /* Create a link to it. */
debug(F101,"TTLOCK link","",haslock);
if (haslock) { /* If we made the lockfile... */
#ifdef LOCKF /* Can be canceled with -DNOLOCKF */
/*
Create an advisory lock on the device through its file descriptor.
This code actually seems to work. If it is executed, and then another
process tries to open the same device under a different name to circumvent
the lockfile, they get a "device busy" error.
*/
debug(F100,"TTLOCK LOCKF code...","",0);
while ( lockf(ttyfd, F_TLOCK, 0L) != 0 ) {
debug(F111, "TTLOCK lockf error", "", errno);
if ((++tries >= 3) || (errno != EAGAIN)) {
x = unlink(flfnam); /* Remove the lockfile */
if (errno == EACCES)
printf("Device already locked by another process\n");
haslock = 0;
break;
}
sleep(2);
}
#endif /* LOCKF */
if (haslock) { /* If we made the lockfile ... */
if (lock2[0]) { /* if there is to be a 2nd lockfile */
lockfd = creat(lock2, 0444); /* Create it */
debug(F111,"TTLOCK lock2 creat", lock2, lockfd);
if (lockfd > -1) { /* Created OK, write pid. */
write(lockfd, (char *)&pid, sizeof(pid) );
close(lockfd); /* Close and */
chmod(lock2, 0444); /* set permissions. */
} else { /* Not OK, but don't fail. */
lock2[0] = '\0'; /* Just remember it's not there. */
}
}
break; /* and we're done. */
}
}
}
unlink(tmpnam); /* Unlink (remove) the temp file. */
priv_off(); /* Turn off privs */
i = haslock ? 0 : -1; /* Our return value */
debug(F101,"TTLOCK returns","",i);
return(i);
#endif /* HPUX */
#endif /* USETTYLOCK */
#endif /* !NOUUCP */
}
/* T T U N L O C K */
static int
ttunlck() { /* Remove UUCP lockfile(s). */
#ifndef NOUUCP
int x;
#ifdef USETTYLOCK
if (haslock && *flfnam) {
int x;
priv_on(); /* Turn on privs */
x = ttyunlock(lockname); /* Try to unlock */
priv_off(); /* Turn off privs */
if (x < 0)
printf("Warning - Can't remove lockfile: %s\n", flfnam);
*flfnam = '\0'; /* Erase the name. */
haslock = 0;
return(0);
}
#else /* No ttylock()... */
if (haslock && *flfnam) {
/* Don't remove lockfile if we didn't make it ourselves */
if ((x = ttrpid(flfnam)) != (int)getpid()) {
debug(F111,"ttunlck lockfile seized",flfnam,x);
printf("Warning - Lockfile %s seized by pid %d\n",
flfnam,
x
);
return(0);
}
priv_on(); /* Turn privileges on. */
errno = 0;
x = unlink(flfnam); /* Remove the lockfile. */
debug(F111,"ttunlck unlink",flfnam,x);
if (x < 0) {
if (errno)
perror(ttnmsv);
printf("Warning - Can't remove lockfile: %s\n", flfnam);
}
haslock = 0;
*flfnam = '\0'; /* Erase the name. */
#ifdef RTAIX
errno = 0;
x = unlink(lkflfn); /* Remove link to lockfile */
debug(F111,"ttunlck AIX link unlink",lkflfn,x);
if (x < 0) {
if (errno)
perror(ttnmsv);
printf("Warning - Can't remove link to lockfile: %s\n", lkflfn);
}
*lkflfn = '\0';
#else
#ifdef HPUX
if (lock2[0]) { /* If there is a second lockfile, */
errno = 0;
x = unlink(lock2); /* remove it too. */
debug(F111,"ttunlck lock2 unlink",lock2,x);
if (x < 0) {
if (errno)
perror(ttnmsv);
printf("Warning - Can't remove secondary lockfile: %s\n",
lock2);
}
lock2[0] = '\0'; /* Forget its name. */
}
#endif /* HPUX */
#endif /* RTAIX */
#ifdef LOCKF
(VOID) lockf(ttyfd, F_ULOCK, 0L); /* Remove advisory lock */
#endif /* LOCKF */
priv_off(); /* Turn privileges off. */
}
#endif /* USETTYLOCK */
#endif /* !NOUUCP */
return(0);
}
/*
4.3BSD-style UUCP line direction control.
(Stan Barber, Rice U, 1980-something...)
*/
#ifndef NOUUCP
#ifdef ACUCNTRL
VOID
acucntrl(flag,ttname) char *flag, *ttname; {
char x[DEVNAMLEN+32], *device, *devname;
if (strcmp(ttname,CTTNAM) == 0 || xlocal == 0) /* If not local, */
return; /* just return. */
device = ((devname = xxlast(ttname,'/')) != NULL ? devname+1 : ttname);
if (strncmp(device,"LCK..",4) == 0) device += 5;
sprintf(x,"/usr/lib/uucp/acucntrl %s %s",flag,device);
debug(F110,"called ",x,0);
zsyscmd(x);
}
#endif /* ACUCNTRL */
#endif /* NOUUCP */
/*
T T H F L O W -- Set or Reset hardware flow control.
This is an attempt to collect all hardware-flow-control related code
into a single module. Thanks to Rick Sladkey and John Kohl for lots of
help here. Overview:
Hardware flow control is not supported in many UNIX implementions. Even
when it is supported, there is no (ha ha) "standard" for the programming
interface. In general, 4.3BSD and earlier (sometimes), 4.4BSD, System V,
SunOS, AIX, etc, have totally different methods. (And, not strictly
relevant here, the programming interface often brings one only to a no-op
in the device driver!)
Among all these, we have two major types of APIs: those in which hardware
flow control is determined by bits in the same termio/termios/sgtty mode
word(s) that are used for controlling such items as CBREAK vs RAW mode, and
which are also used by the ttvt(), ttpkt(), conbin(), and concb() routines
for changing terminal modes. And those that use entirely different
mechanisms.
In the first category, it is important that any change in the mode bits be
reflected in the relevant termio(s)/sgtty structure, so that subsequent
changes to that structure do not wipe out the effects of this routine. That
is why a pointer, attrs, to the appropriate structure is passed as a
parameter to this routine.
The second category should give us no worries, since any changes to hardware
flow control accomplished by this routine should not affect the termio(s)/
sgtty structures, and therefore will not be undone by later changes to them.
The second argument, status, means to turn on hardware flow control if
nonzero, and to turn it off if zero.
Returns: 0 on success, -1 on failure.
*/
static int
tthflow(flow, status, attrs)
int flow, /* Type of flow control (ckcdeb.h) */
status; /* Nonzero = turn it on */
/* Zero = turn it off */
#ifdef BSD44ORPOSIX /* POSIX or BSD44 */
struct termios *attrs;
#else /* System V */
#ifdef ATTSV
#ifdef ATT7300
#ifdef UNIX351M
/* AT&T UNIX 3.51m can set but not test for hardware flow control */
#define RTSFLOW CTSCD
#define CTSFLOW CTSCD
#endif /* ATT7300 */
#endif /* UNIX351M */
struct termio *attrs;
#else /* BSD, V7, etc */
struct sgttyb *attrs; /* sgtty info... */
#endif /* ATTSV */
#endif /* BSD44ORPOSIX */
/* tthflow */ {
int x = 0; /* tthflow() return code */
#ifdef Plan9
return p9tthflow(flow, status);
#else
#ifndef OXOS /* NOT Olivetti X/OS... */
/*
For SunOS 4.0 and later in the BSD environment ...
The declarations are copied and interpreted from the System V header files,
so we don't actually have to pull in all the System V junk when building
C-Kermit for SunOS in the BSD environment, which would be dangerous because
having those symbols defined would cause us to take the wrong paths through
the code. The code in this section is used in both the BSD and Sys V SunOS
versions.
*/
#ifdef SUNOS41
/*
In SunOS 4.1 and later, we use the POSIX calls rather than ioctl calls
because GNU CC uses different formats for the _IOxxx macros than regular CC;
the POSIX forms work for both. But the POSIX calls are not available in
SunOS 4.0.
*/
#define CRTSCTS 0x80000000 /* RTS/CTS flow control */
#define TCSANOW 0 /* Do it now */
struct termios {
unsigned long c_iflag; /* Input modes */
unsigned long c_oflag; /* Output modes */
unsigned long c_cflag; /* Control modes */
unsigned long c_lflag; /* Line discipline modes */
char c_line;
CHAR c_cc[17];
};
struct termios temp;
_PROTOTYP( int tcgetattr, (int, struct termios *) );
_PROTOTYP( int tcsetattr, (int, int, struct termios *) );
/*
When CRTSCTS is set, SunOS won't do output unless both CTS and CD are
asserted. So we don't set CRTSCTS unless CD is up. This should be OK,
since we don't need RTS/CTS during dialing, and after dialing is complete,
we should have CD. If not, we still communicate, but without RTS/CTS.
*/
int mflags; /* Modem signal flags */
if (ttpipe) return(0);
debug(F101,"ttyflow entry status","",status);
if (!status) { /* Turn hard flow off */
if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
(temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */
x = tcsetattr(ttyfd,TCSANOW,&temp);
}
} else { /* Turn hard flow on */
if (ioctl(ttyfd,TIOCMGET,&mflags) > -1 && /* Get modem signals */
(mflags & TIOCM_CAR)) { /* Check for CD */
debug(F100,"tthflow SunOS has CD","",0);
if (tcgetattr(ttyfd, &temp) > -1 && /* Get device attributes */
!(temp.c_cflag & CRTSCTS)) { /* Check for RTS/CTS */
temp.c_cflag |= CRTSCTS; /* Not there, add it */
x = tcsetattr(ttyfd,TCSANOW,&temp);
}
} else {
x = -1;
debug(F100,"tthflow SunOS no CD","",0);
}
}
#else
#ifdef QNX
struct termios temp;
if (ttpipe) return(0);
debug(F101,"ttyflow entry status","",status);
if (tcgetattr(ttyfd, &temp) > -1) { /* Get device attributes */
if (!status) { /* Turn hard flow off */
if ((temp.c_cflag & (IHFLOW|OHFLOW)) == (IHFLOW|OHFLOW)) {
temp.c_cflag &= ~(IHFLOW|OHFLOW); /* It's there, remove it */
attrs->c_cflag &= ~(IHFLOW|OHFLOW);
x = tcsetattr(ttyfd,TCSANOW,&temp);
}
} else { /* Turn hard flow on */
if ((temp.c_cflag & (IHFLOW|OHFLOW)) != (IHFLOW|OHFLOW)) {
temp.c_cflag |= (IHFLOW|OHFLOW); /* Not there, add it */
temp.c_iflag &= ~(IXON|IXOFF); /* Bye to IXON/IXOFF */
ttraw.c_lflag |= IEXTEN; /* Must be on */
x = tcsetattr(ttyfd,TCSANOW,&temp);
attrs->c_cflag |= (IHFLOW|OHFLOW);
attrs->c_iflag &= ~(IXON|IXOFF);
}
}
} else {
x = -1;
debug(F100, "tthflow QNX getattr fails", "", 0);
}
#else
#ifdef POSIX_CRTSCTS
/*
POSIX_CRTSCTS is defined in ckcdeb.h or on CC command line.
Note: Do not assume CRTSCTS is a one-bit field!
*/
struct termios temp;
if (ttpipe) return(0);
debug(F101,"ttyflow POSIX_CRTSCTS entry status","",status);
if (tcgetattr(ttyfd, &temp) > -1) { /* Get device attributes */
if (!status) { /* Turn hard flow off */
if ((temp.c_cflag & CRTSCTS) == CRTSCTS) { /* Check for RTS/CTS */
temp.c_cflag &= ~CRTSCTS; /* It's there, remove it */
attrs->c_cflag &= ~CRTSCTS;
x = tcsetattr(ttyfd,TCSANOW,&temp);
debug(F100,"tthflow off","",x);
}
} else { /* Turn hard flow on */
if ((temp.c_cflag & CRTSCTS) != CRTSCTS) {
temp.c_cflag |= CRTSCTS; /* Not there, add it */
temp.c_iflag &= ~(IXON|IXOFF|IXANY); /* Bye to IXON/IXOFF */
x = tcsetattr(ttyfd,TCSANOW,&temp);
debug(F100,"tthflow on","",x);
attrs->c_cflag |= CRTSCTS;
attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
}
}
} else {
x = -1;
debug(F100, "tthflow POSIX_CRTSCTS getattr failed", "", 0);
}
#else
#ifdef SUNOS4
/*
SunOS 4.0 (and maybe earlier?). This code is dangerous because it
prevents compilation with GNU gcc, which uses different formats for the
_IORxxx macros than regular cc. SunOS 4.1 and later can use the POSIX
routines above, which work for both cc and gcc.
*/
#define TCGETS _IOR(T, 8, struct termios) /* Get modes into termios struct */
#define TCSETS _IOW(T, 9, struct termios) /* Set modes from termios struct */
#define CRTSCTS 0x80000000 /* RTS/CTS flow control */
struct termios {
unsigned long c_iflag; /* Input modes */
unsigned long c_oflag; /* Output modes */
unsigned long c_cflag; /* Control modes */
unsigned long c_lflag; /* Line discipline modes */
char c_line;
CHAR c_cc[17];
};
struct termios temp;
if (ttpipe) return(0);
debug(F101,"ttyflow entry status","",status);
if (ioctl(ttyfd,TCGETS,&temp) > -1) { /* Get terminal modes. */
if (status) { /* Turn hard flow on */
temp.c_cflag |= CRTSCTS; /* Add RTS/CTS to them. */
x = ioctl(ttyfd,TCSETS,&temp); /* Set them again. */
attrs->c_cflag |= CRTSCTS; /* Add to global info. */
} else { /* Turn hard flow off */
temp.c_cflag &= ~CRTSCTS;
x = ioctl(ttyfd,TCSETS,&temp);
attrs->c_cflag &= ~CRTSCTS;
}
}
#else /* Not SunOS 4.0 or later */
#ifdef AIXRS /* IBM AIX RS/6000 */
#ifndef AIX41 /* But only pre-4.x == SVR4 */
if (ttpipe) return(0);
if (status) {
if ((x = ioctl(ttyfd, TXADDCD, "rts")) < 0 && errno != EBUSY)
debug(F100,"hardflow TXADDCD (rts) error", "", 0);
} else {
if ((x = ioctl(ttyfd, TXDELCD, "rts")) < 0 && errno != EINVAL)
debug(F100,"hardflow TXDELCD (rts) error", "", 0);
}
#endif /* AIX41 */
#else /* Not AIX RS/6000 */
#ifdef ATTSV /* System V... */
#ifdef CK_SCOV5 /* SCO Open Server 5.0 */
#define CK_SCOUNIX
#else
#ifdef M_UNIX /* SCO UNIX 3.2v4.x or earlier */
#define CK_SCOUNIX
#endif /* M_UNIX */
#endif /* CK_SCOV5 */
#ifdef SCO_FORCE_RTSXOFF
#ifdef CK_SCOUNIX /* But not SCO OpenServer 5.0.4 */
#ifdef SCO_OSR504 /* or later... */
#undef CK_SCOUNIX
#endif /* SCO_OSR504 */
#endif /* CK_SCOUNIX */
#endif /* SCO_FORCE_RTSXOFF */
#ifdef CK_SCOUNIX
#ifdef POSIX
struct termios temp;
if (ttpipe) return(0);
debug(F101,"ttyflow entry status","",status);
x = tcgetattr(ttyfd, &temp);
debug(F101,"tthflow SCO POSIX tcgetattr","",x);
#else /* POSIX */
struct termio temp;
if (ttpipe) return(0);
debug(F101,"ttyflow entry status","",status);
x = ioctl(ttyfd, TCGETA, &temp);
debug(F101,"tthflow SCO UNIX TCGETA","",x);
#endif /* POSIX */
/*
This is not really POSIX, since POSIX does not deal with hardware flow
control, but we are using the POSIX APIs. In fact, RTSFLOW and CTSFLOW
are defined in termio.h, but within #ifndef _POSIX_SOURCE..#endif. So
let's try forcing their definitions here.
*/
#ifndef CTSFLOW
#define CTSFLOW 0020000
debug(F101,"tthflow SCO defining CTSFLOW","",CTSFLOW);
#else
debug(F101,"tthflow SCO CTSFLOW","",CTSFLOW);
#endif /* CTSFLOW */
#ifndef RTSFLOW
#define RTSFLOW 0040000
debug(F101,"tthflow SCO defining RTSFLOW","",RTSFLOW);
#else
debug(F101,"tthflow SCO RTSFLOW","",RTSFLOW);
#endif /* RTSFLOW */
#ifndef ORTSFL
#define ORTSFL 0100000
debug(F101,"tthflow SCO defining ORTSFL","",ORTSFL);
#else
debug(F101,"tthflow SCO ORTSFL","",ORTSFL);
#endif /* ORTSFL */
if (x != -1) {
if (status) { /* Turn it ON */
temp.c_cflag |= RTSFLOW|CTSFLOW;
attrs->c_cflag |= RTSFLOW|CTSFLOW;
#ifdef ORTSFL
temp.c_cflag &= ~ORTSFL;
attrs->c_cflag &= ~ORTSFL;
#endif /* ORTSFL */
temp.c_iflag &= ~(IXON|IXOFF|IXANY);
attrs->c_iflag &= ~(IXON|IXOFF|IXANY);
} else { /* Turn it OFF */
#ifdef ORTSFL
temp.c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
attrs->c_cflag &= ~(RTSFLOW|CTSFLOW|ORTSFL);
#else /* ORTSFL */
temp.c_cflag &= ~(RTSFLOW|CTSFLOW);
attrs->c_cflag &= ~(RTSFLOW|CTSFLOW);
#endif /* ORTSFL */
}
#ifdef POSIX
x = tcsetattr(ttyfd, TCSADRAIN, &temp);
#else
x = ioctl(ttyfd, TCSETA, &temp);
#endif /* POSIX */
debug(F101,"tthflow SCO set modes","",x);
}
#else /* Not SCO UNIX */
if (ttpipe) return(0);
if (!status) { /* Turn it OFF */
#ifdef RTSXOFF
debug(F100,"tthflow ATTSV RTS/CTS OFF","",0);
rctsx.x_hflag &= ~(RTSXOFF|CTSXON);
#ifdef TCSETX
x = ioctl(ttyfd,TCSETX,&rctsx);
debug(F101,"tthflow ATTSV TCSETX OFF","",x);
#else
x = -1
debug(F100,"tthflow TCSETX not defined","",0);
#endif /* TCSETX */
#else
debug(F100,"tthflow ATTSV RTSXOFF not defined","",0);
#endif /* RTSXOFF */
#ifdef DTRXOFF
debug(F100,"tthflow ATTSV DTR/CD OFF","",0);
rctsx.x_hflag &= ~(DTRXOFF|CDXON);
x = ioctl(ttyfd,TCSETX,&rctsx);
debug(F101,"tthflow ATTSV DTRXOFF OFF","",x);
#else
debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
#endif /* DTRXOFF */
} else { /* Turn it ON. */
if (flow == FLO_RTSC) { /* RTS/CTS Flow control... */
debug(F100,"tthflow ATTSV RTS/CTS ON","",0);
#ifdef RTSXOFF
/* This is the preferred way, according to SVID3 */
#ifdef TCGETX
x = ioctl(ttyfd,TCGETX,&rctsx);
debug(F101,"tthflow TCGETX","",x);
if (x > -1) {
rctsx.x_hflag |= RTSXOFF | CTSXON;
x = ioctl(ttyfd,TCSETX,&rctsx);
debug(F100,"tthflow ATTSV ioctl","",x);
}
#else
debug(F100,"tthflow TCGETX not defined","",0);
x = -1
#endif /* TCGETX */
#else
debug(F100,"tthflow RTSXOFF not defined","",0);
x = -1;
#endif /* RTSXOFF */
} else if (flow == FLO_DTRC) { /* DTR/CD Flow control... */
debug(F100,"tthflow ATTSV DTR/CD ON","",0);
#ifdef DTRXOFF
/* This is straight out of SVID R4 */
if (ioctl(ttyfd,TCGETX,&rctsx) > -1) {
rctsx.x_hflag &= ~(DTRXOFF|CDXON);
x = ioctl(ttyfd,TCSETX,&rctsx);
}
#else
debug(F100,"tthflow ATTSV DTRXOFF not defined","",0);
x = -1;
#endif /* DTRXOFF */
}
}
#endif /* CK_SCOUNIX */
#else /* not System V... */
#ifdef CK_DTRCTS
#ifdef LDODTR
#ifdef LDOCTS
if (ttpipe) return(0);
x = LDODTR | LDOCTS; /* Found only on UTEK? */
if (flow == FLO_DTRT && status) { /* Use hardware flow control */
if (lmodef) {
x = ioctl(ttyfd,TIOCLBIS,&x);
if (x < 0) {
debug(F100,"hardflow TIOCLBIS error","",0);
} else {
lmodef++;
debug(F100,"hardflow TIOCLBIS ok","",0);
}
}
} else {
if (lmodef) {
x = ioctl(ttyfd,TIOCLBIC,&x);
if (x < 0) {
debug(F100,"hardflow TIOCLBIC error","",0);
} else {
lmodef++;
debug(F100,"hardflow TIOCLBIC ok","",0);
}
}
}
#endif /* LDODTR */
#endif /* LDOCTS */
#endif /* CK_DTRCTS */
#endif /* ATTSV */
#endif /* AIXRS */
#endif /* SUNOS4 */
#endif /* QNX */
#endif /* POSIX_CRTSCTS */
#endif /* SUNOS41 */
#else /* OXOS */
struct termios temp; /* Olivetti X/OS ... */
if (ttpipe) return(0);
x = ioctl(ttyfd,TCGETS,&temp);
if (x == 0) {
temp.c_cflag &= ~(CRTSCTS|CDTRCTS|CBRKFLOW|CDTRDSR|CRTSDSR);
if (status) {
switch (flow) {
case FLO_RTSC: temp.c_cflag |= CRTSCTS; /* RTS/CTS (hard) */
break;
case FLO_DTRT: temp.c_cflag |= CDTRCTS; /* DTR/CTS (hard) */
break;
}
}
x = ioctl(ttyfd,TCSETS,&temp);
}
#endif /* OXOS */
return(x);
#endif /* Plan9 */
}
/* T T P K T -- Condition the communication line for packets */
/* or for modem dialing */
/*
If called with speed > -1, also set the speed.
Returns 0 on success, -1 on failure.
NOTE: the "xflow" parameter is supposed to be the currently selected
type of flow control, but for historical reasons, this parameter is also
used to indicate that we are dialing. Therefore, when the true flow
control setting is needed, we access the external variable "flow", rather
than trusting our "xflow" argument.
*/
int
#ifdef CK_ANSIC
ttpkt(long speed, int xflow, int parity)
#else
ttpkt(speed,xflow,parity) long speed; int xflow, parity;
#endif /* CK_ANSIC */
/* ttpkt */ {
#ifndef NOLOCAL
int s2;
int s = -1;
#endif /* NOLOCAL */
#ifndef SVORPOSIX
int x;
#endif /* SVORPOSIX */
extern int flow; /* REAL flow-control setting */
if (ttyfd < 0) return(-1); /* Not open. */
debug(F101,"ttpkt parity","",parity);
debug(F101,"ttpkt xflow","",xflow);
debug(F101,"ttpkt speed","",(int) speed);
ttprty = parity; /* Let other tt functions see these. */
ttspeed = speed; /* Make global copy for this module */
ttpmsk = ttprty ? 0177 : 0377; /* Parity stripping mask */
debug(F101,"ttpkt ttpmsk","",ttpmsk);
debug(F101,"ttpkt netconn","",netconn);
needpchk = 1; /* Need parity check */
#ifdef NETCONN /* No mode-changing for telnet */
if (netconn) {
#ifdef TCPSOCKET
#ifdef TCP_NODELAY
if (ttnet == NET_TCPB) { /* But turn off Nagle */
extern int tcp_nodelay;
nodelay_sav = tcp_nodelay;
no_delay(1);
}
#endif /* TCP_NODELAY */
#endif /* TCPSOCKET */
return(0);
}
#endif /* NETCONN */
if (ttpipe) return(0);
#ifndef Plan9
if (ttfdflg && !isatty(ttyfd)) return(0);
#endif /* Plan9 */
#ifdef COHERENT
#define SVORPOSIX
#endif /* COHERENT */
#ifndef SVORPOSIX /* Berkeley, V7, etc. */
#ifdef LPASS8
/*
For some reason, with BSD terminal drivers, you can't set FLOW to XON/XOFF
after having previously set it to NONE without closing and reopening the
device. Unless there's something I overlooked below...
*/
if (ttflow == FLO_NONE && flow == FLO_XONX && xlocal == 0) {
debug(F101,"ttpkt executing horrible flow kludge","",0);
ttclos(0); /* Close it */
x = 0;
ttopen(ttnmsv,&x,ttmdm,0); /* Open it again */
}
#endif /* LPASS8 */
#endif /* SVORPOSIX */
#ifdef COHERENT
#undef SVORPOSIX
#endif /* COHERENT */
if (xflow != FLO_DIAL && xflow != FLO_DIAX)
ttflow = xflow; /* Now make this available too. */
#ifndef NOLOCAL
if (xlocal) {
s2 = (int) (speed / 10L); /* Convert bps to cps */
s = ttsspd(s2); /* Check and set the speed */
debug(F101,"ttpkt carrier","",xflow);
carrctl(&ttraw, xflow != FLO_DIAL /* Carrier control */
&& (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
tvtflg = 0; /* So ttvt() will work next time */
}
#endif /* NOLOCAL */
#ifdef COHERENT
#define SVORPOSIX
#endif /* COHERENT */
#ifndef SVORPOSIX /* BSD section */
if (flow == FLO_RTSC || /* Hardware flow control */
flow == FLO_DTRC ||
flow == FLO_DTRT) {
tthflow(flow, 1, &ttraw);
debug(F100,"ttpkt hard flow, TANDEM off, RAW on","",0);
ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */
ttraw.sg_flags |= RAW; /* Enter raw mode */
} else if (flow == FLO_NONE) { /* No flow control */
debug(F100,"ttpkt no flow, TANDEM off, RAW on","",0);
ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */
tthflow(flow, 0, &ttraw); /* Turn off any hardware f/c too */
ttraw.sg_flags |= RAW; /* Enter raw mode */
} else if (flow == FLO_KEEP) { /* Keep device's original setting */
debug(F100,"ttpkt keeping original TANDEM","",0);
ttraw.sg_flags &= ~TANDEM;
ttraw.sg_flags |= (ttold.sg_flags & TANDEM);
/* NOTE: We should also handle hardware flow control here! */
}
/* SET FLOW XON/XOFF is in effect, or SET FLOW KEEP resulted in Xon/Xoff */
if ((flow == FLO_XONX) || (ttraw.sg_flags & TANDEM)) {
debug(F100,"ttpkt turning on TANDEM","",0);
ttraw.sg_flags |= TANDEM; /* So ask for it. */
#ifdef LPASS8 /* Can pass 8-bit data through? */
/* If the LPASS8 local mode is available, then flow control can always */
/* be used, even if parity is none and we are transferring 8-bit data. */
/* But we only need to do all this if Xon/Xoff is requested. */
/* BUT... this tends not to work through IP or LAT connections, terminal */
/* servers, telnet, rlogin, etc, so it is currently disabled. */
x = LPASS8; /* If LPASS8 defined, then */
debug(F100,"ttpkt executing LPASS8 code","",0);
if (lmodef) { /* TIOCLBIS must be too. */
x = ioctl(ttyfd,TIOCLBIS,&x); /* Try to set LPASS8. */
if (x < 0) {
debug(F100,"ttpkt TIOCLBIS error","",0);
} else {
lmodef++;
debug(F100,"ttpkt TIOCLBIS ok","",0);
}
}
/*
But if we use LPASS8 mode, we must explicitly turn off
terminal interrupts of all kinds.
*/
#ifdef TIOCGETC /* Not rawmode, */
if (tcharf && (xlocal == 0)) { /* must turn off */
tchnoi.t_intrc = -1; /* interrupt character */
tchnoi.t_quitc = -1; /* and quit character. */
tchnoi.t_startc = 17; /* Make sure xon */
tchnoi.t_stopc = 19; /* and xoff not ignored. */
#ifndef NOBRKC
tchnoi.t_eofc = -1; /* eof character. */
tchnoi.t_brkc = -1; /* brk character. */
#endif /* NOBRKC */
if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
debug(F100,"ttpkt TIOCSETC failed","",0);
} else {
tcharf = 1;
debug(F100,"ttpkt TIOCSETC ok","",0);
}
#ifdef COMMENT
/* only for paranoid debugging */
if (tcharf) {
struct tchars foo;
char tchbuf[100];
ioctl(0,TIOCGETC,&foo);
sprintf(tchbuf,
"intr=%d,quit=%d, start=%d, stop=%d, eof=%d, brk=%d",
foo.t_intrc, foo.t_quitc, foo.t_startc,
foo.t_stopc, foo.t_eofc, foo.t_brkc);
debug(F110,"ttpkt chars",tchbuf,0);
}
#endif /* COMMENT */
}
ttraw.sg_flags |= CBREAK; /* Needed for unknown reason */
#endif /* TIOCGETC */
/* Prevent suspend during packet mode */
#ifdef TIOCGLTC /* Not rawmode, */
if (ltcharf && (xlocal == 0)) { /* must turn off */
ltchnoi.t_suspc = -1; /* suspend character */
ltchnoi.t_dsuspc = -1; /* and delayed suspend character */
if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
debug(F100,"ttpkt TIOCSLTC failed","",0);
} else {
ltcharf = 1;
debug(F100,"ttpkt TIOCSLTC ok","",0);
}
}
#endif /* TIOCGLTC */
#else /* LPASS8 not defined */
/* Previously, BSD-based implementations always */
/* used rawmode for packets. Now, we use rawmode only if parity is NONE. */
/* This allows the flow control requested above to actually work, but only */
/* if the user asks for parity (which also means they get 8th-bit quoting). */
if (parity) { /* If parity, */
ttraw.sg_flags &= ~RAW; /* use cooked mode */
#ifdef COMMENT
/* WHY??? */
if (xlocal)
#endif /* COMMENT */
ttraw.sg_flags |= CBREAK;
debug(F101,"ttpkt cooked, cbreak, parity","",parity);
#ifdef TIOCGETC /* Not rawmode, */
if (tcharf && (xlocal == 0)) { /* must turn off */
tchnoi.t_intrc = -1; /* interrupt character */
tchnoi.t_quitc = -1; /* and quit character. */
tchnoi.t_startc = 17; /* Make sure xon */
tchnoi.t_stopc = 19; /* and xoff not ignored. */
#ifndef NOBRKC
tchnoi.t_eofc = -1; /* eof character. */
tchnoi.t_brkc = -1; /* brk character. */
#endif /* NOBRKC */
if (ioctl(ttyfd,TIOCSETC,&tchnoi) < 0) {
debug(F100,"ttpkt TIOCSETC failed","",0);
} else {
tcharf = 1;
debug(F100,"ttpkt TIOCSETC ok","",0);
}
}
#endif /* TIOCGETC */
#ifdef TIOCGLTC /* Not rawmode, */
/* Prevent suspend during packet mode */
if (ltcharf && (xlocal == 0)) { /* must turn off */
ltchnoi.t_suspc = -1; /* suspend character */
ltchnoi.t_dsuspc = -1; /* and delayed suspend character */
if (ioctl(ttyfd,TIOCSLTC,&tchnoi) < 0) {
debug(F100,"ttpkt TIOCSLTC failed","",0);
} else {
ltcharf = 1;
debug(F100,"ttpkt TIOCSLTC ok","",0);
}
}
#endif /* TIOCGLTC */
} else { /* If no parity, */
ttraw.sg_flags |= RAW; /* must use 8-bit raw mode. */
debug(F101,"ttpkt setting rawmode, parity","",parity);
}
#endif /* LPASS8 */
} /* End of Xon/Xoff section */
/* Don't echo, don't map CR to CRLF on output, don't fool with case */
#ifdef LCASE
ttraw.sg_flags &= ~(ECHO|CRMOD|LCASE);
#else
ttraw.sg_flags &= ~(ECHO|CRMOD);
#endif /* LCASE */
#ifdef TOWER1
ttraw.sg_flags &= ~ANYP; /* Must set this on old Towers */
#endif /* TOWER1 */
#ifdef BELLV10
if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0) return(-1); /* Set the new modes. */
#else
if (stty(ttyfd,&ttraw) < 0) return(-1); /* Set the new modes. */
#endif /* BELLV10 */
debug(F100,"ttpkt stty ok","",0);
#ifdef sony_news
x = xlocal ? km_ext : km_con; /* Put line in ASCII mode. */
if (x != -1) { /* Make sure we know original modes. */
x &= ~KM_TTYPE;
x |= KM_ASCII;
if (ioctl(ttyfd,TIOCKSET, &x) < 0) {
perror("ttpkt can't set ASCII mode");
debug(F101,"ttpkt error setting ASCII mode","",x);
return(-1);
}
}
debug(F100,"ttpkt set ASCII mode ok","",0);
#endif /* sony_news */
if (xlocal == 0) /* Turn this off so we can read */
signal(SIGINT,SIG_IGN); /* Ctrl-C chars typed at console */
tvtflg = 0; /* So ttvt() will work next time */
return(0);
#endif /* Not ATTSV or POSIX */
/* AT&T UNIX and POSIX */
#ifdef COHERENT
#define SVORPOSIX
#endif /* COHERENT */
#ifdef SVORPOSIX
if (flow == FLO_XONX) { /* Xon/Xoff */
ttraw.c_iflag |= (IXON|IXOFF);
tthflow(flow, 0, &ttraw);
} else if (flow == FLO_NONE) { /* None */
/* NOTE: We should also turn off hardware flow control here! */
ttraw.c_iflag &= ~(IXON|IXOFF);
tthflow(flow, 0, &ttraw);
} else if (flow == FLO_KEEP) { /* Keep */
ttraw.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
ttraw.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
/* NOTE: We should also handle hardware flow control here! */
#ifdef POSIX_CRTSCTS
/* In Linux case, we do this, which is unlikely to be portable */
ttraw.c_cflag &= ~CRTSCTS; /* Turn off RTS/CTS flag */
ttraw.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
#endif /* POSIX_CRTSCTS */
} else if (flow == FLO_RTSC || /* Hardware */
flow == FLO_DTRC ||
flow == FLO_DTRT) {
ttraw.c_iflag &= ~(IXON|IXOFF); /* (190) */
tthflow(flow, 1, &ttraw);
}
ttraw.c_lflag &= ~(ICANON|ECHO);
ttraw.c_lflag &= ~ISIG; /* Do NOT check for interrupt chars */
#ifndef OXOS
#ifdef QNX
if (flow != FLO_RTSC && flow != FLO_DTRC && flow != FLO_DTRT)
#endif /* QNX */
#ifndef COHERENT
ttraw.c_lflag &= ~IEXTEN; /* Turn off ^O/^V processing */
#endif /* COHERENT */
#else /* OXOS */
ttraw.c_cc[VDISCARD] = ttraw.c_cc[VLNEXT] = CDISABLE;
#endif /* OXOS */
ttraw.c_lflag |= NOFLSH; /* Don't flush */
ttraw.c_iflag |= (BRKINT|IGNPAR);
#ifdef ATTSV
#ifdef BSD44
ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP|IXANY);
#else
ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|INPCK|ISTRIP|IXANY);
#endif /* BSD44 */
#else /* POSIX */
ttraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|INPCK|ISTRIP);
#endif /* ATTSV */
ttraw.c_oflag &= ~OPOST;
ttraw.c_cflag &= ~(CSIZE|PARENB);
ttraw.c_cflag |= (CS8|CREAD|HUPCL);
#ifdef IX370
ttraw.c_cc[4] = 48; /* So Series/1 doesn't interrupt on every char */
ttraw.c_cc[5] = 1;
#else
#ifndef VEOF /* for DGUX this is VEOF, not VMIN */
ttraw.c_cc[4] = 1; /* [VMIN] return max of this many characters or */
#else
#ifndef OXOS
#ifdef VMIN
ttraw.c_cc[VMIN] = 1;
#endif /* VMIN */
#else /* OXOS */
ttraw.c_min = 1;
#endif /* OXOS */
#endif /* VEOF */
#ifndef VEOL /* for DGUX this is VEOL, not VTIME */
ttraw.c_cc[5] = 0; /* [VTIME] when this many secs/10 expire w/no input */
#else
#ifndef OXOS
#ifdef VTIME
ttraw.c_cc[VTIME] = 0;
#endif /* VTIME */
#else /* OXOS */
ttraw.c_time = 0;
#endif /* OXOS */
#endif /* VEOL */
#endif /* IX370 */
#ifdef VINTR /* Turn off interrupt character */
if (xlocal == 0) /* so ^C^C can break us out of */
ttraw.c_cc[VINTR] = 0; /* packet mode. */
#endif /* VINTR */
#ifdef Plan9
if (p9ttyparity('n') < 0)
return -1;
#else
#ifdef BSD44ORPOSIX
#ifdef BEBOX
ttraw.c_cc[VMIN] = 0; /* DR7 can only poll. */
#endif /* BEBOX */
if (tcsetattr(ttyfd,TCSADRAIN,&ttraw) < 0) return(-1);
#else /* ATTSV */
if (ioctl(ttyfd,TCSETAW,&ttraw) < 0) return(-1); /* set new modes . */
#endif /* BSD44ORPOSIX */
#endif /* Plan9 */
tvtflg = 0;
return(0);
#endif /* ATTSV */
#ifdef COHERENT
#undef SVORPOSIX
#endif /* COHERENT */
}
/* T T S E T F L O W -- Set flow control immediately. */
int
ttsetflow(flow) int flow; {
if (ttyfd < 0) /* Communications channel must open */
return(-1);
#ifdef NETCMD
if (ttpipe) return(0);
#endif /* NETCMD */
if (flow == FLO_RTSC || /* Hardware flow control... */
flow == FLO_DTRC ||
flow == FLO_DTRT) {
tthflow(flow, 1, &ttraw);
#ifndef SVORPOSIX
ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */
#else
ttraw.c_iflag &= ~(IXON|IXOFF);
#endif /* SVORPOSIX */
} else if (flow == FLO_XONX) { /* Xon/Xoff... */
#ifndef SVORPOSIX
ttraw.sg_flags |= TANDEM;
#else
ttraw.c_iflag |= (IXON|IXOFF);
#endif /* SVORPOSIX */
tthflow(FLO_RTSC, 0, &ttraw); /* Turn off hardware flow control */
} else if (flow == FLO_NONE) { /* No flow control */
#ifndef SVORPOSIX
ttraw.sg_flags &= ~TANDEM; /* Turn off software flow control */
#else
ttraw.c_iflag &= ~(IXON|IXOFF);
#endif /* SVORPOSIX */
tthflow(FLO_RTSC, 0, &ttraw); /* Turn off any hardware f/c too */
}
/* Set the new modes... */
#ifndef SVORPOSIX /* BSD and friends */
#ifdef BELLV10
if (ioctl(ttyfd,TIOCSETP,&ttraw) < 0)
return(-1);
#else
#ifndef MINIX2
if (stty(ttyfd,&ttraw) < 0)
return(-1);
#endif /* MINIX2 */
#endif /* BELLV10 */
#else
#ifdef BSD44ORPOSIX /* POSIX */
if (tcsetattr(ttyfd,TCSADRAIN,&ttraw) < 0)
return(-1);
#else /* System V */
if (ioctl(ttyfd,TCSETAW,&ttraw) < 0)
return(-1);
#endif /* BSD44ORPOSIX */
#endif /* SVORPOSIX */
return(0);
}
/* T T V T -- Condition communication line for use as virtual terminal */
#ifndef NOLOCAL
int
#ifdef CK_ANSIC
ttvt(long speed, int flow)
#else
ttvt(speed,flow) long speed; int flow;
#endif /* CK_ANSIC */
/* ttvt */ {
int s, s2;
debug(F101,"ttvt ttyfd","",ttyfd);
debug(F101,"ttvt tvtflg","",tvtflg);
debug(F101,"ttvt speed","",speed);
debug(F101,"ttvt flow","",flow);
ttpmsk = 0xff; /* ??? */
if (ttyfd < 0) return(-1); /* Not open. */
if (ttpipe) return(0); /* Pipe */
#ifdef NETCONN
if (netconn) {
tvtflg = 1; /* Network connections */
debug(F100,"ttvt network connection, skipping...","",0);
#ifdef TCPSOCKET
#ifdef TCP_NODELAY
{
extern int tcp_nodelay;
if (ttnet == NET_TCPB) {
if (nodelay_sav > -1) {
no_delay(nodelay_sav);
nodelay_sav = -1;
}
}
}
#endif /* TCP_NODELAY */
#endif /* TCPSOCKET */
return(0); /* require no special setup */
}
#endif /* NETCONN */
if (tvtflg != 0 && speed == ttspeed && flow == ttflow && ttcarr == curcarr)
{
debug(F100,"ttvt modes already set, skipping...","",0);
return(0); /* Already been called. */
}
if (ttfdflg
#ifndef Plan9
&& !isatty(ttyfd)
#endif /* Plan9 */
) {
debug(F100,"ttvt using external fd, skipping...","",0);
return(0);
}
debug(F100,"ttvt setting modes...","",0);
if (xlocal) { /* For external lines... */
s2 = (int) (speed / 10L);
s = ttsspd(s2); /* Check/set the speed */
carrctl(&tttvt, flow != FLO_DIAL /* Do carrier control */
&& (ttcarr == CAR_ON || (ttcarr == CAR_AUT && ttmdm != 0)));
} else
s = s2 = -1;
#ifdef COHERENT
#define SVORPOSIX
#endif /* COHERENT */
#ifndef SVORPOSIX
/* Berkeley, V7, etc */
if (flow == FLO_RTSC || /* Hardware flow control */
flow == FLO_DTRC ||
flow == FLO_DTRT)
tthflow(flow, 1, &tttvt);
if (flow == FLO_XONX) { /* Xon/Xoff flow control */
tttvt.sg_flags |= TANDEM; /* Ask for it. */
tthflow(flow, 0, &tttvt); /* Turn off hardware f/c */
} else if (flow == FLO_KEEP) {
tttvt.sg_flags &= ~TANDEM;
tttvt.sg_flags |= (ttold.sg_flags & TANDEM);
/* NOTE: We should also handle hardware flow control here! */
} else if (flow == FLO_NONE) {
tttvt.sg_flags &= ~TANDEM; /* No Xon/Xoff */
tthflow(flow, 0, &tttvt); /* Turn off hardware f/c */
}
tttvt.sg_flags |= RAW; /* Raw mode in all cases */
#ifdef TOWER1
tttvt.sg_flags &= ~(ECHO|ANYP); /* No echo or parity */
#else
tttvt.sg_flags &= ~ECHO; /* No echo */
#endif /* TOWER1 */
#ifdef BELLV10
if (ioctl(ttyfd,TIOCSETP,&tttvt) < 0) /* Set the new modes */
return(-1);
#else
if (stty(ttyfd,&tttvt) < 0) /* Set the new modes */
return(-1);
#endif /* BELLV10 */
#else /* It is ATTSV or POSIX */
if (flow == FLO_RTSC || /* Hardware flow control */
flow == FLO_DTRC ||
flow == FLO_DTRT) {
tthflow(flow, 1, &tttvt);
} else if (flow == FLO_XONX) { /* Software flow control */
tttvt.c_iflag |= (IXON|IXOFF); /* On if requested. */
tthflow(flow, 0, &tttvt); /* Turn off hardware f/c */
} else if (flow == FLO_KEEP) {
tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff flags */
tttvt.c_iflag |= (ttold.c_iflag & (IXON|IXOFF)); /* OR in old ones */
/* NOTE: We should also handle hardware flow control here! */
#ifdef POSIX_CRTSCTS
tttvt.c_cflag &= ~CRTSCTS; /* Turn off RTS/CTS flag */
tttvt.c_cflag |= (ttold.c_cflag & CRTSCTS); /* OR in old one */
#endif /* POSIX_CRTSCTS */
} else if (flow == FLO_NONE) { /* NONE */
tthflow(flow, 0, &tttvt); /* Turn off hardware f/c */
tttvt.c_iflag &= ~(IXON|IXOFF); /* Turn off Xon/Xoff */
}
#ifndef OXOS
#ifdef COHERENT
tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
#else
tttvt.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
#endif /* COHERENT */
#ifdef QNX
/* Needed for hwfc */
if (flow == FLO_RTSC || flow == FLO_DTRC || flow == FLO_DTRT)
tttvt.c_lflag |= IEXTEN;
#endif /* QNX */
#else /* OXOS */
tttvt.c_lflag &= ~(ISIG|ICANON|ECHO);
tttvt.c_cc[VDISCARD] = tttvt.c_cc[VLNEXT] = CDISABLE;
#endif /* OXOS */
tttvt.c_iflag |= (IGNBRK|IGNPAR);
#ifdef ATTSV
#ifdef BSD44
tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|BRKINT|INPCK|ISTRIP|IXANY);
#else
tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|BRKINT|INPCK|ISTRIP|IXANY);
#endif /* BSD44 */
#else /* POSIX */
tttvt.c_iflag &= ~(INLCR|IGNCR|ICRNL|BRKINT|INPCK|ISTRIP);
#endif /* ATTSV */
tttvt.c_oflag &= ~OPOST;
tttvt.c_cflag &= ~(CSIZE|PARENB);
tttvt.c_cflag |= (CS8|CREAD|HUPCL);
#ifndef VEOF /* DGUX termio has VEOF at entry 4, see comment above */
tttvt.c_cc[4] = 1;
#else
#ifndef OXOS
#ifdef VMIN
tttvt.c_cc[VMIN] = 1;
#endif /* VMIN */
#else /* OXOS */
tttvt.c_min = 1;
#endif /* OXOS */
#endif /* VEOF */
#ifndef VEOL /* DGUX termio has VEOL at entry 5, see comment above */
tttvt.c_cc[5] = 0;
#else
#ifndef OXOS
#ifdef VTIME
tttvt.c_cc[VTIME] = 0;
#endif /* VTIME */
#else /* OXOS */
tttvt.c_time = 0;
#endif /* OXOS */
#endif /* VEOL */
#ifdef Plan9
if (p9ttyparity('n') < 0)
return -1;
#else
#ifdef BSD44ORPOSIX
#ifdef BEBOX
tttvt.c_cc[VMIN] = 0; /* DR7 can only poll. */
#endif /* BEBOX */
if (tcsetattr(ttyfd,TCSADRAIN,&tttvt) < 0) return(-1);
#else /* ATTSV */
if (ioctl(ttyfd,TCSETAW,&tttvt) < 0) return(-1); /* set new modes . */
#endif /* BSD44ORPOSIX */
#endif /* Plan9 */
#endif /* ATTSV */
ttspeed = speed; /* Done, remember how we were */
ttflow = flow; /* called, so we can decide how to */
tvtflg = 1; /* respond next time. */
debug(F101,"ttvt done","",tvtflg);
return(0);
#ifdef COHERENT
#undef SVORPOSIX
#endif /* COHERENT */
}
#endif /* NOLOCAL */
#ifndef NOLOCAL
/* Serial speed department . . . */
/*
Plan 9's native speed setting interface lets you set anything you like,
but will fail if the hardware doesn't like it, so we allow all the common
speeds.
*/
#ifdef Plan9
#ifndef B50
#define B50 50
#endif /* B50 */
#ifndef B75
#define B75 75
#endif /* B75 */
#ifndef B110
#define B110 110
#endif /* B110 */
#ifndef B134
#define B134 134
#endif /* B134 */
#ifndef B200
#define B200 200
#endif /* B200 */
#ifndef B300
#define B300 300
#endif /* B300 */
#ifndef B1200
#define B1200 1200
#endif /* B1200 */
#ifndef B1800
#define B1800 1800
#endif /* B1800 */
#ifndef B2400
#define B2400 2400
#endif /* B2400 */
#ifndef B4800
#define B4800 4800
#endif /* B4800 */
#ifndef B9600
#define B9600 9600
#endif /* B9600 */
#ifndef B14400
#define B14400 14400
#endif /* B14400 */
#ifndef B19200
#define B19200 19200
#endif /* B19200 */
#ifndef B28800
#define B28800 28800
#endif /* B28800 */
#ifndef B38400
#define B38400 38400
#endif /* B38400 */
#ifndef B57600
#define B57600 57600
#endif /* B57600 */
#ifndef B76800
#define B76800 76800
#endif /* B76800 */
#ifndef B115200
#define B115200 115200
#endif /* B115200 */
#ifndef B230400
#define B230400 230400
#endif /* B230400 */
#ifndef B460800
#define B460800 460800
#endif /* B460800 */
#ifndef B921600
#define B921600 921600
#endif /* B921600 */
#endif /* Plan9 */
/* T T S S P D -- Checks and sets transmission rate. */
/* Call with speed in characters (not bits!) per second. */
/* Returns -1 on failure, 0 if it did nothing, 1 if it changed the speed. */
int
ttsspd(cps) int cps; {
int x;
#ifdef POSIX
/* Watch out, speed_t should be unsigned, so don't compare with -1, etc... */
speed_t
#else
int
#endif /* POSIX */
s, s2;
int ok = 1; /* Speed check result, assume ok */
#ifdef OLINUXHISPEED
unsigned int spd_flags = 0;
struct serial_struct serinfo;
#endif /* OLINUXHISPEED */
debug(F101,"ttsspd cps","",cps);
debug(F101,"ttsspd ttyfd","",ttyfd);
debug(F101,"ttsspd xlocal","",xlocal);
if (ttyfd < 0 || xlocal == 0 ) /* Don't set speed on console */
return(0);
#ifdef NETCONN
if (netconn)
return(0);
#endif /* NETCONN */
if (ttpipe)
return(0);
if (cps < 0) return(-1);
s = s2 = 0; /* NB: s and s2 might be unsigned */
#ifdef MINIX2 /* Hack alert */
#define MINIX /* Use pre-2.0 speed selection for Minix 2.0 as well */
#endif /* MINIX2 */
/* First check that the given speed is valid. */
switch (cps) {
#ifndef MINIX
case 0: s = B0; break;
case 5: s = B50; break;
case 7: s = B75; break;
#endif /* MINIX */
case 11: s = B110; break;
#ifndef MINIX
case 13: s = B134; break;
case 15: s = B150; break;
case 20: s = B200; break;
#endif /* MINIX */
case 30: s = B300; break;
#ifndef MINIX
case 60: s = B600; break;
#endif /* MINIX */
case 120: s = B1200; break;
#ifndef MINIX
case 180: s = B1800; break;
#endif /* MINIX */
case 240: s = B2400; break;
case 480: s = B4800; break;
#ifndef MINIX
case 888: s = B75; s2 = B1200; break; /* 888 = 75/1200 split speed */
#endif /* MINIX */
case 960: s = B9600; break;
#ifdef B14400
case 1440: s = B14400; break;
#endif /* B14400 */
#ifdef B19200
case 1920: s = B19200; break;
#else
#ifdef EXTA
case 1920: s = EXTA; break;
#endif /* EXTA */
#endif /* B19200 */
#ifdef B28800
case 2880: s = B28800; break;
#endif /* B28800 */
#ifdef B38400
case 3840: s = B38400;
#ifdef OLINUXHISPEED
spd_flags = ~ASYNC_SPD_MASK; /* Nonzero, but zero flags */
#endif /* OLINUXHISPEED */
break;
#else /* B38400 not defined... */
#ifdef EXTB
case 3840: s = EXTB; break;
#endif /* EXTB */
#endif /* B38400 */
#ifdef HPUX
#ifdef _B57600
case 5760: s = _B57600; break;
#endif /* _B57600 */
#ifdef _B115200
case 11520: s = _B115200; break;
#endif /* _B115200 */
#else
#ifdef OLINUXHISPEED
/*
This bit from <carlo@sg.tn.tudelft.nl>:
"Only note to make is maybe this: When the ASYNC_SPD_CUST flags are set then
setting the speed to 38400 will set the custom speed (and ttgspd returns
38400), but speeds 57600 and 115200 won't work any more because I didn't
want to mess up the speed flags when someone is doing sophisticated stuff
like custom speeds..."
*/
case 5760: s = B38400; spd_flags = ASYNC_SPD_HI; break;
case 11520: s = B38400; spd_flags = ASYNC_SPD_VHI; break;
#else
#ifdef B57600
case 5760: s = B57600; break;
#endif /* B57600 */
#ifdef B76800
case 7680: s = B76800; break;
#endif /* B76800 */
#ifdef B115200
case 11520: s = B115200; break;
#endif /* B115200 */
#endif /* OLINUXHISPEED */
#ifdef B230400
case 23040: s = B230400; break;
#endif /* B230400 */
#ifdef B460800
case 46080: s = B460800; break;
#endif /* 460800 */
#ifdef B921600
case 92160: s = B921600; break;
#endif /* B921600 */
#endif /* HPUX */
default:
ok = 0; /* Good speed not found, so not ok */
break;
}
debug(F101,"ttsspd ok","",ok);
debug(F101,"ttsspd s","",s);
if (!ok) {
debug(F100,"ttsspd fails","",0);
return(-1);
} else {
if (!s2) s2 = s; /* Set input speed */
#ifdef Plan9
if (p9ttsspd(cps) < 0)
return(-1);
#else
#ifdef BSD44ORPOSIX
x = tcgetattr(ttyfd,&ttcur); /* Get current speed */
debug(F101,"ttsspd tcgetattr","",x);
if (x < 0)
return(-1);
#ifdef OLINUXHISPEED
debug(F101,"ttsspd spd_flags","",spd_flags);
if (spd_flags && spd_flags != ASYNC_SPD_CUST) {
if (ioctl(ttyfd, TIOCGSERIAL, &serinfo) < 0) {
debug(F100,"ttsspd: TIOCGSERIAL failed","",0);
return(-1);
} else debug(F100,"ttsspd: TIOCGSERIAL ok","",0);
serinfo.flags &= ~ASYNC_SPD_MASK;
serinfo.flags |= (spd_flags & ASYNC_SPD_MASK);
if (ioctl(ttyfd, TIOCSSERIAL, &serinfo) < 0)
return(-1);
}
#endif /* OLINUXHISPEED */
cfsetospeed(&ttcur,s);
cfsetispeed(&ttcur,s2);
cfsetospeed(&ttraw,s);
cfsetispeed(&ttraw,s2);
cfsetospeed(&tttvt,s);
cfsetispeed(&tttvt,s2);
cfsetospeed(&ttold,s);
cfsetispeed(&ttold,s2);
x = tcsetattr(ttyfd,TCSADRAIN,&ttcur);
debug(F101,"ttsspd tcsetattr","",x);
if (x < 0) return(-1);
#else
#ifdef ATTSV
if (cps == 888) return(-1); /* No split speeds, sorry. */
x = ioctl(ttyfd,TCGETA,&ttcur);
debug(F101,"ttsspd TCGETA ioctl","",x);
if (x < 0) return(-1);
ttcur.c_cflag &= ~CBAUD;
ttcur.c_cflag |= s;
tttvt.c_cflag &= ~CBAUD;
tttvt.c_cflag |= s;
ttraw.c_cflag &= ~CBAUD;
ttraw.c_cflag |= s;
ttold.c_cflag &= ~CBAUD;
ttold.c_cflag |= s;
x = ioctl(ttyfd,TCSETAW,&ttcur);
debug(F101,"ttsspd TCSETAW ioctl","",x);
if (x < 0) return(-1);
#else
#ifdef BELLV10
x = ioctl(ttyfd,TIOCGDEV,&tdcur);
debug(F101,"ttsspd TIOCGDEV ioctl","",x);
if (x < 0) return(-1);
tdcur.ispeed = s2;
tdcur.ospeed = s;
errno = 0;
ok = ioctl(ttyfd,TIOCSDEV,&tdcur);
debug(F101,"ttsspd BELLV10 ioctl","",ok);
if (ok < 0) {
perror(ttnmsv);
debug(F101,"ttsspd BELLV10 errno","",ok);
return(-1);
}
#else
x = gtty(ttyfd,&ttcur);
debug(F101,"ttsspd gtty","",x);
if (x < 0) return(-1);
ttcur.sg_ospeed = s; ttcur.sg_ispeed = s2;
tttvt.sg_ospeed = s; tttvt.sg_ispeed = s2;
ttraw.sg_ospeed = s; ttraw.sg_ispeed = s2;
ttold.sg_ospeed = s; ttold.sg_ispeed = s2;
x = stty(ttyfd,&ttcur);
debug(F101,"ttsspd stty","",x);
if (x < 0) return(-1);
#endif /* BELLV10 */
#endif /* ATTSV */
#endif /* BSD44ORPOSIX */
#endif /* Plan9 */
}
return(1); /* Return 1 = success. */
}
#endif /* NOLOCAL */
/* C O N G S P D - Get speed of console terminal */
long
congspd() {
/*
This is a disgusting hack. The right way to do this would be to pass an
argument to ttgspd(), but then we'd need to change the Kermit API and
all of the ck?tio.c modules. (Currently used only for rlogin.)
*/
int t1, t2;
long spd;
#ifdef NETCONN
t2 = netconn;
netconn = 0;
#endif /* NETCONN */
t1 = ttyfd;
ttyfd = -1;
spd = ttgspd();
debug(F101,"congspd","",spd);
#ifdef NETCONN
netconn = t2;
#endif /* NETCONN */
ttyfd = t1;
return(spd);
}
/* T T S P D L I S T -- Get list of serial speeds allowed on this platform */
#define NSPDLIST 64
static long spdlist[NSPDLIST];
/*
As written, this picks up the speeds known at compile time, and thus
apply to the system where C-Kermit was built, rather than to the one where
it is running. Suggestions for improvement are always welcome.
*/
long *
ttspdlist() {
int i;
for (i = 0; i < NSPDLIST; i++) /* Initialize the list */
spdlist[i] = -1L;
i = 1;
#ifdef B50
spdlist[i++] = 50L;
#endif /* B50 */
#ifdef B75
spdlist[i++] = 75L;
#endif /* B75 */
#ifdef B110
spdlist[i++] = 110L;
#endif /* B110 */
#ifdef B134
spdlist[i++] = 134L;
#endif /* B134 */
#ifdef B150
spdlist[i++] = 150L;
#endif /* B150 */
#ifdef B200
spdlist[i++] = 200L;
#endif /* B200 */
#ifdef B300
spdlist[i++] = 300L;
#endif /* B300 */
#ifdef B600
spdlist[i++] = 600L;
#endif /* B600 */
#ifdef B1200
spdlist[i++] = 1200L;
#endif /* B1200 */
#ifdef B1800
spdlist[i++] = 1800L;
#endif /* B1800 */
#ifdef B2400
spdlist[i++] = 2400L;
#endif /* B2400 */
#ifdef B4800
spdlist[i++] = 4800L;
#endif /* B4800 */
#ifdef B9600
spdlist[i++] = 9600L;
#endif /* B9600 */
#ifdef B14400
spdlist[i++] = 14400L;
#endif /* B14400 */
#ifdef B19200
spdlist[i++] = 19200L;
#else
#ifdef EXTA
spdlist[i++] = 19200L;
#endif /* EXTA */
#endif /* B19200 */
#ifdef B28800
spdlist[i++] = 28800L;
#endif /* B28800 */
#ifdef B33600
spdlist[i++] = 33600L;
#endif /* B33600 */
#ifdef B38400
spdlist[i++] = 38400L;
#else
#ifdef EXTB
spdlist[i++] = 38400L;
#endif /* EXTB */
#endif /* B38400 */
#ifdef _B57600
spdlist[i++] = 57600L;
#else
#ifdef B57600
spdlist[i++] = 57600L;
#endif /* B57600 */
#endif /* _B57600 */
#ifdef B76800
spdlist[i++] = 76800L;
#endif /* B76800 */
#ifdef _B115200
spdlist[i++] = 115200L;
#else
#ifdef B115200
spdlist[i++] = 115200L;
#endif /* B115200 */
#endif /* _B115200 */
#ifdef B230400
spdlist[i++] = 230400L;
#endif /* B230400 */
#ifdef B460800
spdlist[i++] = 460800L;
#endif /* B460800 */
#ifdef B921600
spdlist[i++] = 921600L;
#endif /* B921600 */
spdlist[0] = i - 1; /* Return count in 0th element */
return((long *)spdlist);
}
/* T T G S P D - Get speed of currently selected tty line */
/*
Unreliable. After SET LINE, it returns an actual speed, but not necessarily
the real speed. On some systems, it returns the line's nominal speed, from
/etc/ttytab. Even if you SET SPEED to something else, this function might
not notice.
*/
long
ttgspd() { /* Get current serial device speed */
#ifdef POSIX
speed_t /* Should be unsigned */
#else
int /* Isn't unsigned */
#endif /* POSIX */
s;
int x;
long ss;
#ifdef OLINUXHISPEED
unsigned int spd_flags = 0;
struct serial_struct serinfo;
#endif /* OLINUXHISPEED */
#ifdef NETCONN
if (netconn) return(-1); /* -1 if network connection */
#endif /* NETCONN */
if (ttpipe) return(-1);
debug(F101,"ttgspd ttyfd","",ttyfd);
#ifdef Plan9
if (ttyfd < 0)
ss = -1;
else
ss = ttylastspeed;
#else
#ifdef OLINUXHISPEED
debug(F100,"ttgspd Linux OLINUXHISPEED","",0);
#endif /* OLINUXHISPEED */
if (ttyfd < 0) {
#ifdef BSD44ORPOSIX
s = cfgetospeed(&ccold);
debug(F101,"ttgspd cfgetospeed 1 POSIX","",s);
#else
#ifdef ATTSV
s = ccold.c_cflag & CBAUD;
debug(F101,"ttgspd c_cflag CBAUD 1 ATTSV","",s);
#else
s = ccold.sg_ospeed; /* (obtained by congm()) */
debug(F101,"ttgspd sg_ospeed 1","",s);
#endif /* ATTSV */
#endif /* BSD44POSIX */
} else {
#ifdef BSD44ORPOSIX
if (tcgetattr(ttyfd,&ttcur) < 0) return(-1);
s = cfgetospeed(&ttcur);
debug(F101,"ttgspd cfgetospeed 2 BSDORPOSIX","",s);
#ifdef OLINUXHISPEED
if (ioctl(ttyfd,TIOCGSERIAL,&serinfo) > -1)
spd_flags = serinfo.flags & ASYNC_SPD_MASK;
debug(F101,"ttgspd spd_flags","",spd_flags);
#endif /* OLINUXHISPEED */
#else
#ifdef ATTSV
x = ioctl(ttyfd,TCGETA,&ttcur);
debug(F101,"ttgspd ioctl 2 ATTSV x","",x);
if (x < 0) return(-1);
s = ttcur.c_cflag & CBAUD;
debug(F101,"ttgspd ioctl 2 ATTSV speed","",s);
#else
#ifdef BELLV10
x = ioctl(ttyfd,TIOCGDEV,&tdcur);
debug(F101,"ttgspd ioctl 2 BELLV10 x","",x);
if (x < 0) return(-1);
s = tdcur.ospeed;
debug(F101,"ttgspd ioctl 2 BELLV10 speed","",s);
#else
x = gtty(ttyfd,&ttcur);
debug(F101,"ttgspd gtty 2 x","",x);
if (x < 0) return(-1);
s = ttcur.sg_ospeed;
debug(F101,"ttgspd gtty 2 speed","",s);
#endif /* BELLV10 */
#endif /* ATTSV */
#endif /* BSD44ORPOSIX */
}
debug(F101,"ttgspd code","",s);
#ifdef OLINUXHISPEED
debug(F101,"ttgspd spd_flags","",spd_flags);
#endif /* OLINUXHISPEED */
switch (s) {
#ifdef B0
case B0: ss = 0L; break;
#endif /* B0 */
#ifndef MINIX
/*
MINIX defines the Bxx symbols to be bps/100, so B50==B75, B110==B134==B150,
etc, making for many "duplicate case in switch" errors, which are fatal.
*/
#ifdef B50
case B50: ss = 50L; break;
#endif /* B50 */
#ifdef B75
case B75: ss = 75L; break;
#endif /* B75 */
#endif /* MINIX */
#ifdef B110
case B110: ss = 110L; break;
#endif /* B110 */
#ifndef MINIX
#ifdef B134
case B134: ss = 134L; break;
#endif /* B134 */
#ifdef B150
case B150: ss = 150L; break;
#endif /* B150 */
#endif /* MINIX */
#ifdef B200
case B200: ss = 200L; break;
#endif /* B200 */
#ifdef B300
case B300: ss = 300L; break;
#endif /* B300 */
#ifdef B600
case B600: ss = 600L; break;
#endif /* B600 */
#ifdef B1200
case B1200: ss = 1200L; break;
#endif /* B1200 */
#ifdef B1800
case B1800: ss = 1800L; break;
#endif /* B1800 */
#ifdef B2400
case B2400: ss = 2400L; break;
#endif /* B2400 */
#ifdef B4800
case B4800: ss = 4800L; break;
#endif /* B4800 */
#ifdef B9600
case B9600: ss = 9600L; break;
#endif /* B9600 */
#ifdef B19200
case B19200: ss = 19200L; break;
#else
#ifdef EXTA
case EXTA: ss = 19200L; break;
#endif /* EXTA */
#endif /* B19200 */
#ifdef MINIX2
/* End of hack to make MINIX2 use MINIX1 speed setting */
#undef MINIX
#endif /* MINIX2 */
#ifndef MINIX
#ifdef B38400
case B38400:
ss = 38400L;
#ifdef OLINUXHISPEED
switch(spd_flags) {
case ASYNC_SPD_HI: ss = 57600L; break;
case ASYNC_SPD_VHI: ss = 115200L; break;
}
#endif /* OLINUXHISPEED */
break;
#else
#ifdef EXTB
case EXTB: ss = 38400L; break;
#endif /* EXTB */
#endif /* B38400 */
#endif /* MINIX */
#ifdef HPUX
#ifdef _B57600
case _B57600: ss = 57600L; break;
#endif /* _B57600 */
#ifdef _B115200
case _B115200: ss = 115200L; break;
#endif /* _B115200 */
#else
#ifdef B57600
case B57600: ss = 57600L; break;
#endif /* B57600 */
#ifdef B76800
case B76800: ss = 76800L; break;
#endif /* B76800 */
#ifdef B115200
case B115200: ss = 115200L; break;
#endif /* B115200 */
#ifdef B230400
case B230400: ss = 230400L; break;
#endif /* B230400 */
#ifdef B460800
case B460800: ss = 460800L; break;
#endif /* B460800 */
#endif /* HPUX */
#ifdef B921600
case 92160: ss = 921600L; break;
#endif /* B921600 */
default:
ss = -1; break;
}
#endif /* Plan9 */
debug(F101,"ttgspd speed","",ss);
return(ss);
}
#ifdef MINIX2 /* Another hack alert */
#define MINIX
#endif /* MINIX2 */
/*
FIONREAD data type... This has been defined as "long" for many, many
years, and it worked OK until 64-bit platforms appeared. Thus we use
int for 64-bit platforms, but keep long for the others. If we changed
the default PEEKTYPE to int, this would probably break 16-bit builds
(note that sizeof(long) == sizeof(int) on most 32-bit platforms), many
of which we have no way of testing any more. Therefore, do not change
the default definition of PEEKTYPE -- only add exceptions to it as needed.
*/
#ifdef COHERENT
#ifdef FIONREAD
#undef FIONREAD
#endif /* FIONREAD */
#define FIONREAD TIOCQUERY
#define PEEKTYPE int
#else /* Not COHERENT... */
#ifdef OSF32 /* Digital UNIX 3.2 or higher */
#define PEEKTYPE int
#else
#define PEEKTYPE long /* Elsewhere (see notes above) */
#endif /* OSF32 */
#endif /* COHERENT */
/* ckumyr.c by Kristoffer Eriksson, ske@pkmab.se, 15 Mar 1990. */
#ifdef MYREAD
/* Private buffer for myread() and its companions. Not for use by anything
* else. ttflui() is allowed to reset them to initial values. ttchk() is
* allowed to read my_count.
*
* my_item is an index into mybuf[]. Increment it *before* reading mybuf[].
*
* A global parity mask variable could be useful too. We could use it to
* let myread() strip the parity on its own, instead of stripping sign
* bits as it does now.
*/
#ifdef BIGBUFOK
#define MYBUFLEN 32768
#else
#ifdef pdp11
#define MYBUFLEN 256
#else
#define MYBUFLEN 1024
#endif /* pdp11 */
#endif /* BIGBUFOK */
#ifdef ANYX25
#undef MYBUFLEN
#define MYBUFLEN 256
/*
On X.25 connections, there is an extra control byte at the beginning.
*/
static CHAR x25buf[MYBUFLEN+1]; /* Communication device input buffer */
static CHAR *mybuf = x25buf+1;
#else
static CHAR mybuf[MYBUFLEN];
#endif /* ANYX25 */
static int my_count = 0; /* Number of chars still in mybuf */
static int my_item = -1; /* Last index read from mybuf[] */
int
ttpeek() {
#ifdef MYREAD
return(my_count);
#else
return(0);
#endif /* MYREAD */
}
/* myread() -- Efficient read of one character from communications line.
*
* Uses a private buffer to minimize the number of expensive read() system
* calls. Essentially performs the equivalent of read() of 1 character, which
* is then returned. By reading all available input from the system buffers
* to the private buffer in one chunk, and then working from this buffer, the
* number of system calls is reduced in any case where more than one character
* arrives during the processing of the previous chunk, for instance high
* baud rates or network type connections where input arrives in packets.
* If the time needed for a read() system call approaches the time for more
* than one character to arrive, then this mechanism automatically compensates
* for that by performing bigger read()s less frequently. If the system load
* is high, the same mechanism compensates for that too.
*
* myread() is a macro that returns the next character from the buffer. If the
* buffer is empty, mygetbuf() is called. See mygetbuf() for possible error
* returns.
*
* This should be efficient enough for any one-character-at-a-time loops.
* For even better efficiency you might use memcpy()/bcopy() or such between
* buffers (since they are often better optimized for copying), but it may not
* be worth it if you have to take an extra pass over the buffer to strip
* parity and check for CTRL-C anyway.
*
* Note that if you have been using myread() from another program module, you
* may have some trouble accessing this macro version and the private variables
* it uses. In that case, just add a function in this module, that invokes the
* macro.
*/
#define myread() (--my_count < 0 ? mygetbuf() : 255 & (int)mybuf[++my_item])
/* Specification: Push back up to one character onto myread()'s queue.
*
* This implementation: Push back characters into mybuf. At least one character
* must have been read through myread() before myunrd() may be used. After
* EOF or read error, again, myunrd() can not be used. Sometimes more than
* one character can be pushed back, but only one character is guaranteed.
* Since a previous myread() must have read its character out of mybuf[],
* that guarantees that there is space for at least one character. If push
* back was really needed after EOF, a small addition could provide that.
*
* myunrd() is currently not called from anywhere inside kermit...
*/
#ifdef COMMENT /* not used */
myunrd(ch) CHAR ch; {
if (my_item >= 0) {
mybuf[my_item--] = ch;
++my_count;
}
}
#endif /* COMMENT */
/* T T P U S H B A C K -- Put n bytes back into the myread buffer */
static CHAR * pushbuf = NULL;
static int pushed = 0;
int
ttpushback(s,n) CHAR * s; int n; {
debug(F101,"ttpushback n","",n);
if (pushbuf || n > MYBUFLEN || n < 1)
return(-1);
debug(F101,"ttpushback my_count","",my_count);
if (my_count > 0) {
if (!(pushbuf = (CHAR *)malloc(n+1)))
return(-1);
memcpy(pushbuf,mybuf,my_count);
pushed = my_count;
}
memcpy(mybuf,s,n);
my_count = n;
my_item = -1;
return(0);
}
/* mygetbuf() -- Fill buffer for myread() and return first character.
*
* This function is what myread() uses when it can't get the next character
* directly from its buffer. First, it calls a system dependent myfillbuf()
* to read at least one new character into the buffer, and then it returns
* the first character just as myread() would have done. This function also
* is responsible for all error conditions that myread() can indicate.
*
* Returns: When OK => a positive character, 0 or greater.
* When EOF => -2.
* When error => -3, error code in errno.
*
* Older myread()s additionally returned -1 to indicate that there was nothing
* to read, upon which the caller would call myread() again until it got
* something. The new myread()/mygetbuf() always gets something. If it
* doesn't, then make it do so! Any program that actually depends on the old
* behaviour will break.
*
* The older version also used to return -2 both for EOF and other errors,
* and used to set errno to 9999 on EOF. The errno stuff is gone, EOF and
* other errors now return different results, although Kermit currently never
* checks to see which it was. It just disconnects in both cases.
*
* Kermit lets the user use the quit key to perform some special commands
* during file transfer. This causes read(), and thus also mygetbuf(), to
* finish without reading anything and return the EINTR error. This should
* be checked by the caller. Mygetbuf() could retry the read() on EINTR,
* but if there is nothing to read, this could delay Kermit's reaction to
* the command, and make Kermit appear unresponsive.
*
* The debug() call should be removed for optimum performance.
*/
int
mygetbuf() {
errno = 0;
#ifdef DEBUG
if (deblog && my_count > 0)
debug(F101,"mygetbuf IMPROPERLY CALLED with my_count","",my_count);
#endif /* DEBUG */
if (my_count <= 0)
my_count = myfillbuf();
#ifdef DEBUG
if (deblog) debug(F101, "myfillbuf read", "", my_count);
#endif /* DEBUG */
if (my_count <= 0) {
my_count = 0;
my_item = -1;
debug(F101,"mygetbuf errno","",errno);
#ifdef TCPSOCKET
if (netconn && ttnet == NET_TCPB && errno != 0) {
if (errno != EINTR) {
debug(F101,"mygetbuf TCP error","",errno);
ttclos(0); /* Close the connection. */
}
return(-3);
}
#endif /* TCPSOCKET */
if (!netconn && xlocal && errno) {
if (errno != EINTR) {
debug(F101,"mygetbuf SERIAL error","",errno);
ttclos(0); /* Close the connection. */
}
}
return((my_count < 0) ? -3 : -2);
}
--my_count;
return((unsigned)(0xff & mybuf[my_item = 0]));
}
/* myfillbuf():
* System-dependent read() into mybuf[], as many characters as possible.
*
* Returns: OK => number of characters read, always more than zero.
* EOF => 0
* Error => -1, error code in errno.
*
* If there is input available in the system's buffers, all of it should be
* read into mybuf[] and the function return immediately. If no input is
* available, it should wait for a character to arrive, and return with that
* one in mybuf[] as soon as possible. It may wait somewhat past the first
* character, but be aware that any such delay lengthens the packet turnaround
* time during kermit file transfers. Should never return with zero characters
* unless EOF or irrecoverable read error.
*
* Correct functioning depends on the correct tty parameters being used.
* Better control of current parameters is required than may have been the
* case in older Kermit releases. For instance, O_NDELAY (or equivalent) can
* no longer be sometimes off and sometimes on like it used to, unless a
* special myfillbuf() is written to handle that. Otherwise the ordinary
* myfillbuf()s may think they have come to EOF.
*
* If your system has a facility to directly perform the functioning of
* myfillbuf(), then use it. If the system can tell you how many characters
* are available in its buffers, then read that amount (but not less than 1).
* If the system can return a special indication when you try to read without
* anything to read, while allowing you to read all there is when there is
* something, you may loop until there is something to read, but probably that
* is not good for the system load.
*/
#ifdef SVORPOSIX
/* This is for System III/V with VMIN>0, VTIME=0 and O_NDELAY off,
* and CLOCAL set any way you like. This way, read() will do exactly
* what is required by myfillbuf(): If there is data in the buffers
* of the O.S., all available data is read into mybuf, up to the size
* of mybuf. If there is none, the first character to arrive is
* awaited and returned.
*/
int
myfillbuf() {
int fd, n;
#ifdef NETCMD
if (ttpipe)
fd = fdin;
else
#endif /* NETCMD */
fd = ttyfd;
#ifdef sxaE50
/* From S. Dezawa at Fujifilm in Japan. I don't know why this is */
/* necessary for the sxa E50, but it is. */
return read(fd, mybuf, 255);
#else
#ifdef BEBOX
while (1) {
#ifdef NETCONN
if (netconn) {
n = netxin(sizeof(mybuf), (char *)mybuf);
debug(F101,"BEBOX SVORPOSIX network myfillbuf","",n);
}
else
#endif /* NETCONN */
n = read(fd, mybuf, sizeof(mybuf));
debug(F101,"BEBOX SVORPOSIX notnet myfillbuf","",n);
if (n > 0)
return(n);
snooze(1000.0);
}
#else /* BEBOX */
errno = 0;
debug(F100,"SVORPOSIX myfillbuf calling read()","",0);
#ifdef IBMX25
if (netconn && (nettype == NET_IX25)) {
/* can't use sizeof because mybuf is a pointer, and not an array! */
n = x25xin( MYBUFLEN, mybuf );
} else
#endif /* IBMX25 */
n = read(fd, mybuf, sizeof(mybuf));
debug(F101,"SVORPOSIX myfillbuf","",n);
debug(F101,"SVORPOSIX myfillbuf ttcarr","",ttcarr);
debug(F101,"SVORPOSIX myfillbuf errno","",errno);
return(n);
#endif /* BEBOX */
#endif /* sxaE50 */
}
#else /* not AT&T or POSIX */
#ifdef aegis
/* This is quoted from the old myread(). The semantics seem to be
* alright, but maybe errno would not need to be set even when
* there is no error? I don't know aegis.
*/
int
myfillbuf() {
int count;
#ifdef NETCMD
if (ttpipe)
fd = fdin;
else
#endif /* NETCMD */
fd = ttyfd;
count = ios_$get((short)fd, ios_$cond_opt, mybuf, 256L, st);
errno = EIO;
if (st.all == ios_$get_conditional_failed) /* get at least one */
count = ios_$get((short)fd, 0, mybuf, 1L, st);
if (st.all == ios_$end_of_file)
return(0);
else if (st.all != status_$ok) {
errno = EIO;
return(-1);
}
return(count);
}
#else /* !aegis */
#ifdef FIONREAD
/* This is for systems with FIONREAD. FIONREAD returns the number
* of characters available for reading. If none are available, wait
* until something arrives, otherwise return all there is.
*/
int
myfillbuf() {
PEEKTYPE avail;
int x, fd;
#ifdef NETCMD
if (ttpipe)
fd = fdin;
else
#endif /* NETCMD */
fd = ttyfd;
#ifdef SUNX25
/*
SunLink X.25 support in this routine from Stefaan A. Eeckels, Eurostat (CEC).
Depends on SunOS having FIONREAD, not because we use it, but just so this
code is grouped correctly within the #ifdefs. Let's hope Solaris keeps it.
We call x25xin() instead of read() so that Q-Bit packets, which contain
X.25 service-level information (e.g. PAD parameter changes), can be processed
transparently to the upper-level code. This is a blocking read, and so
we depend on higher-level code (such as ttinc()) to set any necessary alarms.
*/
extern int nettype;
if (netconn && nettype == NET_SX25) {
while ((x = x25xin(sizeof(x25buf), x25buf)) < 1) ;
return(x - 1); /* "-1" compensates for extra status byte */
}
#endif /* SUNX25 */
errno = 0;
debug(F100,"myfillbuf calling FIONREAD ioctl","",0);
x = ioctl(fd, FIONREAD, &avail);
#ifdef DEBUG
if (deblog) {
debug(F101,"myfillbuf FIONREAD","",x);
debug(F101,"myfillbuf FIONREAD avail","",avail);
debug(F101,"myfillbuf FIONREAD errno","",errno);
}
#endif /* DEBUG */
if (x < 0 || avail == 0)
avail = 1;
if (avail > MYBUFLEN)
avail = MYBUFLEN;
errno = 0;
x = read(fd, mybuf, (int) avail);
#ifdef DEBUG
if (deblog) {
debug(F101,"myfillbuf avail","",avail);
debug(F101,"myfillbuf read","",x);
debug(F101,"myfillbuf read errno","",errno);
}
#endif /* DEBUG */
return(x);
}
#else /* !FIONREAD */
/* Add other systems here, between #ifdef and #else, e.g. NETCONN. */
/* When there is no other possibility, read 1 character at a time. */
int
myfillbuf() {
int x;
#ifdef NETCMD
if (ttpipe)
fd = fdin;
else
#endif /* NETCMD */
fd = ttyfd;
x = read(fd, mybuf, 1);
return(x);
}
#endif /* !FIONREAD */
#endif /* !aegis */
#endif /* !ATTSV */
#endif /* MYREAD */
#ifdef MINIX2
#undef MINIX
#endif /* MINIX2 */
/* T T F L U I -- Flush tty input buffer */
void
ttflux() {
#ifdef MYREAD
/*
Flush internal MYREAD buffer.
*/
debug(F101,"ttflux my_count","",my_count);
#ifdef CK_ENCRYPTION
if (u_encrypt && my_count > 0)
ck_krb_decrypt(&mybuf[my_item+1],my_count);
#endif /* CK_ENCRYPTION */
my_count = 0; /* Reset count to zero */
my_item = -1; /* And buffer index to -1 */
#endif /* MYREAD */
}
int
ttflui() {
int n, fd;
#ifdef NETCMD
if (ttpipe)
fd = fdin;
else
#endif /* NETCMD */
fd = ttyfd;
debug(F101,"ttflui ttpipe","",ttpipe);
#ifdef MYREAD
/*
Flush internal MYREAD buffer *FIRST*, in all cases.
*/
ttflux();
#endif /* MYREAD */
#ifdef NETCONN
/*
Network flush is done specially, in the network support module.
*/
if (netconn && !ttpipe) {
debug(F100,"ttflui netflui","",0);
return(netflui());
}
#endif /* NETCONN */
debug(F101,"ttflui ttyfd","",ttyfd);
if (ttyfd < 0) return(-1);
#ifdef aegis
sio_$control((short)yfd, sio_$flush_in, true, st);
if (st.all != status_$ok) {
fprintf(stderr, "flush failed: "); error_$print(st);
} else { /* sometimes the flush doesn't work */
for (;;) {
char buf[256];
/* eat all the characters that shouldn't be available */
ios_$get((short)fd, ios_$cond_opt, buf, 256L, st); /* (void) */
if (st.all == ios_$get_conditional_failed) break;
fprintf(stderr, "flush failed(2): "); error_$print(st);
}
}
#else
#ifdef BSD44 /* 4.4 BSD */
n = FREAD; /* Specify read queue */
debug(F100,"ttflui BSD44","",0);
ioctl(fd,TIOCFLUSH,&n);
#else
#ifdef Plan9
#undef POSIX /* Uh oh... */
#endif /* Plan9 */
#ifdef POSIX /* POSIX */
debug(F100,"ttflui POSIX","",0);
tcflush(fd,TCIFLUSH);
#else
#ifdef ATTSV /* System V */
#ifndef VXVE
debug(F100,"ttflui ATTSV","",0);
ioctl(fd,TCFLSH,0);
#endif /* VXVE */
#else /* Not BSD44, POSIX, or Sys V */
#ifdef TIOCFLUSH /* Those with TIOCFLUSH defined */
#ifdef ANYBSD /* Berkeley */
n = FREAD; /* Specify read queue */
debug(F100,"ttflui TIOCFLUSH ANYBSD","",0);
ioctl(fd,TIOCFLUSH,&n);
#else /* Others (V7, etc) */
debug(F100,"ttflui TIOCFLUSH","",0);
ioctl(fd,TIOCFLUSH,0);
#endif /* ANYBSD */
#else /* All others... */
/*
No system call (that we know about) for input buffer flushing.
So see how many there are and read them in a loop, using ttinc().
ttinc() is buffered, so we're not getting charged with a system call
per character, just a function call.
*/
if ((n = ttchk()) > 0) {
debug(F101,"ttflui read loop","",n);
while ((n--) && ttinc(0) > 0) ;
}
#endif /* TIOCFLUSH */
#endif /* ATTSV */
#endif /* POSIX */
#ifdef Plan9
#define POSIX
#endif /* Plan9 */
#endif /* BSD44 */
#endif /* aegis */
return(0);
}
int
ttfluo() { /* Flush output buffer */
int fd;
#ifdef NETCMD
if (ttpipe)
fd = fdout;
else
#endif /* NETCMD */
fd = ttyfd;
#ifdef Plan9
return 0;
#else
#ifdef POSIX
return(tcflush(fd,TCOFLUSH));
#else
#ifdef OXOS
return(ioctl(fd,TCFLSH,1));
#else
return(0); /* All others, nothing */
#endif /* OXOS */
#endif /* POSIX */
#endif /* Plan9 */
}
/* Interrupt Functions */
/* Set up terminal interrupts on console terminal */
#ifndef FIONREAD /* We don't need esctrp() */
#ifndef SELECT /* if we have any of these... */
#ifndef CK_POLL
#ifndef RDCHK
#ifndef OXOS
#ifdef SVORPOSIX
SIGTYP
esctrp(foo) int foo; { /* trap console escapes (^\) */
signal(SIGQUIT,SIG_IGN); /* ignore until trapped */
conesc = 1;
debug(F101,"esctrp caught SIGQUIT","",conesc);
}
#endif /* SVORPOSIX */
#endif /* OXOS */
#ifdef V7
#ifndef MINIX2
SIGTYP
esctrp(foo) int foo; { /* trap console escapes (^\) */
signal(SIGQUIT,SIG_IGN); /* ignore until trapped */
conesc = 1;
debug(F101,"esctrp caught SIGQUIT","",conesc);
}
#endif /* MINIX2 */
#endif /* V7 */
#ifdef C70
SIGTYP
esctrp(foo) int foo; { /* trap console escapes (^\) */
conesc = 1;
signal(SIGQUIT,SIG_IGN); /* ignore until trapped */
}
#endif /* C70 */
#endif /* RDCHK */
#endif /* CK_POLL */
#endif /* SELECT */
#endif /* FIONREAD */
/* C O N B G T -- Background Test */
static int jc = 0; /* 0 = no job control */
/*
Call with flag == 1 to prevent signal test, which can not be expected
to work during file transfer, when SIGINT probably *is* set to SIG_IGN.
Call with flag == 0 to use the signal test, but only if the process-group
test fails, as it does on some UNIX systems, where getpgrp() is buggy,
requires an argument when the man page says it doesn't, or vice versa.
If flag == 0 and the process-group test fails, then we determine background
status simply (but not necessarily reliably) from isatty().
conbgt() sets the global backgrd = 1 if we appear to be in the background,
and to 0 if we seem to be in the foreground. conbgt() is highly prone to
misbehavior.
*/
VOID
conbgt(flag) int flag; {
int x = -1, /* process group or SIGINT test */
y = 0; /* isatty() test */
/*
Check for background operation, even if not running on real tty, so that
background flag can be set correctly. If background status is detected,
then Kermit will not issue its interactive prompt or most messages.
If your prompt goes away, you can blame (and fix?) this function.
*/
/* Use process-group test if possible. */
#ifdef POSIX /* We can do it in POSIX */
#define PGROUP_T
#else
#ifdef BSD4 /* and in BSD 4.x. */
#define PGROUP_T
#else
#ifdef HPUXJOBCTL /* and in most HP-UX's */
#define PGROUP_T
#else
#ifdef TIOCGPGRP /* and anyplace that has this ioctl. */
#define PGROUP_T
#endif /* TIOCGPGRP */
#endif /* HPUXJOBCTL */
#endif /* BSD4 */
#endif /* POSIX */
#ifdef MIPS /* Except if it doesn't work... */
#undef PGROUP_T
#endif /* MIPS */
#ifdef PGROUP_T
/*
Semi-reliable process-group test. Check whether this process's group is
the same as the controlling terminal's process group. This works if the
getpgrp() call doesn't lie (as it does in the SUNOS System V environment).
*/
PID_T mypgrp = (PID_T)0; /* Kermit's process group */
PID_T ctpgrp = (PID_T)0; /* The terminal's process group */
#ifndef _POSIX_SOURCE
/*
The getpgrp() prototype is obtained from system header files for POSIX
and Sys V R4 compilations. Other systems, who knows. Some complain about
a duplicate declaration here, others don't, so it's safer to leave it in
if we don't know for certain.
*/
#ifndef SVR4
#ifndef PS2AIX10
extern PID_T getpgrp();
#endif /* PS2AIX10 */
#endif /* SVR4 */
#endif /* _POSIX_SOURCE */
/* Get my process group. */
#ifdef SVR3 /* Maybe this should be ATTSV? */
/* This function is not described in SVID R2 */
mypgrp = getpgrp();
debug(F101,"ATTSV conbgt process group","",(int) mypgrp);
#else
#ifdef POSIX
mypgrp = getpgrp();
debug(F101,"POSIX conbgt process group","",(int) mypgrp);
#else
#ifdef OSFPC
mypgrp = getpgrp();
debug(F101,"OSF conbgt process group","",(int) mypgrp);
#else
#ifdef QNX
mypgrp = getpgrp();
debug(F101,"QNX conbgt process group","",(int) mypgrp);
#else
#ifdef OSF32 /* (was OSF40) */
mypgrp = getpgrp();
debug(F101,"Digital UNIX conbgt process group","",(int) mypgrp);
#else /* BSD, V7, etc */
#ifdef MINIX2
mypgrp = getpgrp();
#else
mypgrp = getpgrp(0);
#endif /* MINIX2 */
debug(F101,"BSD conbgt process group","",(int) mypgrp);
#endif /* OSF32 */
#endif /* QNX */
#endif /* OSFPC */
#endif /* POSIX */
#endif /* SVR3 */
#ifdef MINIX2
#undef BSD44ORPOSIX
#endif /* MINIX2 */
/* Now get controlling tty's process group */
#ifdef BSD44ORPOSIX
ctpgrp = tcgetpgrp(1); /* The POSIX way */
debug(F101,"POSIX conbgt terminal process group","",(int) ctpgrp);
#else
ioctl(1, TIOCGPGRP, &ctpgrp); /* Or the BSD way */
debug(F101,"non-POSIX conbgt terminal process group","",(int) ctpgrp);
#endif /* BSD44ORPOSIX */
#ifdef MINIX2
#define BSD44ORPOSIX
#endif /* MINIX2 */
if ((mypgrp > (PID_T) 0) && (ctpgrp > (PID_T) 0))
x = (mypgrp == ctpgrp) ? 0 : 1; /* If they differ, then background. */
else x = -1; /* If error, remember. */
debug(F101,"conbgt process group test","",x);
#endif /* PGROUP_T */
/* Try to see if job control is available */
#ifdef NOJC /* User override */
jc = 0; /* No job control allowed */
debug(F111,"NOJC","jc",jc);
#else
#ifdef BSD44
jc = 1;
#else
#ifdef SVR4ORPOSIX /* POSIX actually tells us */
debug(F100,"SVR4ORPOSIX jc test...","",0);
#ifdef _SC_JOB_CONTROL
#ifdef __bsdi__
jc = 1;
#else
#ifdef __386BSD__
jc = 1;
#else
jc = sysconf(_SC_JOB_CONTROL); /* Whatever system says */
if (jc < 0) {
debug(F101,"sysconf fails, jcshell","",jcshell);
jc = (jchdlr == SIG_DFL) ? 1 : 0;
} else
debug(F111,"sysconf(_SC_JOB_CONTROL)","jc",jc);
#endif /* __386BSD__ */
#endif /* __bsdi__ */
#else
#ifdef _POSIX_JOB_CONTROL
jc = 1; /* By definition */
debug(F111,"_POSIX_JOB_CONTROL is defined","jc",jc);
#else
jc = 0; /* Assume job control not allowed */
debug(F111,"SVR4ORPOSIX _SC/POSIX_JOB_CONTROL not defined","jc",jc);
#endif /* _POSIX_JOB_CONTROL */
#endif /* _SC_JOB_CONTROL */
#else
#ifdef BSD4
jc = 1; /* Job control allowed */
debug(F111,"BSD job control","jc",jc);
#else
#ifdef SVR3JC
jc = 1; /* JC allowed */
debug(F111,"SVR3 job control","jc",jc);
#else
#ifdef OXOS
jc = 1; /* JC allowed */
debug(F111,"X/OS job control","jc",jc);
#else
#ifdef HPUX9
jc = 1; /* JC allowed */
debug(F111,"HP-UX 9.0 job control","jc",jc);
#else
#ifdef HPUX10
jc = 1; /* JC allowed */
debug(F111,"HP-UX 10.0 job control","jc",jc);
#else
jc = 0; /* JC not allowed */
debug(F111,"job control catch-all","jc",jc);
#endif /* HPUX10 */
#endif /* HPUX9 */
#endif /* OXOS */
#endif /* SVR3JC */
#endif /* BSD4 */
#endif /* SVR4ORPOSIX */
#endif /* BSD44 */
#endif /* NOJC */
debug(F101,"conbgt jc","",jc);
#ifndef NOJC
debug(F101,"conbgt jcshell","",jcshell);
/*
At this point, if jc == 1 but jcshell == 0, it means that the OS supports
job control, but the shell or other process we are running under does not
(jcshell is set in sysinit()) and so if we suspend ourselves, nothing good
will come of it. So...
*/
if (jc < 0) jc = 0;
if (jc > 0 && jcshell == 0) jc = 0;
#endif /* NOJC */
/*
Another background test.
Test if SIGINT (terminal interrupt) is set to SIG_IGN (ignore),
which is done by the shell (sh) if the program is started with '&'.
Unfortunately, this is NOT done by csh or ksh so watch out!
Note, it's safe to set SIGINT to SIG_IGN here, because further down
we always set it to something else.
*/
if (x < 0 && !flag) { /* Didn't get good results above... */
SIGTYP (*osigint)();
osigint = signal(SIGINT,SIG_IGN); /* What is SIGINT set to? */
x = (osigint == SIG_IGN) ? 1 : 0; /* SIG_IGN? */
debug(F101,"conbgt osigint","",osigint);
debug(F101,"conbgt signal test","",x);
}
/* Also check to see if we're running with redirected stdio. */
/* This is not really background operation, but we want to act as though */
/* it were. */
y = (isatty(0) && isatty(1)) ? 1 : 0;
debug(F101,"conbgt isatty test","",y);
#ifdef BSD29
/* The process group and/or signal test doesn't work under these... */
backgrd = !y;
#else
#ifdef sxaE50
backgrd = !y;
#else
#ifdef MINIX
backgrd = !y;
#else
#ifdef MINIX2
backgrd = !y;
#else
if (x > -1)
backgrd = (x || !y) ? 1 : 0;
else backgrd = !y;
#endif /* BSD29 */
#endif /* sxaE50 */
#endif /* MINIX */
#endif /* MINIX2 */
debug(F101,"conbgt backgrd","",backgrd);
}
/* C O N I N T -- Console Interrupt setter */
/*
First arg is pointer to function to handle SIGTERM & SIGINT (like Ctrl-C).
Second arg is pointer to function to handle SIGTSTP (suspend).
*/
VOID /* Set terminal interrupt traps. */
#ifdef CK_ANSIC
#ifdef apollo
conint(f,s) SIGTYP (*f)(), (*s)();
#else
conint(SIGTYP (*f)(int), SIGTYP (*s)(int))
#endif /* apollo */
#else
conint(f,s) SIGTYP (*f)(), (*s)();
#endif /* CK_ANSIC */
/* conint */ {
conbgt(0); /* Do background test. */
/* Set the desired handlers for hangup and software termination. */
signal(SIGTERM,f); /* Software termination */
#ifdef COMMENT
/*
Prior to edit 184, we used to trap SIGHUP here. That is clearly wrong;
on some systems, it would leave the user's process on the terminal after
the phone hung up. But the trap was here for a reason: most likely some
UNIX systems (init, getty, or login) fail to properly restore the terminal
modes after regaining control of a hung-up-upon login terminal. Therefore
removing this trap is likely to cause problems too. A more sensible
approach would be to use a special handler for HANGUP, which would restore
the terminal modes and then exit(). But that could leave zombie processes
around (like the lower CONNECT fork, or any fork started by zxcmd()), but
there is probably no clean, portable, reliable way for Kermit to kill all
its forks. So we just exit() and hope that UNIX fixes the terminal modes
before the next person tries to log in.
*/
signal(SIGHUP,f); /* Hangup */
#endif /* COMMENT */
/* Now handle keyboard stop, quit, and interrupt signals. */
/* Check if invoked in background -- if so signals set to be ignored. */
/* However, if running under a job control shell, don't ignore them. */
/* We won't be getting any, as we aren't in the terminal's process group. */
debug(F101,"conint backgrd","",backgrd);
debug(F101,"conint jc","",jc);
if (backgrd && !jc) { /* In background, ignore signals */
debug(F101,"conint background ignoring signals, jc","",jc);
#ifdef SIGTSTP
signal(SIGTSTP,SIG_IGN); /* Keyboard stop */
#endif /* SIGTSTP */
signal(SIGQUIT,SIG_IGN); /* Keyboard quit */
signal(SIGINT,SIG_IGN); /* Keyboard interrupt */
} else { /* Else in foreground or suspended */
debug(F101,"conint foreground catching signals, jc","",jc);
signal(SIGINT,f); /* Catch terminal interrupt */
#ifdef SIGTSTP /* Keyboard stop (suspend) */
debug(F101,"conint SIGSTSTP","",s);
if (s == NULL) s = SIG_DFL;
#ifdef NOJC /* No job control allowed. */
signal(SIGTSTP,SIG_IGN);
#else /* Job control allowed */
if (jc) /* if available. */
signal(SIGTSTP,s);
else
signal(SIGTSTP,SIG_IGN);
#endif /* NOJC */
#endif /* SIGTSTP */
#ifndef OXOS
#ifdef SVORPOSIX
#ifndef FIONREAD /* Watch out, we don't know this... */
#ifndef SELECT
#ifndef CK_POLL
#ifndef RDCHK
signal(SIGQUIT,esctrp); /* Quit signal, Sys III/V. */
#endif /* RDCHK */
#endif /* CK_POLL */
#endif /* SELECT */
#endif /* FIONREAD */
if (conesc) conesc = 0; /* Clear out pending escapes */
#else
#ifdef V7
signal(SIGQUIT,esctrp); /* V7 like Sys III/V */
if (conesc) conesc = 0;
#else
#ifdef aegis
signal(SIGQUIT,f); /* Apollo, catch it like others. */
#else
signal(SIGQUIT,SIG_IGN); /* Others, ignore like 4D & earlier. */
#endif /* aegis */
#endif /* V7 */
#endif /* SVORPOSIX */
#endif /* OXOS */
}
}
/* C O N N O I -- Reset console terminal interrupts */
SIGTYP /* Dummy function to ignore signals */
#ifdef CK_ANSIC
sig_ign(int foo)
#else
sig_ign(foo) int foo;
#endif /* CK_ANSIC */
/* sig_IGN */ { /* Just like the real one, but has */
} /* different address. */
VOID
connoi() { /* Console-no-interrupts */
debug(F100,"connoi","",0);
#ifdef SIGTSTP
signal(SIGTSTP,SIG_DFL);
#endif /* SIGTSTP */
/* Note the locally defined replacement for SIG_IGN that is used here */
/* for the SIGINT setting. This is done so that the Sys V background */
/* test -- (signal(SIGINT,SIG_IGN) == SIG_IGN) -- can work. If we use */
/* the real SIG_IGN here, then conint will always decide that this */
/* program is running in the background! */
signal(SIGINT,sig_ign); /* <--- note! */
signal(SIGHUP,SIG_DFL);
signal(SIGQUIT,SIG_IGN);
signal(SIGTERM,SIG_IGN);
}
/* I N I T R A W Q -- Set up to read /dev/kmem for character count. */
#ifdef V7
/*
Used in Version 7 to simulate Berkeley's FIONREAD ioctl call. This
eliminates blocking on a read, because we can read /dev/kmem to get the
number of characters available for raw input. If your system can't
or you won't let the world read /dev/kmem then you must figure out a
different way to do the counting of characters available, or else replace
this by a dummy function that always returns 0.
*/
/*
* Call this routine as: initrawq(tty)
* where tty is the file descriptor of a terminal. It will return
* (as a char *) the kernel-mode memory address of the rawq character
* count, which may then be read. It has the side-effect of flushing
* input on the terminal.
*/
/*
* John Mackin, Physiology Dept., University of Sydney (Australia)
* ...!decvax!mulga!physiol.su.oz!john
*
* Permission is hereby granted to do anything with this code, as
* long as this comment is retained unmodified and no commercial
* advantage is gained.
*/
#ifndef MINIX
#ifndef MINIX2
#ifndef COHERENT
#include <a.out.h>
#include <sys/proc.h>
#endif /* COHERENT */
#endif /* MINIX2 */
#endif /* MINIX */
#ifdef COHERENT
#include <l.out.h>
#include <sys/proc.h>
#endif /* COHERENT */
char *
initrawq(tty) int tty; {
#ifdef MINIX
return(0);
#else
#ifdef MINIX2
return(0);
#else
#ifdef UTS24
return(0);
#else
#ifdef BSD29
return(0);
#else
long lseek();
static struct nlist nl[] = {
{PROCNAME},
{NPROCNAME},
{""}
};
static struct proc *pp;
char *qaddr, *p, c;
int m;
PID_T pid, me;
NPTYPE xproc; /* Its type is defined in makefile. */
int catch();
me = getpid();
if ((m = open("/dev/kmem", 0)) < 0) err("kmem");
nlist(BOOTNAME, nl);
if (nl[0].n_type == 0) err("proc array");
if (nl[1].n_type == 0) err("nproc");
lseek(m, (long)(nl[1].n_value), 0);
read (m, &xproc, sizeof(xproc));
saval = signal(SIGALRM, catch);
if ((pid = fork()) == 0) {
while(1)
read(tty, &c, 1);
}
alarm(2);
if(setjmp(jjbuf) == 0) {
while(1)
read(tty, &c, 1);
}
signal(SIGALRM, SIG_DFL);
#ifdef DIRECT
pp = (struct proc *) nl[0].n_value;
#else
if (lseek(m, (long)(nl[0].n_value), 0) < 0L) err("seek");
if (read(m, &pp, sizeof(pp)) != sizeof(pp)) err("no read of proc ptr");
#endif
lseek(m, (long)(nl[1].n_value), 0);
read(m, &xproc, sizeof(xproc));
if (lseek(m, (long)pp, 0) < 0L) err("Can't seek to proc");
if ((p = malloc(xproc * sizeof(struct proc))) == NULL) err("malloc");
if (read(m,p,xproc * sizeof(struct proc)) != xproc*sizeof(struct proc))
err("read proc table");
for (pp = (struct proc *)p; xproc > 0; --xproc, ++pp) {
if (pp -> p_pid == (short) pid) goto iout;
}
err("no such proc");
iout:
close(m);
qaddr = (char *)(pp -> p_wchan);
free (p);
kill(pid, SIGKILL);
wait((WAIT_T *)0);
return (qaddr);
#endif
#endif
#endif
#endif
}
/* More V7-support functions... */
static VOID
err(s) char *s; {
char buf[200];
sprintf(buf, "fatal error in initrawq: %s", s);
perror(buf);
doexit(1,-1);
}
static VOID
catch(foo) int foo; {
longjmp(jjbuf, -1);
}
/* G E N B R K -- Simulate a modem break. */
#ifdef MINIX
#define BSPEED B110
#else
#ifdef MINIX2
#define BSPEED B110
#else
#define BSPEED B150
#endif /* MINIX2 */
#endif /* MINIX */
#ifndef MINIX2
VOID
genbrk(fn,msec) int fn, msec; {
struct sgttyb ttbuf;
int ret, sospeed, x, y;
ret = ioctl(fn, TIOCGETP, &ttbuf);
sospeed = ttbuf.sg_ospeed;
ttbuf.sg_ospeed = BSPEED;
ret = ioctl(fn, TIOCSETP, &ttbuf);
y = (int)strlen(brnuls);
x = ( BSPEED * 100 ) / msec;
if (x > y) x = y;
ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
ttbuf.sg_ospeed = sospeed;
ret = ioctl(fn, TIOCSETP, &ttbuf);
ret = write(fn, "@", 1);
return;
}
#endif /* MINIX2 */
#ifdef MINIX2
int
genbrk(fn,msec) int fn, msec; {
struct termios ttbuf;
int ret, x, y;
speed_t sospeed;
ret = tcgetattr(fn, &ttbuf);
sospeed = ttbuf.c_ospeed;
ttbuf.c_ospeed = BSPEED;
ret = tcsetattr(fn,TCSADRAIN, &ttbuf);
y = (int)strlen(brnuls);
x = ( BSPEED * 100 ) / msec;
if (x > y) x = y;
ret = write(fn, brnuls, (( BSPEED * 100 ) / msec ));
ttbuf.c_ospeed = sospeed;
ret = tcsetattr(fn, TCSADRAIN, &ttbuf);
ret = write(fn, "@", 1);
return ret;
}
#endif /* MINIX2 */
#endif /* V7 */
/*
I N C H K -- Check if chars waiting to be read on given file descriptor.
This routine is a merger of ttchk() and conchk().
Call with:
channel == 0 to check console.
channel == 1 to check communications connection.
and:
fd = file descriptor.
Returns:
>= 0: number of characters waiting, 0 or greater,
0: on any kind of error,
-2: if there is (definitely) no connection.
Note: In UNIX we don't have to call nettchk() because a socket
file descriptor works just like in serial i/o, ioctls and all.
(But this will change if we add non-file-descriptor channels,
such as IBM X.25 for AIX...)
*/
static int
in_chk(channel, fd) int channel, fd; {
int x, n = 0; /* Workers, n = return value */
/*
The first section checks to make sure we have a connection,
but only if we're in local mode.
*/
#ifdef DEBUG
if (deblog) {
char buf[16];
sprintf(buf,"%d",fd); /* File descriptor */
debug(F111,"in_chk entry",buf,channel);
}
#endif /* DEBUG */
if (channel && xlocal) {
if (ttyfd < 0) { /* No connection */
return(-2); /* That's what this means */
} else if (!netconn /* Serial connection */
&& ttcarr != CAR_OFF /* with CARRIER WATCH ON (or AUTO) */
#ifdef COMMENT
#ifdef MYREAD
/*
Seems like this would be a good idea but it prevents C-Kermit from
popping back to the prompt automatically when carrier drops. However,
commenting this out prevents us from seeing the NO CARRIER message.
Needs more work...
*/
&& my_count < 1 /* Nothing in our internal buffer */
#endif /* MYREAD */
#endif /* COMMENT */
) {
int x;
x = ttgmdm(); /* So get modem signals */
if (x > -1) { /* Check for carrier */
if (!(x & BM_DCD)) { /* No carrier */
debug(F101,"in_chk carrier lost","",x);
return(-2); /* This means "disconnected" */
}
}
}
}
/* We seem to have a connection so now see if any bytes are waiting on it */
errno = 0; /* Reset this so we log good info */
#ifdef FIONREAD
x = ioctl(fd, FIONREAD, &n); /* BSD and lots of others */
#ifdef DEBUG /* (the more the better) */
if (deblog) {
debug(F101,"in_chk FIONREAD return code","",x);
debug(F101,"in_chk FIONREAD count","",n);
debug(F101,"in_chk FIONREAD errno","",errno);
}
#endif /* DEBUG */
#else /* FIONREAD not defined */
/*
Here, if (netconn && ttnet == NET_TCPB), we might try calling recvmsg()
with flags MSG_PEEK|MSG_DONTWAIT on the socket (ttyfd), except this is not
portable (MSG_DONTWAIT isn't defined in any of the <sys/socket.h> files
that I looked at, but it is needed to prevent the call from blocking), and
the msghdr struct differs from place to place, so we would need another
avalanche of ifdefs. Still, when FIONREAD is not available, this is the
only other known method of asking the OS for the *number* of characters
available for reading.
*/
#ifdef V7 /* UNIX V7: look in kernel memory */
#ifdef MINIX
n = 0; /* But not in MINIX */
#else
#ifdef MINIX2
n = 0;
#else
lseek(kmem[TTY], (long) qaddr[TTY], 0); /* 7th Edition Unix */
x = read(kmem[TTY], &n, sizeof(int));
if (x != sizeof(int))
n = 0;
#endif /* MINIX2 */
#endif /* MINIX */
#else /* Not V7 */
#ifdef PROVX1
x = ioctl(fd, TIOCQCNT, &ttbuf); /* DEC Pro/3xx Venix V.1 */
n = ttbuf.sg_ispeed & 0377; /* Circa 1984 */
if (x < 0) n = 0;
#else
#ifdef MYREAD
/*
Here we skip all the undependable and expensive calls below if we
already have something in our internal buffer. This tends to work quite
nicely, so the only really bad case remaining is the one in which neither
FIONREAD or MYREAD are defined, which is increasingly rare these days.
*/
if (channel != 0 && my_count > 0) {
debug(F101,"in_chk buf my_count","",my_count);
n = my_count; /* n was 0 before we got here */
return(n);
}
#endif /* MYREAD */
/*
rdchk(), select(), and poll() tell us *if* data is available to be read, but
not how much, so these should be used only as a final resort. Especially
since these calls tend to add a lot overhead.
*/
#ifdef RDCHK /* This mostly SCO-specific */
n = rdchk(fd);
debug(F101,"in_chk rdchk","",n);
#else /* No RDCHK */
#ifdef SELECT
#ifdef Plan9
/* Only allows select on the console ... don't ask */
if (channel == 0)
#endif /* Plan9 */
{
fd_set rfds; /* Read file descriptors */
#ifdef BELLV10
FD_ZERO(rfds); /* Initialize them */
FD_SET(fd,rfds); /* We want to look at this fd */
#else
FD_ZERO(&rfds); /* Initialize them */
FD_SET(fd,&rfds); /* We want to look at this fd */
tv.tv_sec = tv.tv_usec = 0L; /* A 0-valued timeval structure */
#endif /* BELLV10 */
#ifdef Plan9
n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"in_chk Plan 9 select","",n);
#else
#ifdef BELLV10
n = select( 128, rfds, (fd_set *)0, (fd_set *)0, 0 );
debug(F101,"in_chk BELLV10 select","",n);
#else
#ifdef BSD44
n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"in_chk BSD44 select","",n);
#else
#ifdef BSD43
n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"in_chk BSD43 select","",n);
#else
#ifdef SOLARIS
n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"in_chk SOLARIS select","",n);
#else
#ifdef QNX
n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"in_chk QNX select","",n);
#else
#ifdef COHERENT
n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"in_chk COHERENT select","",n);
#else
#ifdef SVR4
n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"in_chk SVR4 select","",n);
#else
#ifdef __linux__
n = select( FD_SETSIZE, &rfds, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"in_chk LINUX select","",n);
#else
n = select( FD_SETSIZE, &rfds, (int *)0, (int *)0, &tv );
debug(F101,"in_chk catchall select","",n);
#endif /* __linux__ */
#endif /* SVR4 */
#endif /* COHERENT */
#endif /* QNX */
#endif /* SOLARIS */
#endif /* BSD43 */
#endif /* BSD44 */
#endif /* BELLV10 */
#endif /* Plan9 */
}
#else /* Not SELECT */
#ifdef CK_POLL
{
struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLIN;
pfd.revents = 0;
n = poll(&pfd, 1, 0);
debug(F101,"in_chk poll","",n);
if ((n > 0) && (pfd.revents & POLLIN))
n = 1;
}
#endif /* CK_POLL */
#endif /* SELECT */
#endif /* RDCHK */
#endif /* PROVX1 */
#endif /* V7 */
#endif /* FIONREAD */
/* From here down, treat console and communication device differently... */
if (channel == 0) { /* Console */
#ifdef SVORPOSIX
#ifndef FIONREAD
#ifndef SELECT
#ifndef CK_POLL
#ifndef RDCHK
/*
This is the hideous hack used in System V and POSIX systems that don't
support FIONREAD, rdchk(), select(), poll(), etc, in which the user's
CONNECT-mode escape character is attached to SIGQUIT. Used, obviously,
only on the console.
*/
if (conesc) { /* Escape character typed == SIGQUIT */
debug(F100,"in_chk conesc","",conesc);
conesc = 0;
signal(SIGQUIT,esctrp); /* Restore signal */
n += 1;
}
#endif /* RDCHK */
#endif /* CK_POLL */
#endif /* SELECT */
#endif /* FIONREAD */
#endif /* SVORPOSIX */
return(n); /* Done with console */
}
if (channel != 0) { /* Communications connection */
#ifdef MYREAD
#ifndef FIONREAD
/*
select() or rdchk(), etc, has told us that something is waiting, but we
don't know how much. So we do a read to get it and then we know. Note:
This read is NOT nonblocking if nothing is there (because of VMIN=1), but
it should be safe in this case since the OS tells us at least one byte is
waiting to be read, and MYREAD reads return as much as is there without
waiting for any more. Controlled tests on Solaris and Unixware (with
FIONREAD deliberately undefined) show this to be true.
*/
debug(F101,"in_chk read my_count","",my_count);
debug(F101,"in_chk read n","",n);
if (n > 0 && my_count == 0) {
/* This also catches disconnects etc */
/* Do what mygetbuf does except don't grab a character */
my_count = myfillbuf();
my_item = -1; /* ^^^ */
debug(F101,"in_chk myfillbuf my_count","",my_count);
if (my_count < 0)
return(-1);
else
n = 0; /* NB: n is replaced by my_count */
}
#endif /* FIONREAD */
/*
Here we add whatever we think is unread to what is still in our
our internal buffer. Thus the importance of setting n to 0 just above.
*/
debug(F101,"in_chk my_count","",my_count);
debug(F101,"in_chk n","",n);
if (my_count > 0)
n += my_count;
#endif /* MYREAD */
}
debug(F101,"in_chk result","",n);
/* Errors here don't prove the connection has dropped so just say 0 */
return(n < 0 ? 0 : n);
}
/* T T C H K -- Tell how many characters are waiting in tty input buffer */
int
ttchk() {
int fd;
#ifdef NETCMD
if (ttpipe)
fd = fdin;
else
#endif /* NETCMD */
fd = ttyfd;
return(in_chk(1,fd));
}
/* T T X I N -- Get n characters from tty input buffer */
/* Returns number of characters actually gotten, or -1 on failure */
/* Intended for use only when it is known that n characters are actually */
/* Available in the input buffer. */
int
ttxin(n,buf) int n; CHAR *buf; {
register int x = 0, c = -2;
char cc;
int fd;
if (n < 1) /* Nothing to do */
return(0);
#ifdef NETCMD
if (ttpipe)
fd = fdin;
else
#endif /* NETCMD */
fd = ttyfd;
#ifdef SUNX25
if (netconn && (ttnet == NET_SX25)) /* X.25 connection */
return(x25xin(n,buf));
#endif /* SUNX25 */
#ifdef IBMX25
/* riehm: possibly not needed. Test worked with normal reads and writes */
if (netconn && (ttnet == NET_IX25)) { /* X.25 connection */
x = x25xin(n,buf);
if (x > 0) buf[x] = '\0';
return(x);
}
#endif /* IBMX25 */
#ifdef MYREAD
debug(F101,"ttxin MYREAD","",n);
while (x < n) {
c = myread();
if (c < 0) {
debug(F101,"ttxin myread returns","",c);
if (c == -3) x = -1;
break;
}
buf[x++] = c & ttpmsk;
}
#else
debug(F101,"ttxin READ","",n);
x = read(fd,buf,n);
for (c = 0; c < n; c++) /* Strip any parity */
buf[c] &= ttpmsk;
#endif /* MYREAD */
debug(F101,"ttxin x","",x); /* Done */
if (x > 0) buf[x] = '\0';
if (x < 0) x = -1;
return(x);
}
/* T T O L -- Write string s, length n, to communication device. */
/*
Returns:
>= 0 on success, number of characters actually written.
-1 on failure.
*/
#ifdef CK_ENCRYPTION
CHAR xpacket[10240];
#endif /* CK_ENCRYPTION */
#define TTOLMAXT 5
int
ttol(s,n) int n; CHAR *s; {
int x, len, tries, fd;
#ifdef CKXXCHAR
extern int dblflag; /* For SET SEND DOUBLE-CHARACTER */
extern short dblt[];
CHAR *p = NULL, *p2, *s2, c;
int n2 = 0;
#endif /* CKXXCHAR */
if (ttyfd < 0) /* Not open? */
return(-3);
debug(F101,"ttol n","",n);
debug(F110,"ttol s",s,0);
#ifdef NETCMD
if (ttpipe)
fd = fdout;
else
#endif /* NETCMD */
fd = ttyfd;
#ifdef CKXXCHAR
/* Double any characters that must be doubled. */
debug(F101,"ttol dblflag","",dblflag);
if (dblflag) {
p = (CHAR *) malloc(n + n + 1);
if (p) {
s2 = s;
p2 = p;
n2 = 0;
while (*s2) {
c = *s2++;
*p2++ = c;
n2++;
if (dblt[(unsigned) c] & 2) {
*p2++ = c;
n2++;
}
}
s = p;
n = n2;
}
}
#endif /* CKXXCHAR */
tries = TTOLMAXT; /* Allow up to this many tries */
len = n; /* Remember original length */
#ifdef CK_ENCRYPTION
/*
This is to avoid encrypting a packet that is already encrypted, e.g.
when we resend a packet directly out of the packet buffer.
*/
if (me_encrypt) {
memcpy((char *)xpacket,(char *)s,n);
s = xpacket;
ck_krb_encrypt((char *)s,n);
}
#endif /* CK_ENCRYPTION */
while (n > 0 && tries-- > 0) { /* Be persistent */
debug(F101,"ttol try","",TTOLMAXT - tries);
#ifdef BEBOX
if (netconn && !ttpipe)
x = nettol((char *)s,n); /* Write string to device */
else
#endif /* BEBOX */
#ifdef IBMX25
if (ttnet == NET_IX25)
/*
* this is a more controlled way of writing to X25
* STREAMS, however write should also work!
*/
x = x25write(ttyfd, s, n);
else
#endif /* IBMX25 */
x = write(fd,s,n); /* Write string to device */
if (x == n) { /* Worked? */
debug(F101,"ttol ok","",x); /* OK */
#ifdef CKXXCHAR
if (p) free(p);
#endif /* CKXXCHAR */
return(len); /* Done */
} else if (x < 0) { /* No, got error? */
debug(F101,"ttol write error","",errno);
#ifdef EWOULDBLOCK
if (errno == EWOULDBLOCK) {
msleep(10);
continue;
} else
#endif /* EWOULDBLOCK */
#ifdef TCPSOCKET
if (netconn && ttnet == NET_TCPB) {
debug(F101,"ttol TCP error","",errno);
ttclos(0); /* Close the connection. */
x = -3;
}
#endif /* TCPSOCKET */
#ifdef CKXXCHAR
if (p) free(p);
#endif /* CKXXCHAR */
return(x);
} else { /* No error, so partial success */
debug(F101,"ttol partial","",x); /* This never happens */
s += x; /* Point to part not written yet */
n -= x; /* Adjust length */
if (x > 0) msleep(10); /* Wait 10 msec */
} /* Go back and try again */
}
#ifdef CKXXCHAR
if (p) free(p);
#endif /* CKXXCHAR */
return(n < 1 ? len : -1); /* Return the results */
}
/* T T O C -- Output a character to the communication line */
/*
This function should only be used for interactive, character-mode operations,
like terminal connection, script execution, dialer i/o, where the overhead
of the signals and alarms does not create a bottleneck.
*/
int
#ifdef CK_ANSIC
ttoc(char c)
#else
ttoc(c) char c;
#endif /* CK_ANSIC */
/* ttoc */ {
#define TTOC_TMO 15 /* Timeout in case we get stuck */
int xx, fd;
if (ttyfd < 0) /* Check for not open. */
return(-1);
#ifdef NETCMD
if (ttpipe)
fd = fdout;
else
#endif /* NETCMD */
fd = ttyfd;
c &= 0xff;
/* debug(F101,"ttoc","",(CHAR) c); */
saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
xx = alarm(TTOC_TMO); /* for this many seconds. */
if (xx < 0) xx = 0; /* Save old alarm value. */
/* debug(F101,"ttoc alarm","",xx); */
if (
#ifdef CK_POSIX_SIG
sigsetjmp(sjbuf,1)
#else
setjmp(sjbuf)
#endif /* CK_POSIX_SIG */
) { /* Timer went off? */
ttimoff(); /* Yes, cancel this alarm. */
if (xx - TTOC_TMO > 0) alarm(xx - TTOC_TMO); /* Restore previous one */
/* debug(F100,"ttoc timeout","",0); */
#ifdef NETCONN
if (!netconn) {
#endif /* NETCONN */
debug(F101,"ttoc timeout","",c);
if (ttflow == FLO_XONX) {
debug(F101,"ttoc flow","",ttflow); /* Maybe we're xoff'd */
#ifndef Plan9
#ifdef POSIX
/* POSIX way to unstick. */
debug(F100,"ttoc tcflow","",tcflow(ttyfd,TCOON));
#else
#ifdef BSD4 /* Berkeley way to do it. */
#ifdef TIOCSTART
/* .... Used to be "ioctl(ttyfd, TIOCSTART, 0);". Who knows? */
{
int x = 0;
debug(F101,"ttoc TIOCSTART","",ioctl(ttyfd, TIOCSTART, &x));
}
#endif /* TIOCSTART */
#endif /* BSD4 */
/* Is there a Sys V way to do this? */
#endif /* POSIX */
#endif /* Plan9 */
}
#ifdef NETCONN
}
#endif /* NETCONN */
return(-1); /* Return failure code. */
} else {
int ret_code;
#ifdef BEBOX
#ifdef NETCONN
if (netconn && !ttpipe)
ret_code = nettoc(c);
else
#endif /* BEBOX */
#endif /* NETCONN */
#ifdef CK_ENCRYPTION
{
if (me_encrypt)
ck_krb_encrypt(&c,1);
}
#endif /* CK_ENCRYPTION */
#ifdef IBMX25
/* riehm: maybe this isn't necessary after all. Test program
* worked fine with data being sent and retrieved with normal
* read's and writes!
*/
if (ttnet == NET_IX25)
ret_code = x25write(ttyfd,&c,1); /* as above for X25 streams */
else
#endif /* IBMX25 */
ret_code = write(fd,&c,1); /* Try to write the character. */
if (ret_code < 1) { /* Failed */
ttimoff(); /* Turn off the alarm. */
alarm(xx); /* Restore previous alarm. */
debug(F101,"ttoc error","",errno); /* Log the error, */
return(-1); /* and return the error code. */
}
}
ttimoff(); /* Success, turn off the alarm. */
alarm(xx); /* Restore previous alarm. */
return(0); /* Return good code. */
}
/* T T I N L -- Read a record (up to break character) from comm line. */
/*
Reads up to "max" characters from the communication line, terminating on:
(a) the packet length field if the "turn" argument is zero, or
(b) on the packet-end character (eol) if the "turn" argument is nonzero
(c) a certain number of Ctrl-C's in a row
and returns the number of characters read upon success, or if "max" was
exceeded or the timeout interval expired before (a) or (b), returns -1.
The characters that were input are copied into "dest" with their parity bits
stripped if parity was selected. Returns the number of characters read.
Characters after the eol are available upon the next call to this function.
The idea is to minimize the number of system calls per packet, and also to
minimize timeouts. This function is the inner loop of the program and must
be as efficient as possible. The current strategy is to use myread().
WARNING: this function calls parchk(), which is defined in another module.
Normally, ckutio.c does not depend on code from any other module, but there
is an exception in this case because all the other ck?tio.c modules also
need to call parchk(), so it's better to have it defined in a common place.
Since this function has grown to have its fingers so deeply into the
protocol, it is slated for removal: rpack() should take care of everything.
*/
#ifdef CTRLC
#undef CTRLC
#endif /* CTRLC */
#define CTRLC '\03'
/*
We have four different declarations here because:
(a) to allow Kermit to be built without the automatic parity sensing feature
(b) one of each type for ANSI C, one for non-ANSI.
*/
static int csave = -1;
int
#ifdef PARSENSE
#ifdef CK_ANSIC
ttinl(CHAR *dest, int max,int timo, CHAR eol, CHAR start, int turn)
#else
ttinl(dest,max,timo,eol,start,turn) int max,timo,turn; CHAR *dest, eol, start;
#endif /* CK_ANSIC */
#else /* not PARSENSE */
#ifdef CK_ANSIC
ttinl(CHAR *dest, int max,int timo, CHAR eol)
#else
ttinl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
#endif /* __SDTC__ */
#endif /* PARSENSE */
/* ttinl */ {
#ifndef MYREAD
CHAR ch, dum;
#endif /* MYREAD */
#ifdef PARSENSE
int pktlen = -1;
int lplen = 0;
int havelen = 0;
#endif /* PARSENSE */
int cc = 0; /* Character count */
int fd;
#ifdef CKXXCHAR
extern short dblt[]; /* Ignore-character table */
extern int ignflag;
#endif /* CKXXCHAR */
if (ttyfd < 0) return(-3); /* Not open. */
debug(F101,"ttinl max","",max);
debug(F101,"ttinl timo","",timo);
#ifdef NETCMD
if (ttpipe)
fd = fdin;
else
#endif /* NETCMD */
fd = ttyfd;
#ifdef COMMENT
if (xlocal && conchk() > 0) /* Allow for console interruptions */
return(-1);
#endif /* COMMENT */
*dest = '\0'; /* Clear destination buffer */
if (timo < 0) timo = 0; /* Safety */
if (timo) { /* Don't time out if timo == 0 */
int xx;
saval = signal(SIGALRM,timerh); /* Enable timer interrupt */
xx = alarm(timo); /* Set it. */
debug(F101,"ttinl alarm","",xx);
}
if (
#ifdef CK_POSIX_SIG
sigsetjmp(sjbuf,1)
#else
setjmp(sjbuf)
#endif /* CK_POSIX_SIG */
) { /* Timer went off? */
debug(F100,"ttinl timout","",0); /* Get here on timeout. */
/* debug(F110," with",(char *) dest,0); */
ttimoff(); /* Turn off timer */
return(-1); /* and return error code. */
} else {
register int i, n; /* local variables */
int ccn = 0;
#ifdef PARSENSE
register int flag = 0;
debug(F000,"ttinl start","",start);
#endif /* PARSENSE */
ttpmsk = (ttprty) ? 0177 : 0377; /* Set parity stripping mask. */
#ifdef COMMENT
m == ttpmsk;
#endif /* COMMENT */
#ifdef COMMENT
/*
No longer needed.
*/
#ifdef SUNX25
if (netconn && (ttnet == NET_SX25))
#ifdef PARSENSE
return(x25inl(dest,max,timo,eol,start));
#else
return(x25inl(dest,max,timo,eol));
#endif /* PARSENSE */
#endif /* SUNX25 */
#endif /* COMMENT */
/* Now read into destination, stripping parity and looking for the */
/* the packet terminator, and also for several Ctrl-C's typed in a row. */
i = 0; /* Destination index */
debug(F101,"ttinl eol","",eol);
while (i < max-1) {
#ifdef MYREAD
/* debug(F101,"ttinl i","",i); */
errno = 0;
if (csave > -1) {
n = csave;
debug(F101,"ttinl unsaving","",n);
} else
if ((n = myread()) < 0) { /* Timeout or i/o error? */
#ifdef DEBUG
if (deblog) {
debug(F101,"ttinl myread failure, n","",n);
debug(F101,"ttinl myread errno","",errno);
}
#endif /* DEBUG */
/* Don't let EINTR break packets. */
if (n == -3) {
if (errno == EINTR && i > 0) {
debug(F101,"ttinl EINTR myread i","",i);
continue;
} else return(n);
} else if (n == -2 && netconn /* && timo == 0 */ ) {
/* Here we try to catch broken network connections */
/* even when ioctl() and read() do not catch them */
debug(F100,"ttinl untimed network myread fails","",0);
n = -3; /* Upgrade the error */
ttclos(0);
}
break; /* Break out of while loop */
}
#else /* not MYREAD (is this code used anywhere any more?) */
if (csave > -1) /* Char saved from last time */
ch = csave;
else if ((n = read(fd, &ch, 1)) < 1)
break; /* Error - break out of while loop */
n = ch;
#endif /* MYREAD */
/* Get here with char in n */
#ifdef CK_ENCRYPTION
/* If csave > -1 we already decrypted this character */
if (u_encrypt && csave == -1) { /* So don't decrypt it again */
char ch = n;
ck_krb_decrypt(&ch,1);
n = ch;
}
#endif /* CK_ENCRYPTION */
csave = -1; /* Unflag that we unsaved a char */
#ifdef CKXXCHAR
if (ignflag)
if (dblt[(unsigned) n] & 1) /* Character to ignore? */
continue;
#endif /* CKXXCHAR */
#ifdef PARSENSE
/*
Figure out what the length is supposed to be in case the packet
has no terminator (as with Honeywell GCOS-8 Kermit).
*/
if ((flag == 0) && ((n & 0x7f) == start)) flag = 1;
if (flag) dest[i++] = n & ttpmsk;
#ifdef COMMENT
/* if (!flag && cc++ > (max / 2)) return(-1); */
#endif /* COMMENT */
/*
If we have not been instructed to wait for a turnaround character, we
can go by the packet length field. If turn != 0, we must wait for the
end of line (eol) character before returning.
*/
if (!havelen) {
if (i == 2) {
pktlen = xunchar(dest[1] & 0x7f);
if (pktlen > 1) {
havelen = 1;
debug(F101,"ttinl length","",pktlen);
}
} else if (i == 5 && pktlen == 0) {
lplen = xunchar(dest[4] & 0x7f);
} else if (i == 6 && pktlen == 0) {
pktlen = lplen * 95 + xunchar(dest[5] & 0x7f) + 5;
havelen = 1;
debug(F101,"ttinl extended length","",pktlen);
}
}
#else
dest[i++] = n & ttpmsk;
#endif /* PARSENSE */
/*
Use parity mask, rather than always stripping parity, to check for
cancellation. Otherwise, runs like \x03\x83\x03 in packet could cancel
the transfer when parity is NONE.
*/
/* Check cancellation */
if (!xlocal && xfrcan && ((n & ttpmsk) == xfrchr)) {
if (++ccn >= xfrnum) { /* If xfrnum in a row, bail out. */
if (timo) { /* Clear timer. */
ttimoff();
}
fprintf(stderr,"^C...\r\n"); /* Echo Ctrl-C */
return(-2);
}
} else ccn = 0; /* No cancellation, reset counter, */
#ifdef PARSENSE
if (flag == 0) {
debug(F101,"ttinl skipping","",n);
continue;
}
#endif /* PARSENSE */
/* Check for end of packet */
if (
#ifdef PARSENSE
/*
Purely length-driven if SET HANDSHAKE NONE (i.e. turn == 0).
This allows packet terminators and handshake characters to appear
literally inside a packet data field.
*/
(havelen && (i > pktlen+1) &&
(!turn || (turn && (n & 0x7f) == turn))) /* (turn, not eol) */
#else /* !PARSENSE */
/*
Built without PARSENSE, so just look for packet terminator.
*/
((n & 0x7f) == eol)
#endif /* PARSENSE */
) {
#ifndef PARSENSE
debug(F101,"ttinl got eol","",eol); /* (or turn) */
dest[i] = '\0'; /* Yes, terminate the string, */
/* debug(F101,"ttinl i","",i); */
#else
#ifdef DEBUG
if (deblog) {
if ((n & 0x7f) != eol) {
debug(F101,"ttinl EOP length","",pktlen);
debug(F101,"ttinl i","",i);
#ifdef MYREAD
#ifdef PARSENSE
/*
We read a packet based on its length. This leaves the EOP character still
unread, and so ttchk() will always return at least 1 because of this. But
if we know it is there, we can safely get rid of it. So...
*/
{
int x;
while (my_count > 0) {
x = ttinc(0);
/* Start of next packet */
if (x == start) { /* Save for next time */
csave = (unsigned)((unsigned)x & 0xff);
debug(F101,"ttinl csaved","",x);
break;
}
debug(F101,"ttinl removed","",x);
}
}
#endif /* PARSENSE */
#endif /* MYREAD */
} else debug(F101,"ttinl got eol","",eol); /* (or turn) */
}
#endif /* DEBUG */
dest[i] = '\0'; /* Terminate the string, */
/* Parity checked yet? */
if (needpchk && ttprty == 0) {
if ((ttprty = parchk(dest,start,i)) > 0) { /* No, check. */
int j;
debug(F101,"ttinl senses parity","",ttprty);
debug(F110,"ttinl packet before",dest,0);
ttpmsk = 0x7f;
for (j = 0; j < i; j++)
dest[j] &= 0x7f; /* Strip parity from packet */
debug(F110,"ttinl packet after ",dest,0);
} else ttprty = 0; /* restore if parchk error */
}
needpchk = 0;
#endif /* PARSENSE */
if (timo) { /* Turn off timer. */
ttimoff();
}
debug(F011,"ttinl got", dest, (i < 60) ? i : -60);
return(i);
}
} /* End of while() */
ttimoff();
return(n);
}
}
/* T T I N C -- Read a character from the communication line */
/*
On success, returns the character that was read, >= 0.
On failure, returns -1 or other negative myread error code,
or -2 if connection is broken or ttyfd < 0.
*/
int
ttinc(timo) int timo; {
int n = 0, fd;
CHAR ch = 0;
if (ttyfd < 0) return(-2); /* Not open. */
#ifdef NETCMD
if (ttpipe)
fd = fdin;
else
#endif /* NETCMD */
fd = ttyfd;
if ((timo <= 0) /* Untimed. */
#ifdef MYREAD
|| (my_count > 0) /* Buffered char already waiting. */
#endif /* MYREAD */
) {
#ifdef MYREAD
/* Comm line failure returns -1 thru myread, so no &= 0377 */
n = myread(); /* Wait for a character... */
/* debug(F000,"ttinc MYREAD n","",n); */
#ifdef CK_ENCRYPTION
/* debug(F101,"ttinc u_encrypt","",u_encrypt); */
if (u_encrypt && n >= 0) {
ch = n;
ck_krb_decrypt(&ch,1);
n = ch;
}
#endif /* CK_ENCRYPTION */
#ifdef TCPSOCKET
if (netconn && (ttnproto == NP_TELNET) && (n > -1))
return((unsigned)(n & 0xff));
else
#endif /* TCPSOCKET */
return(n < 0 ? n : (unsigned)(n & ttpmsk));
#else /* MYREAD */
while ((n = read(fd,&ch,1)) == 0) /* Wait for a character. */
/* Shouldn't have to loop in ver 5A. */
#ifdef NETCONN
if (netconn) { /* Special handling for net */
netclos(); /* If read() returns 0 it means */
netconn = 0; /* the connection has dropped. */
errno = ENOTCONN;
return(-2);
}
#endif /* NETCONN */
;
/* debug(F101,"ttinc","",ch); */
#ifdef TCPSOCKET
if (netconn && (ttnproto == NP_TELNET) && (n > -1)) {
#ifdef CK_ENCRYPTION
if (u_encrypt) {
ck_krb_decrypt(&ch,1);
}
#endif /* CK_ENCRYPTION */
return((unsigned)(n & 0xff));
} else
#endif /* TCPSOCKET */
return( (n < 1) ? -3 : (unsigned)(ch & ttpmsk) );
#endif /* MYREAD */
} else { /* Timed read */
int oldalarm;
saval = signal(SIGALRM,timerh); /* Set up handler, save old one. */
oldalarm = alarm(timo); /* Set alarm, save old one. */
if (
#ifdef CK_POSIX_SIG
sigsetjmp(sjbuf,1)
#else
setjmp(sjbuf)
#endif /* CK_POSIX_SIG */
) { /* Timer expired */
n = -1; /* set flag */
} else {
#ifdef MYREAD
n = myread(); /* If managing own buffer... */
debug(F101,"ttinc myread","",n);
ch = n;
#else
n = read(fd,&ch,1); /* Otherwise call the system. */
if (n == 0) n = -1;
debug(F101,"ttinc read","",n);
#endif /* MYREAD */
#ifdef CK_ENCRYPTION
if (u_encrypt && n >= 0) {
ck_krb_decrypt(&ch,1);
}
#endif /* CK_ENCRYPTION */
if (n >= 0)
n = (unsigned) (ch & 0xff);
else
n = (n < 0) ? -3 : -2; /* Special return codes. */
}
ttimoff(); /* Turn off the timer */
if (oldalarm > 0) {
if (n == -1) /* and restore any previous alarm */
oldalarm -= timo;
if (oldalarm < 0) /* adjusted by our timeout interval */
oldalarm = 0;
if (oldalarm) {
debug(F101,"ttinc restoring oldalarm","",oldalarm);
alarm(oldalarm);
}
}
#ifdef NETCONN
if (netconn) {
if (n == -2) { /* read() returns 0 */
netclos(); /* on network read failure */
netconn = 0;
errno = ENOTCONN;
}
}
#endif /* NETCONN */
#ifdef TCPSOCKET
if (netconn && (ttnproto == NP_TELNET) && (n > -1))
return((unsigned)(n & 0xff));
else
#endif /* TCPSOCKET */
/* Return masked char or neg. */
return( (n < 0) ? n : (unsigned)(n & ttpmsk) );
}
}
/* S N D B R K -- Send a BREAK signal of the given duration */
#ifndef NOLOCAL
static int
#ifdef CK_ANSIC
sndbrk(int msec) { /* Argument is milliseconds */
#else
sndbrk(msec) int msec; {
#endif /* CK_ANSIC */
#ifndef POSIX
int x, n;
#endif /* POSIX */
#ifdef OXOS
#define BSDBREAK
#endif /* OXOS */
#ifdef ANYBSD
#define BSDBREAK
#endif /* ANYBSD */
#ifdef BSD44
#define BSDBREAK
#endif /* BSD44 */
#ifdef COHERENT
#define BSDBREAK
#endif /* COHERENT */
#ifdef BELLV10
#ifdef BSDBREAK
#undef BSDBREAK
#endif /* BSDBREAK */
#endif /* BELLV10 */
#ifdef PROVX1
char spd;
#endif /* PROVX1 */
debug(F101,"ttsndb ttyfd","",ttyfd);
if (ttyfd < 0) return(-1); /* Not open. */
#ifdef Plan9
return p9sndbrk(msec);
#else
#ifdef NETCONN
#ifdef NETCMD
if (ttpipe) /* Pipe */
return(ttoc('\0'));
#endif /* NETCMD */
if (netconn) /* Send network BREAK */
return(netbreak());
#endif /* NETCONN */
if (msec < 1 || msec > 5000) return(-1); /* Bad argument */
#ifdef POSIX /* Easy in POSIX */
debug(F101,"sndbrk POSIX","",msec);
return(tcsendbreak(ttyfd,msec / 375));
#else
#ifdef PROVX1
gtty(ttyfd,&ttbuf); /* Get current tty flags */
spd = ttbuf.sg_ospeed; /* Save speed */
ttbuf.sg_ospeed = B50; /* Change to 50 baud */
stty(ttyfd,&ttbuf); /* ... */
n = (int)strlen(brnuls); /* Send the right number of nulls */
x = msec / 91;
if (x > n) x = n;
write(ttyfd,brnuls,n);
ttbuf.sg_ospeed = spd; /* Restore speed */
stty(ttyfd,&ttbuf); /* ... */
return(0);
#else
#ifdef aegis
sio_$control((short)ttyfd, sio_$send_break, msec, st);
return(0);
#else
#ifdef BSDBREAK
n = FWRITE; /* Flush output queue. */
/* Watch out for int vs long problems in &n arg! */
debug(F101,"sndbrk BSDBREAK","",msec);
ioctl(ttyfd,TIOCFLUSH,&n); /* Ignore any errors.. */
if (ioctl(ttyfd,TIOCSBRK,(char *)0) < 0) { /* Turn on BREAK */
perror("Can't send BREAK");
return(-1);
}
x = msleep(msec); /* Sleep for so many milliseconds */
if (ioctl(ttyfd,TIOCCBRK,(char *)0) < 0) { /* Turn off BREAK */
perror("BREAK stuck!!!");
doexit(BAD_EXIT,-1); /* Get out, closing the line. */
/* with bad exit status */
}
return(x);
#else
#ifdef ATTSV
/*
No way to send a long BREAK in Sys V, so send a bunch of regular ones.
(Actually, Sys V R4 is *supposed* to have the POSIX tcsendbreak() function,
but there's no way for this code to know for sure.)
*/
debug(F101,"sndbrk ATTSV","",msec);
x = msec / 275;
for (n = 0; n < x; n++) {
/* Reportedly the cast breaks this function on some systems */
/* But then why was it here in the first place? */
if (ioctl(ttyfd,TCSBRK, /* (char *) */ 0) < 0) {
perror("Can't send BREAK");
return(-1);
}
}
return(0);
#else
#ifdef V7
debug(F101,"sndbrk V7","",msec);
return(genbrk(ttyfd,250)); /* Simulate a BREAK */
#else
debug(F101,"sndbrk catchall","",msec);
ttoc(0);ttoc(0);ttoc(0);ttoc(0);
return(0);
#endif /* V7 */
#endif /* BSDBREAK */
#endif /* ATTSV */
#endif /* aegis */
#endif /* PROVX1 */
#endif /* POSIX */
#endif /* Plan9 */
}
/* T T S N D B -- Send a BREAK signal */
int
ttsndb() {
return(sndbrk(275));
}
/* T T S N D L B -- Send a Long BREAK signal */
int
ttsndlb() {
return(sndbrk(1500));
}
#endif /* NOLOCAL */
/* M S L E E P -- Millisecond version of sleep(). */
/*
Call with number of milliseconds (thousandths of seconds) to sleep.
Intended only for small intervals. For big ones, just use sleep().
Highly system-dependent.
Returns 0 always, even if it didn't work.
*/
/* Define MSLFTIME for systems that must use an ftime() loop. */
#ifdef ANYBSD /* For pre-4.2 BSD versions */
#ifndef BSD4
#define MSLFTIME
#endif /* BSD4 */
#endif /* ANYBSD */
#ifdef TOWER1 /* NCR Tower OS 1.0 */
#define MSLFTIME
#endif /* TOWER1 */
#ifdef COHERENT /* Coherent... */
#ifndef _I386 /* Maybe Coherent/386 should get this, too */
#define MSLFTIME /* Opinions are divided */
#endif /* _I386 */
#endif /* COHERENT */
#ifdef COMMENT
#ifdef GETMSEC
/* Millisecond timer */
static long msecbase = 0L; /* Unsigned long not portable */
long
getmsec() { /* Milliseconds since base time */
struct timeval xv;
struct timezone xz;
long secs, msecs;
if (gettimeofday(&tv, &tz) < 0)
return(-1);
if (msecbase == 0L) { /* First call, set base time. */
msecbase = tv.tv_sec;
debug(F101,"getmsec base","",msecbase);
}
return(((tv.tv_sec - msecbase) * 1000L) + (tv.tv_usec / 1000L));
}
#endif /* GETMSEC */
#endif /* COMMENT */
int
msleep(m) int m; {
/*
Other possibilities here are:
nanosleep(), reportedly defined in POSIX.4.
sginap(), IRIX only (back to what IRIX version I don't know).
*/
#ifdef Plan9
return _SLEEP(m);
#else
#ifdef BEBOX
snooze(m*1000);
#else /* BEBOX */
#ifdef SELECT
int t1, x;
debug(F101,"msleep SELECT 1","",m);
if (m <= 0) return(0);
if (m >= 1000) { /* Catch big arguments. */
sleep(m/1000);
m = m % 1000;
if (m < 10) return(0);
}
debug(F101,"msleep SELECT 2","",m);
#ifdef BELLV10
x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, m );
debug(F101,"msleep BELLV10 select","",x);
#else /* BELLV10 */
#ifndef COHERENT
/* Hmmm... what's all this then? */
if (gettimeofday(&tv, &tz) < 0) return(-1); /* Get current time. */
t1 = tv.tv_sec; /* Seconds */
#endif /* COHERENT */
tv.tv_sec = 0; /* Use select() */
tv.tv_usec = m * 1000L;
#ifdef BSD44
x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"msleep BSD44 select","",x);
#else /* BSD44 */
#ifdef __linux__
x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"msleep __linux__ select","",x);
#else /* __linux__ */
#ifdef BSD43
x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"msleep BSD43 select","",x);
#else /* BSD43 */
#ifdef QNX
x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"msleep QNX select","",x);
#else /* QNX */
#ifdef COHERENT
x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"msleep COHERENT select","",x);
#else /* COHERENT */
#ifdef HPUX1000 /* 10.00 only, not 10.10 or later */
x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
debug(F101,"msleep HP-UX 10.00 select","",x);
#else /* HPUX1000 */
#ifdef SVR4
x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"msleep SVR4 select","",x);
#else /* SVR4 */
#ifdef OSF40
x = select( 0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv );
debug(F101,"msleep OSF40 select","",x);
#else /* OSF40 */
x = select( 0, (int *)0, (int *)0, (int *)0, &tv );
debug(F101,"msleep catch-all select","",x);
#endif /* OSF40 */
#endif /* HP1000 */
#endif /* SVR4 */
#endif /* COHERENT */
#endif /* QNX */
#endif /* BSD43 */
#endif /* __linux__ */
#endif /* BSD44 */
#endif /* BELLV10 */
return(0);
#else /* Not SELECT */
#ifdef CK_POLL /* We have poll() */
struct pollfd pfd; /* Supply a valid address for poll() */
#ifdef ODT30 /* But in SCO ODT 3.0 */
#ifdef NAP /* we should use nap() instead */
debug(F101,"msleep ODT 3.0 NAP","",m); /* because using poll() here */
nap((long)m); /* seems to break dialing. */
return(0);
#else
debug(F101,"msleep ODT 3.0 POLL","",m);
poll(&pfd, 0, m);
return(0);
#endif /* NAP */
#else
debug(F101,"msleep POLL","",m);
poll(&pfd, 0, m);
return(0);
#endif /* ODT30 */
/*
We could handle the above more cleanly by just letting nap() take
always take precedence over poll() in this routine, but there is no way
to know whether that would break something else.
*/
#else /* Not POLL */
#ifdef USLEEP
/*
"This routine is implemented using setitimer(2); it requires eight
system calls...". In other words, it might take 5 minutes to sleep
for 100 milliseconds...
*/
debug(F101,"msleep USLEEP","",m);
if (m >= 1000) { /* Catch big arguments. */
sleep(m/1000);
m = m % 1000;
if (m < 10) return(0);
}
usleep((unsigned int)(m * 1000));
return(0);
#else
#ifdef aegis
time_$clock_t dur;
debug(F101,"msleep aegis","",m);
dur.c2.high16 = 0;
dur.c2.low32 = 250 * m; /* one millisecond = 250 four microsecond ticks */
time_$wait(time_$relative, dur, st);
return(0);
#else
#ifdef PROVX1
debug(F101,"msleep Venix","",m);
if (m <= 0) return(0);
sleep(-((m * 60 + 500) / 1000));
return(0);
#else
#ifdef NAP
debug(F101,"msleep NAP","",m);
nap((long)m);
return(0);
#else
#ifdef ATTSV
#ifndef BSD44
extern long times(); /* Or #include <times.h> ? */
#endif /* BSD44 */
long t1, t2, tarray[4];
int t3;
#ifdef COMMENT
/* This better be picked up in ckcdeb.h... */
char *getenv();
#endif /* COMMENT */
char *cp = getenv("HZ");
int CLOCK_TICK;
int hertz;
if (cp && (hertz = atoi(cp))) {
CLOCK_TICK = 1000 / hertz;
} else { /* probably single user mode */
#ifdef HZ
CLOCK_TICK = 1000 / HZ;
#else
static warned = 0;
/* HZ always exists in, for instance, SCO Xenix, so you don't have to
* make special #ifdefs for XENIX here, like in ver 4F. Also, if you
* have Xenix, you have should have nap(), so the best is to use -DNAP
* in the makefile. Most systems have HZ.
*/
CLOCK_TICK = 17; /* 1/60 sec */
if (!warned) {
printf("warning: environment variable HZ bad... using HZ=%d\r\n",
1000 / CLOCK_TICK);
warned = 1;
}
#endif /* !HZ */
}
debug(F101,"msleep ATTSV","",m);
if (m <= 0) return(0);
if (m >= 1000) { /* Catch big arguments. */
sleep(m/1000);
m = m % 1000;
if (m < 10) return(0);
}
if ((t1 = times(tarray)) < 0) return(-1);
while (1) {
if ((t2 = times(tarray)) < 0) return(-1);
t3 = ((int)(t2 - t1)) * CLOCK_TICK;
if (t3 > m) return(t3);
}
#else /* Not ATTSV */
#ifdef MSLFTIME /* Use ftime() loop... */
int t1, t3 = 0;
debug(F101,"msleep MSLFTIME","",m);
if (m <= 0) return(0);
if (m >= 1000) { /* Catch big arguments. */
sleep(m/1000);
m = m % 1000;
if (m < 10) return(0);
}
#ifdef QNX
ftime(&ftp); /* void ftime() in QNX */
#else
if (ftime(&ftp) < 0) return(-1); /* Get base time. */
#endif /* QNX */
t1 = ((ftp.time & 0xff) * 1000) + ftp.millitm;
while (1) {
ftime(&ftp); /* Get current time and compare. */
t3 = (((ftp.time & 0xff) * 1000) + ftp.millitm) - t1;
if (t3 > m) return(0);
}
#else
/* This includes true POSIX, which has no way to do this. */
debug(F101,"msleep busy loop","",m);
if (m >= 1000) { /* Catch big arguments. */
sleep(m/1000);
m = m % 1000;
if (m < 10) return(0);
}
if (m > 0) while (m > 0) m--; /* Just a dumb busy loop */
return(0);
#endif /* MSLFTIME */
#endif /* ATTSV */
#endif /* NAP */
#endif /* PROVX1 */
#endif /* aegis */
#endif /* CK_POLL */
#endif /* SELECT */
#endif /* BEBOX */
#endif /* USLEEP */
#endif /* Plan9 */
}
/* R T I M E R -- Reset elapsed time counter */
VOID
rtimer() {
tcount = time( (time_t *) 0 );
}
/* G T I M E R -- Get current value of elapsed time counter in seconds */
int
gtimer() {
int x;
x = (int) (time( (time_t *) 0 ) - tcount);
debug(F101,"gtimer","",x);
return( (x < 0) ? 0 : x );
}
#ifdef GFTIMER
static struct timeval tzero;
VOID
rftimer() {
#ifdef MOTSV88R4 /* Account for Mot's definition */
(VOID) gettimeofday(&tzero);
#else
(VOID) gettimeofday(&tzero, (struct timezone *)0);
#endif /* MOTSV88R4 */
}
CKFLOAT
gftimer() {
struct timeval tnow, tdelta;
CKFLOAT s, sb;
#ifdef DEBUG
char fpbuf[64];
#endif /* DEBUG */
#ifdef MOTSV88R4 /* Acount for Mot's definition */
(VOID) gettimeofday(&tnow);
#else
(VOID) gettimeofday(&tnow, (struct timezone *)0);
#endif /* MOTSV88R4 */
tdelta.tv_sec = tnow.tv_sec - tzero.tv_sec;
tdelta.tv_usec = tnow.tv_usec - tzero.tv_usec;
if (tdelta.tv_usec < 0) {
tdelta.tv_sec--;
tdelta.tv_usec += 1000000;
}
s = (CKFLOAT) tdelta.tv_sec + ((CKFLOAT) tdelta.tv_usec / 1000000.0);
if (s < GFMINTIME)
s = GFMINTIME;
#ifdef DEBUG
if (deblog) {
sprintf(fpbuf,"%f",s);
debug(F110,"gftimer",fpbuf,0);
}
#endif /* DEBUG */
return(s);
}
#endif /* GFTIMER */
/* Z T I M E -- Return date/time string */
VOID
ztime(s) char **s; {
#undef ZTIMEV7 /* Which systems need to use */
#ifdef COHERENT /* old UNIX Version 7 way... */
#define ZTIMEV7
#endif /* COHERENT */
#ifdef TOWER1
#define ZTIMEV7
#endif /* TOWER1 */
#ifdef ANYBSD
#ifndef BSD42
#define ZTIMEV7
#endif /* BSD42 */
#endif /* ANYBSD */
#ifdef V7
#ifndef MINIX
#define ZTIMEV7
#endif /* MINIX */
#endif /* V7 */
#ifdef POSIX
#define ZTIMEV7
#endif /* POSIX */
#ifdef HPUX1020
/*
Prototypes are in <time.h>, included above.
*/
time_t clock_storage;
clock_storage = time((void *) 0);
*s = ctime(&clock_storage);
debug(F110,"ztime: HPUX 10.20",*s,0);
#else
#ifdef ATTSV /* AT&T way */
/* extern long time(); */ /* Theoretically these should */
char *ctime(); /* already been dcl'd in <time.h> */
long clock_storage;
clock_storage = time(
#ifdef IRIX60
(time_t *)
#else
(long *)
#endif /* IRIX60 */
0 );
*s = ctime( &clock_storage );
debug(F110,"ztime: ATTSV",*s,0);
#else
#ifdef PROVX1 /* Venix 1.0 way */
int utime[2];
time(utime);
*s = ctime(utime);
debug(F110,"ztime: PROVX1",*s,0);
#else
#ifdef BSD42 /* 4.2BSD way */
char *asctime();
struct tm *localtime();
struct tm *tp;
gettimeofday(&tv, &tz);
time(&tv.tv_sec);
tp = localtime(&tv.tv_sec);
*s = asctime(tp);
debug(F110,"ztime: BSD42",*s,0);
#else
#ifdef MINIX /* MINIX way */
#ifdef COMMENT
extern long time(); /* Already got these from <time.h> */
extern char *ctime();
#endif /* COMMENT */
time_t utime[2];
time(utime);
*s = ctime(utime);
debug(F110,"ztime: MINIX",*s,0);
#else
#ifdef ZTIMEV7 /* The regular way */
char *asctime();
struct tm *localtime();
struct tm *tp;
long xclock; /* or unsigned long for BeBox? */
time(&xclock);
tp = localtime(&xclock);
*s = asctime(tp);
debug(F110,"ztime: ZTIMEV7",*s,0);
#else /* Catch-all for others... */
*s = "Day Mon 00 00:00:00 0000\n" /* Return dummy in asctime() format */
debug(F110,"ztime: catch-all",*s,0);
#endif /* ZTIMEV7 */
#endif /* MINIX */
#endif /* BSD42 */
#endif /* PROVX1 */
#endif /* ATTSV */
#endif /* HPUX1020 */
}
/* C O N G M -- Get console terminal modes. */
/*
Saves initial console mode, and establishes variables for switching
between current (presumably normal) mode and other modes.
Should be called when program starts, but only after establishing
whether program is in the foreground or background.
Returns 1 if it got the modes OK, 0 if it did nothing, -1 on error.
*/
int
congm() {
int fd;
if (backgrd || !isatty(0)) { /* If in background. */
cgmf = -1; /* Don't bother, modes are garbage. */
return(-1);
}
if (cgmf > 0) return(0); /* Already did this. */
debug(F100,"congm getting modes","",0); /* Need to do it. */
#ifdef aegis
ios_$inq_type_uid(ios_$stdin, conuid, st);
if (st.all != status_$ok) {
fprintf(stderr, "problem getting stdin objtype: ");
error_$print(st);
}
concrp = (conuid == mbx_$uid);
conbufn = 0;
#endif /* aegis */
#ifndef BEBOX
if ((fd = open(CTTNAM,2)) < 0) { /* Open controlling terminal */
#ifdef COMMENT
fprintf(stderr,"Error opening %s\n", CTTNAM);
perror("congm");
return(-1);
#else
fd = 0;
#endif /* COMMENT */
}
#else
fd = 0;
#endif /* !BEBOX */
#ifdef BSD44ORPOSIX
if (tcgetattr(fd,&ccold) < 0) return(-1);
if (tcgetattr(fd,&cccbrk) < 0) return(-1);
if (tcgetattr(fd,&ccraw) < 0) return(-1);
#else
#ifdef ATTSV
if (ioctl(fd,TCGETA,&ccold) < 0) return(-1);
if (ioctl(fd,TCGETA,&cccbrk) < 0) return(-1);
if (ioctl(fd,TCGETA,&ccraw) < 0) return(-1);
#ifdef VXVE
cccbrk.c_line = 0; /* STTY line 0 for CDC VX/VE */
if (ioctl(fd,TCSETA,&cccbrk) < 0) return(-1);
ccraw.c_line = 0; /* STTY line 0 for CDC VX/VE */
if (ioctl(fd,TCSETA,&ccraw) < 0) return(-1);
#endif /* VXVE */
#else
#ifdef BELLV10
if (ioctl(fd,TIOCGETP,&ccold) < 0) return(-1);
if (ioctl(fd,TIOCGETP,&cccbrk) < 0) return(-1);
if (ioctl(fd,TIOCGETP,&ccraw) < 0) return(-1);
#else
if (gtty(fd,&ccold) < 0) return(-1);
if (gtty(fd,&cccbrk) < 0) return(-1);
if (gtty(fd,&ccraw) < 0) return(-1);
#endif /* BELLV10 */
#endif /* ATTSV */
#endif /* BSD44ORPOSIX */
#ifdef sony_news /* Sony NEWS */
if (ioctl(fd,TIOCKGET,&km_con) < 0) { /* Get console Kanji mode */
perror("congm error getting Kanji mode");
debug(F101,"congm error getting Kanji mode","",0);
km_con = -1; /* Make sure this stays undefined. */
return(-1);
}
#endif /* sony_news */
if (fd > 0)
close(fd);
cgmf = 1; /* Flag that we got them. */
return(1);
}
/* C O N C B -- Put console in cbreak mode. */
/* Returns 0 if ok, -1 if not */
int
#ifdef CK_ANSIC
concb(char esc)
#else
concb(esc) char esc;
#endif /* CK_ANSIC */
/* concb */ {
int x;
debug(F101,"concb cgmf","",cgmf);
debug(F101,"concb backgrd","",backgrd);
if (cgmf < 1) /* Did we get console modes yet? */
if (!backgrd) /* No, in background? */
congm(); /* No, try to get them now. */
if (cgmf < 1) /* Still don't have them? */
return(0); /* Give up. */
debug(F101,"concb ttyfd","",ttyfd);
debug(F101,"concb ttfdflg","",ttfdflg);
if (ttfdflg && ttyfd >= 0 && ttyfd < 3)
return(0);
if (!isatty(0)) return(0); /* Only for real ttys */
debug(F100,"concb isatty","",0);
debug(F101,"concb suspend","",suspend);
if (backgrd) return(0); /* Do nothing if in background. */
escchr = esc; /* Make this available to other fns */
ckxech = 1; /* Program can echo characters */
#ifdef aegis
conbufn = 0;
if (concrp) return(write(1, "\035\002", 2));
if (conuid == input_pad_$uid) {pad_$raw(ios_$stdin, st); return(0);}
#endif /* aegis */
#ifdef COHERENT
#define SVORPOSIX
#endif /* COHERENT */
#ifdef Plan9
x = p9concb();
#else
#ifndef SVORPOSIX /* BSD, V7, etc */
cccbrk.sg_flags |= CBREAK; /* Set to character wakeup, */
cccbrk.sg_flags &= ~ECHO; /* no echo. */
#ifdef BELLV10
x = ioctl(0,TIOCSETP,&cccbrk);
#else
x = stty(0,&cccbrk);
#endif /* BELLV10 */
#else /* Sys V and POSIX */
#ifndef OXOS
debug(F101,"concb cccbrk.c_flag","",cccbrk.c_lflag);
#ifdef QNX
/* Don't mess with IEXTEN */
cccbrk.c_lflag &= ~(ICANON|ECHO);
#else
#ifdef COHERENT
cccbrk.c_lflag &= ~(ICANON|ECHO);
#else
cccbrk.c_lflag &= ~(ICANON|ECHO|IEXTEN);
#endif /* COHERENT */
#endif /* QNX */
cccbrk.c_lflag |= ISIG; /* Allow SIGINT, etc, in command mode. */
#else /* OXOS */
debug(F100,"concb OXOS is defined","",0);
cccbrk.c_lflag &= ~(ICANON|ECHO);
cccbrk.c_cc[VDISCARD] = cccbrk.c_cc[VLNEXT] = CDISABLE;
#endif /* OXOS */
#ifdef COMMENT
/*
Believe it or not, in SCO UNIX, VSUSP is greater than NCC, and so this
array reference is out of bounds. It's only a debug() call so who needs it.
*/
#ifdef VSUSP
debug(F101,"concb c_cc[VSUSP]","",cccbrk.c_cc[VSUSP]);
#endif /* VSUSP */
#endif /* COMMENT */
#ifndef VINTR
debug(F101,"concb c_cc[0]","",cccbrk.c_cc[0]);
cccbrk.c_cc[0] = 003; /* Interrupt char is Control-C */
#else
debug(F101,"concb c_cc[VINTR]","",cccbrk.c_cc[0]);
cccbrk.c_cc[VINTR] = 003;
#endif /* VINTR */
#ifndef VQUIT
cccbrk.c_cc[1] = escchr; /* escape during packet modes */
#else
cccbrk.c_cc[VQUIT] = escchr;
#endif /* VQUIT */
#ifndef VEOF
cccbrk.c_cc[4] = 1;
#else
#ifndef OXOS
#ifdef VMIN
cccbrk.c_cc[VMIN] = 1;
#endif /* VMIN */
#else /* OXOS */
cccbrk.c_min = 1;
#endif /* OXOS */
#endif /* VEOF */
#ifdef ZILOG
cccbrk.c_cc[5] = 0;
#else
#ifndef VEOL
cccbrk.c_cc[5] = 1;
#else
#ifndef OXOS
#ifdef VTIME
cccbrk.c_cc[VTIME] = 1;
#endif /* VTIME */
#else /* OXOS */
cccbrk.c_time = 1;
#endif /* OXOS */
#endif /* VEOL */
#endif /* ZILOG */
#ifdef BSD44ORPOSIX /* Set new modes */
x = tcsetattr(0,TCSADRAIN,&cccbrk);
#else /* ATTSV */ /* or the POSIX way */
x = ioctl(0,TCSETAW,&cccbrk); /* the Sys V way */
#endif /* BSD44ORPOSIX */
#endif /* SVORPOSIX */
#ifdef COHERENT
#undef SVORPOSIX
#endif /* COHERENT */
#ifndef aegis
#ifndef NOSETBUF
if (x > -1) setbuf(stdout,NULL); /* Make console unbuffered. */
#endif /* NOSETBUF */
#endif /* aegis */
#ifdef V7
#ifndef MINIX
if (kmem[CON] < 0) {
qaddr[CON] = initrawq(0);
if((kmem[CON] = open("/dev/kmem", 0)) < 0) {
fprintf(stderr, "Can't read /dev/kmem in concb.\n");
perror("/dev/kmem");
exit(1);
}
}
#endif /* MINIX */
#endif /* V7 */
#endif /* Plan9 */
debug(F101,"concb returns","",x);
return(x);
}
/* C O N B I N -- Put console in binary mode */
/* Returns 0 if ok, -1 if not */
int
#ifdef CK_ANSIC
conbin(char esc)
#else
conbin(esc) char esc;
#endif /* CK_ANSIC */
/* conbin */ {
if (!isatty(0)) return(0); /* only for real ttys */
congm(); /* Get modes if necessary. */
debug(F100,"conbin","",0);
escchr = esc; /* Make this available to other fns */
ckxech = 1; /* Program can echo characters */
#ifdef aegis
conbufn = 0;
if (concrp) return(write(1, "\035\002", 2));
if (conuid == input_pad_$uid) {
pad_$raw(ios_$stdin, st);
return(0);
}
#endif /* aegis */
#ifdef COHERENT
#define SVORPOSIX
#endif /* COHERENT */
#ifdef Plan9
return p9conbin();
#else
#ifdef SVORPOSIX
#ifndef OXOS
#ifdef QNX
ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
#else
#ifdef COHERENT
ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
#else
ccraw.c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
#endif /* COHERENT */
#endif /* QNX */
#else /* OXOS */
ccraw.c_lflag &= ~(ISIG|ICANON|ECHO);
ccraw.c_cc[VDISCARD] = ccraw.c_cc[VLNEXT] = CDISABLE;
#endif /* OXOS */
ccraw.c_iflag |= (BRKINT|IGNPAR);
/*
Note that for terminal sessions we disable Xon/Xoff flow control to allow
the passage ^Q and ^S as data characters for EMACS, and to allow XMODEM
transfers to work when C-Kermit is in the middle, etc. Hardware flow
control, if in use, is not affected.
*/
#ifdef ATTSV
#ifdef BSD44
ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXANY|IXOFF
|INPCK|ISTRIP);
#else
ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IUCLC|IXON|IXANY|IXOFF
|INPCK|ISTRIP);
#endif /* BSD44 */
#else /* POSIX */
ccraw.c_iflag &= ~(IGNBRK|INLCR|IGNCR|ICRNL|IXON|IXOFF|INPCK|ISTRIP);
#endif /* ATTSV */
ccraw.c_oflag &= ~OPOST;
#ifdef COMMENT
/*
WHAT THE HECK WAS THIS FOR?
The B9600 setting (obviously) prevents CONNECT from working at any
speed other than 9600 when you are logged in to the 7300 on a serial
line. Maybe some of the other flags are necessary -- if so, put back
the ones that are needed. This code is supposed to work the same, no
matter whether you are logged in to the 7300 on the real console device,
or through a serial port.
*/
#ifdef ATT7300
ccraw.c_cflag = CLOCAL | B9600 | CS8 | CREAD | HUPCL;
#endif /* ATT7300 */
#endif /* COMMENT */
/*** Kermit used to put the console in 8-bit raw mode, but some users have
*** pointed out that this should not be done, since some sites actually
*** use terminals with parity settings on their Unix systems, and if we
*** override the current settings and stop doing parity, then their terminals
*** will display blotches for characters whose parity is wrong. Therefore,
*** the following two lines are commented out (Larry Afrin, Clemson U):
***
*** ccraw.c_cflag &= ~(PARENB|CSIZE);
*** ccraw.c_cflag |= (CS8|CREAD);
***
*** Sys III/V sites that have trouble with this can restore these lines.
***/
#ifndef VINTR
ccraw.c_cc[0] = 003; /* Interrupt char is Ctrl-C */
#else
ccraw.c_cc[VINTR] = 003;
#endif /* VINTR */
#ifndef VQUIT
ccraw.c_cc[1] = escchr; /* Escape during packet mode */
#else
ccraw.c_cc[VQUIT] = escchr;
#endif /* VQUIT */
#ifndef VEOF
ccraw.c_cc[4] = 1;
#else
#ifndef OXOS
#ifdef VMIN
ccraw.c_cc[VMIN] = 1;
#endif /* VMIN */
#else /* OXOS */
ccraw.c_min = 1;
#endif /* OXOS */
#endif /* VEOF */
#ifdef ZILOG
ccraw.c_cc[5] = 0;
#else
#ifndef VEOL
ccraw.c_cc[5] = 1;
#else
#ifndef OXOS
#ifdef VTIME
ccraw.c_cc[VTIME] = 1;
#endif /* VTIME */
#else /* OXOS */
ccraw.c_time = 1;
#endif /* OXOS */
#endif /* VEOL */
#endif /* ZILOG */
#ifdef BSD44ORPOSIX
return(tcsetattr(0,TCSADRAIN,&ccraw));
#else
return(ioctl(0,TCSETAW,&ccraw)); /* Set new modes. */
#endif /* BSD44ORPOSIX */
#else /* Berkeley, etc. */
ccraw.sg_flags |= (RAW|TANDEM); /* Set rawmode, XON/XOFF (ha) */
ccraw.sg_flags &= ~(ECHO|CRMOD); /* Set char wakeup, no echo */
#ifdef BELLV10
return(ioctl(0,TIOCSETP,&ccraw));
#else
return(stty(0,&ccraw));
#endif /* BELLV10 */
#endif /* SVORPOSIX */
#endif /* Plan9 */
#ifdef COHERENT
#undef SVORPOSIX
#endif /* COHERENT */
}
/* C O N R E S -- Restore the console terminal */
int
conres() {
debug(F101,"conres cgmf","",cgmf);
if (cgmf < 1) return(0); /* Do nothing if modes unchanged */
if (!isatty(0)) return(0); /* only for real ttys */
debug(F100,"conres isatty ok","",0);
ckxech = 0; /* System should echo chars */
#ifdef aegis
conbufn = 0;
if (concrp) return(write(1, "\035\001", 2));
if (conuid == input_pad_$uid) {
pad_$cooked(ios_$stdin, st);
return(0);
}
#endif /* aegis */
#ifdef Plan9
p9conres();
#else
#ifdef BSD44ORPOSIX
debug(F100,"conres restoring tcsetattr","",0);
return(tcsetattr(0,TCSADRAIN,&ccold));
#else
#ifdef ATTSV
debug(F100,"conres restoring ioctl","",0);
return(ioctl(0,TCSETAW,&ccold));
#else /* BSD, V7, and friends */
#ifdef sony_news /* Sony NEWS */
if (km_con != -1)
ioctl(0,TIOCKSET,&km_con); /* Restore console Kanji mode */
#endif /* sony_news */
msleep(100);
debug(F100,"conres restoring stty","",0);
#ifdef BELLV10
return(ioctl(0,TIOCSETP,&ccold));
#else
return(stty(0,&ccold));
#endif /* BELLV10 */
#endif /* ATTSV */
#endif /* BSD44ORPOSIX */
#endif /* Plan9 */
}
/* C O N O C -- Output a character to the console terminal */
int
#ifdef CK_ANSIC
conoc(char c)
#else
conoc(c) char c;
#endif /* CK_ANSIC */
/* conoc */ {
#ifdef Plan9
return conwrite(&c,1);
#else
return(write(1,&c,1));
#endif /* Plan9 */
}
/* C O N X O -- Write x characters to the console terminal */
int
conxo(x,s) int x; char *s; {
#ifdef Plan9
return(conwrite(s,x));
#else
return(write(1,s,x));
#endif /* Plan9 */
}
/* C O N O L -- Write a line to the console terminal */
int
conol(s) char *s; {
int len;
len = (int)strlen(s);
#ifdef Plan9
return(conwrite(s,len));
#else
return(write(1,s,len));
#endif /* Plan9 */
}
/* C O N O L A -- Write an array of lines to the console terminal */
int
conola(s) char *s[]; {
int i;
for (i=0 ; *s[i] ; i++) if (conol(s[i]) < 0) return(-1);;
return(0);
}
/* C O N O L L -- Output a string followed by CRLF */
int
conoll(s) char *s; {
conol(s);
#ifdef Plan9
return(conwrite("\r\n", 2));
#else
return(write(1,"\r\n",2));
#endif /* Plan9 */
}
/* C O N C H K -- Return how many characters available at console */
/*
We could also use select() here to cover a few more systems that are not
covered by any of the following, e.g. HP-UX 9.0x on the model 800.
*/
int
conchk() {
static int contyp = 0; /* +1 for isatty, -1 otherwise */
if (contyp == 0) /* This prevents unnecessary */
contyp = (isatty(0) ? 1 : -1); /* duplicated calls to isatty() */
debug(F101,"conchk contyp","",contyp);
if (backgrd || (contyp < 0))
return(0);
#ifdef aegis
if (conbufn > 0) return(conbufn); /* use old count if nonzero */
/* read in more characters */
conbufn = ios_$get(ios_$stdin,
ios_$cond_opt, conbuf, (long)sizeof(conbuf), st);
if (st.all != status_$ok) conbufn = 0;
conbufp = conbuf;
return(conbufn);
#else
return(in_chk(0,0));
#endif /* aegis */
}
/* C O N I N C -- Get a character from the console */
/*
Call with timo > 0 to do a timed read, timo == 0 to do an untimed blocking
read. Upon success, returns the character. Upon failure, returns -1.
A timed read that does not complete within the timeout period returns -1.
*/
int
coninc(timo) int timo; {
int n = 0; CHAR ch;
int xx;
#ifdef aegis /* Apollo Aegis only... */
debug(F101,"coninc timo","",timo);
fflush(stdout);
if (conchk() > 0) {
--conbufn;
return((unsigned)(*conbufp++ & 0xff));
}
#endif /* aegis */
if (timo <= 0 ) { /* Untimed, blocking read. */
while (1) { /* Keep trying till we get one. */
n = read(0, &ch, 1); /* Read a character. */
if (n == 0) continue; /* Shouldn't happen. */
if (n > 0) /* If read was successful, */
return((unsigned)(ch & 0xff)); /* return the character. */
/* Come here if read() returned an error. */
debug(F101, "coninc(0) errno","",errno); /* Log the error. */
#ifndef OXOS
#ifdef SVORPOSIX
#ifdef CIE /* CIE Regulus has no EINTR symbol? */
#ifndef EINTR
#define EINTR 4
#endif /* EINTR */
#endif /* CIE */
/*
This routine is used for several different purposes. In CONNECT mode, it is
used to do an untimed, blocking read from the keyboard in the lower CONNECT
fork. During local-mode file transfer, it reads a character from the
console to interrupt the file transfer (like A for a status report, X to
cancel a file, etc). Obviously, we don't want the reads in the latter case
to be blocking, or the file transfer would stop until the user typed
something. Unfortunately, System V does not allow the console device input
buffer to be sampled nondestructively (e.g. by conchk()), so a kludge is
used instead. During local-mode file transfer, the SIGQUIT signal is armed
and trapped by esctrp(), and this routine pretends to have read the quit
character from the keyboard normally. But, kludge or no kludge, the read()
issued by this command, under System V only, can fail if a signal -- ANY
signal -- is caught while the read is pending. This can occur not only when
the user types the quit character, but also during telnet negotiations, when
the lower CONNECT fork signals the upper one about an echoing mode change.
When this happens, we have to post the read() again. This is apparently not
a problem in BSD-based UNIX versions.
*/
if (errno == EINTR) /* Read interrupted. */
if (conesc) { /* If by SIGQUIT, */
conesc = 0; /* the conesc variable is set, */
return(escchr); /* so return the escape character. */
} else continue; /* By other signal, try again. */
#else
/*
This might be dangerous, but let's do this on non-System V versions too,
since at least one SunOS 4.1.2 user complains of immediate disconnections
upon first making a TELNET connection.
*/
if (errno == EINTR) /* Read interrupted. */
continue;
#endif /* SVORPOSIX */
#else /* OXOS */
if (errno == EINTR) /* Read interrupted. */
continue;
#endif /* OXOS */
return(-1); /* Error */
}
}
if (timo <= 0)
/* This should never happen */
debug(F100,"coninc HORRIBLE ERROR","",0);
/* Timed read... */
saval = signal(SIGALRM,timerh); /* Set up timeout handler. */
xx = alarm(timo); /* Set the alarm. */
debug(F101,"coninc alarm set","",xx);
if (
#ifdef CK_POSIX_SIG
sigsetjmp(sjbuf,1)
#else
setjmp(sjbuf)
#endif /* CK_POSIX_SIG */
) /* The read() timed out. */
n = -2; /* Code for timeout. */
else
n = read(0, &ch, 1);
ttimoff(); /* Turn off timer */
if (n > 0) /* Got character OK. */
return((unsigned)(ch & 0xff)); /* Return it. */
/*
read() returned an error. Same deal as above, but without the loop.
*/
debug(F101, "coninc(timo) n","",n);
debug(F101, "coninc(timo) errno","",errno);
#ifndef OXOS
#ifdef SVORPOSIX
if (n == -1 && errno == EINTR && conesc != 0) {
conesc = 0;
return(escchr); /* User entered escape character. */
} else /* n == 0 shouldn't happen. */
#endif /* SVORPOSIX */
#endif /* ! OXOS */
return(-1);
}
/* C O N G K S -- Console Get Keyboard Scancode */
#ifndef congks
/*
This function needs to be filled in with the various system-dependent
system calls used by SUNOS, NeXT OS, Xenix, Aviion, etc, to read a full
keyboard scan code. For now, it's a dummy.
*/
int
congks(timo) int timo; {
return(coninc(timo));
}
#endif /* congks */
#ifdef ATT7300
/* A T T D I A L -- Dial up the remote system using internal modem
* Purpose: to open and dial a number on the internal modem available on the
* ATT7300 UNIX PC. Written by Joe Doupnik. Superceeds version written by
* Richard E. Hill, Dickinson, TX. which employed dial(3c).
* Uses information in <sys/phone.h> and our status int attmodem.
*/
attdial(ttname,speed,telnbr) char *ttname,*telnbr; long speed; {
char *telnum;
int ttclos();
attmodem &= ~ISMODEM; /* modem not in use yet */
/* Ensure O_NDELAY is set, else i/o traffic hangs */
/* We turn this flag off once the dial is complete */
fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) | O_NDELAY);
/* Condition line, check availability & DATA mode, turn on speaker */
if (ioctl(ttyfd,PIOCOFFHOOK, &dialer) == -1) {
printf("cannot access phone\n");
ttclos(0);
return (-2);
}
ioctl(ttyfd,PIOCGETP,&dialer); /* get phone dialer parameters */
if (dialer.c_lineparam & VOICE) { /* phone must be in DATA mode */
printf(" Should not dial with modem in VOICE mode.\n");
printf(" Exit Kermit, switch to DATA and retry call.\n");
ttclos(0);
return (-2);
}
#ifdef ATTTONED /* Old way, tone dialing only. */
dialer.c_lineparam = DATA | DTMF; /* Dial with tones, */
dialer.c_lineparam &= ~PULSE; /* not with pulses. */
#else
/* Leave current pulse/tone state alone. */
/* But what about DATA? Add it back if you have trouble. */
/* sys/phone says you get DATA automatically by opening device RDWR */
#endif
dialer.c_waitdialtone = 5; /* wait 5 sec for dialtone */
#ifdef COMMENT
dialer.c_feedback = SPEAKERON|NORMSPK|RINGON; /* control speaker */
#else
/* sys/phone says RINGON used only for incoming voice calls */
dialer.c_feedback &= ~(SOFTSPK|LOUDSPK);
dialer.c_feedback |= SPEAKERON|NORMSPK;
#endif
dialer.c_waitflash = 500; /* 0.5 sec flash hook */
if(ioctl(ttyfd,PIOCSETP,&dialer) == -1) { /* set phone parameters */
printf("Cannot set modem characteristics\n");
ttclos(0);
return (-2);
}
ioctl(ttyfd,PIOCRECONN,0); /* Turns on speaker for pulse */
#ifdef COMMENT
fprintf(stderr,"Phone line status. line_par:%o dialtone_wait:%o \
line_status:%o feedback:%o\n",
dialer.c_lineparam, dialer.c_waitdialtone,
dialer.c_linestatus, dialer.c_feedback);
#endif
attmodem |= ISMODEM; /* modem is now in-use */
sleep(1);
for (telnum = telnbr; *telnum != '\0'; telnum++) /* dial number */
#ifdef ATTTONED
/* Tone dialing only */
if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
perror("Error in dialing");
ttclos(0);
return(-2);
}
#else /* Allow Pulse or Tone dialing */
switch (*telnum) {
case 't': case 'T': case '%': /* Tone dialing requested */
dialer.c_lineparam |= DTMF;
dialer.c_lineparam &= ~PULSE;
if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
printf("Cannot set modem to tone dialing\n");
ttclos(0);
return(-2);
}
break;
case 'd': case 'D': case 'p': case 'P': case '^':
dialer.c_lineparam |= PULSE;
dialer.c_lineparam &= ~DTMF;
if (ioctl(ttyfd,PIOCSETP,&dialer) == -1) {
printf("Cannot set modem to pulse dialing\n");
ttclos(0);
return(-2);
}
break;
default:
if (ioctl(ttyfd,PIOCDIAL,telnum) != 0) {
perror("Dialing error");
ttclos(0);
return(-2);
}
break;
}
#endif
ioctl(ttyfd,PIOCDIAL,"@"); /* terminator for data call */
do { /* wait for modems to Connect */
if (ioctl(ttyfd,PIOCGETP,&dialer) != 0) { /* get params */
perror("Cannot get modems to connect");
ttclos(0);
return(-2);
}
} while ((dialer.c_linestatus & MODEMCONNECTED) == 0);
/* Turn off O_NDELAY flag now. */
fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) & ~O_NDELAY);
signal(SIGHUP, ttclos); /* hangup on loss of carrier */
return(0); /* return success */
}
/*
Offgetty, ongetty functions. These function get the 'getty(1m)' off
and restore it to the indicated line. Shell's return codes are:
0: Can't do it. Probably a user logged on.
1: No need. No getty on that line.
2: Done, you should restore the getty when you're done.
DOGETY System(3), however, returns them as 0, 256, 512, respectively.
Thanks to Kevin O'Gorman, Anarm Software Systems.
getoff.sh looks like: geton.sh looks like:
setgetty $1 0 setgetty $1 1
err=$? exit $?
sleep 2
exit $err
*/
/* O F F G E T T Y -- Turn off getty(1m) for the communications tty line
* and get status so it can be restarted after the line is hung up.
*/
int
offgetty(ttname) char *ttname; {
char temp[30];
while (*ttname != '\0') ttname++; /* seek terminator of path */
ttname -= 3; /* get last 3 chars of name */
sprintf(temp,"/usr/bin/getoff.sh %s",ttname);
return(zsyscmd(temp));
}
/* O N G E T T Y -- Turn on getty(1m) for the communications tty line */
int
ongetty(ttname) char *ttname; {
char temp[30];
while (*ttname != '\0') ttname++; /* comms tty path name */
ttname -= 3;
sprintf(temp,"/usr/bin/geton.sh %s",ttname);
return(zsyscmd(temp));
}
#endif /* ATT7300 */
/* T T S C A R R -- Set ttcarr variable, controlling carrier handling.
*
* 0 = Off: Always ignore carrier. E.g. you can connect without carrier.
* 1 = On: Heed carrier, except during dialing. Carrier loss gives disconnect.
* 2 = Auto: For "modem direct": The same as "Off".
* For real modem types: Heed carrier during connect, but ignore
* it anytime else. Compatible with pre-5A C-Kermit versions.
*
* As you can see, this setting does not affect dialing, which always ignores
* carrier (unless there is some special exception for some modem type). It
* does affect ttopen() if it is set before ttopen() is used. This setting
* takes effect on the next call to ttopen()/ttpkt()/ttvt(). And they are
* (or should be) always called before any communications is tried, which
* means that, practically speaking, the effect is immediate.
*
* Of course, nothing of this applies to remote mode (xlocal = 0).
*
* Someone has yet to uncover how to manipulate the carrier in the BSD
* environment (or any non-termio using environment). Until that time, this
* will simply be a no-op for BSD.
*
* Note that in previous versions, the carrier was most often left unchanged
* in ttpkt()/ttvt() unless they were called with FLO_DIAL or FLO_DIAX. This
* has changed. Now it is controlled by ttcarr in conjunction with these
* modes.
*/
int
ttscarr(carrier) int carrier; {
ttcarr = carrier;
debug(F101, "ttscarr","",ttcarr);
return(ttcarr);
}
/* C A R R C T L -- Set tty modes for carrier treatment.
*
* Sets the appropriate bits in a termio or sgttyb struct for carrier control
* (actually, there are no bits in sgttyb for that), or performs any other
* operations needed to control this on the current system. The function does
* not do the actual TCSETA or stty, since often we want to set other bits too
* first. Don't call this function when xlocal is 0, or the tty is not opened.
*
* We don't know how to do anything like carrier control on non-ATTSV systems,
* except, apparently, ultrix. See above. It is also known that this doesn't
* have much effect on a Xenix system. For Xenix, one should switch back and
* forth between the upper and lower case device files. Maybe later.
* Presently, Xenix will stick to the mode it was opened with.
*
* carrier: 0 = ignore carrier, 1 = require carrier.
* The current state is saved in curcarr, and checked to save labour.
*/
#ifdef SVORPOSIX
int
#ifdef BSD44ORPOSIX
carrctl(ttpar, carrier) struct termios *ttpar; int carrier;
#else /* ATTSV */
carrctl(ttpar, carrier) struct termio *ttpar; int carrier;
#endif /* BSD44ORPOSIX */
/* carrctl */ {
debug(F101, "carrctl","",carrier);
if (carrier)
ttpar->c_cflag &= ~CLOCAL;
else
ttpar->c_cflag |= CLOCAL;
return(0);
}
#else /* Berkeley, V7, et al... */
int
carrctl(ttpar, carrier) struct sgttyb *ttpar; int carrier; {
debug(F101, "carrctl","",carrier);
if (carrier == curcarr)
return(0);
curcarr = carrier;
#ifdef ultrix
#ifdef COMMENT
/*
Old code from somebody at DEC that tends to get stuck, time out, etc.
*/
if (carrier) {
ioctl(ttyfd, TIOCMODEM, &temp);
ioctl(ttyfd, TIOCHPCL, 0);
} else {
/* (According to the manuals, TIOCNCAR should be preferred */
/* over TIOCNMODEM...) */
ioctl(ttyfd, TIOCNMODEM, &temp);
}
#else
/*
New code from Jamie Watson that, he says, eliminates the problems.
*/
if (carrier) {
ioctl(ttyfd, TIOCCAR);
ioctl(ttyfd, TIOCHPCL);
} else {
ioctl(ttyfd, TIOCNCAR);
}
#endif /* COMMENT */
#endif /* ultrix */
return(0);
}
#endif /* SVORPOSIX */
/* T T G M D M -- Get modem signals */
/*
Looks for RS-232 modem signals, and returns those that are on in as its
return value, in a bit mask composed of the BM_xxx values defined in ckcdeb.h.
Returns:
-3 Not implemented
-2 if the communication device does not have modem control (e.g. telnet)
-1 on error.
>= 0 on success, with a bit mask containing the modem signals that are on.
*/
/*
Define the symbol K_MDMCTL if we have Sys V R3 / 4.3 BSD style
modem control, namely the TIOCMGET ioctl.
*/
#ifdef BSD43
#define K_MDMCTL
#endif /* BSD43 */
#ifdef SUNOS4
#define K_MDMCTL
#endif /* SUNOS4 */
/*
SCO OpenServer R5.0.4. The TIOCMGET definition is hardwired in because it
is skipped in termio.h when _POSIX_SOURCE is defined. But _POSIX_SOURCE
must be defined in order to get the high serial speeds that are new to
5.0.4. However, the regular SCO drivers do not implement TIOCMGET, so the
ioctl() returns -1 with errno 22 (invalid function). But third-party
drivers, e.g. for Digiboard, do implement it, and so it should work on ports
driven by those drivers.
*/
#ifdef SCO_OSR504
#ifndef TIOCMGET
#define TIOCMGET (('t'<<8)|29)
#endif /* TIOCMGET */
#endif /* SCO_OSR504 */
#ifdef QNX
#define K_MDMCTL
#else
#ifdef TIOCMGET
#define K_MDMCTL
#endif /* TIOCMGET */
#endif /* QNX */
int
ttgmdm() {
#ifdef QNX
#include <sys/qioctl.h>
unsigned long y, mdmbits[2] = { 0L, 0L };
int z = 0;
if (xlocal && ttyfd < 0)
return(-1);
if (ttpipe)
return(-2);
if (!qnx_ioctl(ttyfd, QCTL_DEV_CTL, &mdmbits[0], 8, &mdmbits[0], 4)) {
y = mdmbits[0];
if (y & 0x100000L) z |= BM_CTS; /* Values from comment */
if (y & 0x200000L) z |= BM_DSR; /* in sys/qioctl.h */
if (y & 0x800000L) z |= BM_DCD;
if (y & 0x400000L) z |= BM_RNG;
if (y & 0x000001L) z |= BM_DTR;
if (y & 0x000002L) z |= BM_RTS;
return(z);
} else return(-1);
#else
#ifdef HPUX /* HPUX has its own way */
int x, z;
#ifdef HPUX10 /* Modem flag word */
mflag y; /* mflag typedef'd in <sys/modem.h> */
#else
#ifdef HPUX9
mflag y;
#else
#ifdef HPUX8
mflag y;
#else
unsigned long y; /* Not sure about pre-8.0... */
#endif /* HPUX8 */
#endif /* HPUX9 */
#endif /* HPUX10 */
if (xlocal && ttyfd < 0)
return(-1);
if (netconn) /* Network connection */
return(-2); /* No modem signals */
if (ttpipe)
return(-2);
if (xlocal) /* Get modem signals */
x = ioctl(ttyfd,MCGETA,&y);
else
x = ioctl(0,MCGETA,&y);
if (x < 0) return(-1);
debug(F101,"ttgmdm","",y);
z = 0; /* Initialize return value */
/* Now set bits for each modem signal that is reported to be on. */
#ifdef MCTS
/* Clear To Send */
if (y & MCTS) z |= BM_CTS;
#endif
#ifdef MDSR
/* Data Set Ready */
if (y & MDSR) z |= BM_DSR;
#endif
#ifdef MDCD
/* Carrier */
if (y & MDCD) z |= BM_DCD;
#endif
#ifdef MRI
/* Ring Indicate */
if (y & MRI) z |= BM_RNG;
#endif
#ifdef MDTR
/* Data Terminal Ready */
if (y & MDTR) z |= BM_DTR;
#endif
#ifdef MRTS
/* Request To Send */
if (y & MRTS) z |= BM_RTS;
#endif
return(z);
#else /* ! HPUX */
#ifdef K_MDMCTL
/*
Note, TIOCMGET might already have been defined in <sys/ioctl.h> or elsewhere.
If not, we try including <sys/ttycom.h> -- if this blows up then more ifdefs
are needed.
*/
#ifndef TIOCMGET
#include <sys/ttycom.h>
#endif /* TIOCMGET */
int x, y, z;
debug(F100,"ttgmdm K_MDMCTL defined","",0);
if (netconn) /* Network connection */
return(-2); /* No modem signals */
if (ttpipe)
return(-2);
if (xlocal && ttyfd < 0)
return(-1);
if (xlocal)
x = ioctl(ttyfd,TIOCMGET,&y); /* Get modem signals. */
else
x = ioctl(0,TIOCMGET,&y);
debug(F101,"ttgmdm TIOCMGET ioctl","",x);
if (x < 0) {
debug(F101,"ttgmdm errno","",errno);
return(-1);
}
debug(F101,"ttgmdm bits","",y);
z = 0; /* Initialize return value. */
#ifdef TIOCM_CTS
/* Clear To Send */
if (y & TIOCM_CTS) z |= BM_CTS;
#endif
#ifdef TIOCM_DSR
/* Data Set Ready */
if (y & TIOCM_DSR) z |= BM_DSR;
#endif
#ifdef TIOCM_CAR
/* Carrier */
if (y & TIOCM_CAR) z |= BM_DCD;
#endif
#ifdef TIOCM_RNG
/* Ring Indicate */
if (y & TIOCM_RNG) z |= BM_RNG;
#endif
#ifdef TIOCM_DTR
/* Data Terminal Ready */
if (y & TIOCM_DTR) z |= BM_DTR;
#endif
#ifdef TIOCM_RTS
/* Request To Send */
if (y & TIOCM_RTS) z |= BM_RTS;
#endif
return(z);
#else /* !K_MDMCTL catch-All */
debug(F100,"ttgmdm K_MDMCTL not defined","",0);
#ifdef TIOCMGET
debug(F100,"ttgmdm TIOCMGET defined","",0);
#else
debug(F100,"ttgmdm TIOCMGET not defined","",0);
#endif /* TIOCMGET */
#ifdef _SVID3
debug(F100,"ttgmdm _SVID3 defined","",0);
#else
debug(F100,"ttgmdm _SVID3 not defined","",0);
#endif /* _SVID3 */
if (netconn) /* Network connection */
return(-2); /* No modem signals */
if (ttpipe)
return(-2);
return(-3); /* Sorry, I don't know how... */
#endif /* K_MDMCTL */
#endif /* HPUX */
#endif /* QNX */
}
/* P S U S P E N D -- Put this process in the background. */
/*
Call with flag nonzero if suspending is allowed, zero if not allowed.
Returns 0 on apparent success, -1 on failure (flag was zero, or
kill() returned an error code.
*/
int
psuspend(flag) int flag; {
#ifdef RTU
extern int rtu_bug;
#endif /* RTU */
if (flag == 0) return(-1);
#ifdef NOJC
return(-1);
#else
#ifdef SIGTSTP
/*
The big question here is whether job control is *really* supported.
There's no way Kermit can know for sure. The fact that SIGTSTP is
defined does not guarantee the Unix kernel supports it, and the fact
that the Unix kernel supports it doesn't guarantee that the user's
shell (or other process that invoked Kermit) supports it.
*/
#ifdef RTU
rtu_bug = 1;
#endif /* RTU */
if (kill(0,SIGSTOP) < 0
#ifdef MIPS
/* Let's try this for MIPS too. */
&& kill(getpid(),SIGSTOP) < 0
#endif /* MIPS */
) { /* If job control, suspend the job */
perror("suspend");
debug(F101,"psuspend error","",errno);
return(-1);
}
debug(F100,"psuspend ok","",0);
return(0);
#else
return(-1);
#endif /* SIGTSTP */
#endif /* NOJC */
}
/*
setuid package, by Kristoffer Eriksson, with contributions from Dean
Long and fdc.
*/
/* The following is for SCO when CK_ANSILIBS is defined... */
#ifdef M_UNIX
#ifdef CK_ANSILIBS
#ifndef NOGETID_PROTOS
#define NOGETID_PROTOS
#endif /* NOGETID_PROTOS */
#endif /* CK_ANSILIBS */
#endif /* M_UNIX */
#ifndef _POSIX_SOURCE
#ifndef SUNOS4
#ifndef NEXT
#ifndef PS2AIX10
#ifndef sequent
#ifndef NOGETID_PROTOS
extern UID_T getuid(), geteuid(), getreuid();
extern GID_T getgid(), getegid(), getregid();
#endif /* NOGETID_PROTOS */
#endif /* sequent */
#endif /* PS2AIX10 */
#endif /* NEXT */
#endif /* SUNOS4 */
#endif /* _POSIX_SOURCE */
/*
Subject: Set-user-id
To: fdc@watsun.cc.columbia.edu (Frank da Cruz)
Date: Sat, 21 Apr 90 4:48:25 MES
From: Kristoffer Eriksson <ske@pkmab.se>
This is a set of functions to be used in programs that may be run set-user-id
and/or set-group-id. They handle both the case where the program is not run
with such privileges (nothing special happens then), and the case where one
or both of these set-id modes are used. The program is made to run with the
user's real user and group ids most of the time, except for when more
privileges are needed. Don't set-user-id to "root".
This works on System V and POSIX. In BSD, it depends on the
"saved-set-user-id" feature.
*/
#define UID_ROOT 0 /* Root user and group ids */
#define GID_ROOT 0
/*
The following code defines the symbol SETEUID for UNIX systems based
on BSD4.4 (either -Encumbered or -Lite). This program will then use
seteuid() and setegid() instead of setuid() and setgid(), which still
don't allow arbitrary switching. It also avoids setreuid() and
setregid(), which are included in BSD4.4 for compatibility only, are
insecure, and print warnings to stderr under at least one system (NetBSD
1.0). Note that POSIX systems should still use setuid() and setgid();
the seteuid() and setegid() functions are BSD4.4 extensions to the
POSIX model. Mike Long <mike.long@analog.com>, 8/94.
*/
#ifdef BSD44
#define SETEUID
#endif /* BSD44 */
/*
The following construction automatically defines the symbol SETREUID for
UNIX versions based on Berkeley Unix 4.2 and 4.3. If this symbol is
defined, then this program will use getreuid() and getregid() calls in
preference to getuid() and getgid(), which in Berkeley-based Unixes do
not allow arbitrary switching back and forth of real & effective uid.
This construction also allows -DSETREUID to be put on the cc command line
for any system that has and wants to use setre[ug]id(). It also prevents
automatic definition of SETREUID if -DNOSETREU is included on the cc
command line (or otherwise defined).
*/
#ifdef FT18 /* None of this for Fortune. */
#define NOSETREU
#endif /* FT18 */
#ifdef ANYBSD
#ifndef BSD29
#ifndef BSD41
#ifndef SETREUID
#ifndef NOSETREU
#ifndef SETEUID
#define SETREUID
#endif /* SETEUID */
#endif /* NOSETREU */
#endif /* SETREUID */
#endif /* !BSD41 */
#endif /* !BSD29 */
#endif /* ANYBSD */
/* Variables for user and group IDs. */
static UID_T realuid = (UID_T) -1, privuid = (UID_T) -1;
static GID_T realgid = (GID_T) -1, privgid = (GID_T) -1;
/* P R I V _ I N I -- Initialize privileges package */
/* Called as early as possible in a set-uid or set-gid program to store the
* set-to uid and/or gid and step down to the users real uid and gid. The
* stored id's can be temporarily restored (allowed in System V) during
* operations that require the privilege. Most of the time, the program
* should execute in unpriviliged state, to not impose any security threat.
*
* Note: Don't forget that access() always uses the real id:s to determine
* file access, even with privileges restored.
*
* Returns an error mask, with error values or:ed together:
* 1 if setuid() fails,
* 2 if setgid() fails, and
* 4 if the program is set-user-id to "root", which can't be handled.
*
* Only the return value 0 indicates real success. In case of failure,
* those privileges that could be reduced have been, at least, but the
* program should be aborted none-the-less.
*
* Also note that these functions do not expect the uid or gid to change
* without their knowing. It may work if it is only done temporarily, but
* you're on your own.
*/
int
priv_ini() {
int err = 0;
/* Save real ID:s. */
realuid = getuid();
realgid = getgid();
/* Save current effective ID:s, those set to at program exec. */
privuid = geteuid();
privgid = getegid();
/* If running set-uid, go down to real uid, otherwise remember that
* no privileged uid is available.
*
* Exceptions:
*
* 1) If the real uid is already "root" and the set-uid uid (the
* initial effective uid) is not "root", then we would have trouble
* if we went "down" to "root" here, and then temporarily back to the
* set-uid uid (not "root") and then again tried to become "root". I
* think the "saved set-uid" is lost when changing uid from effective
* uid "root", which changes all uid, not only the effective uid. But
* in this situation, we can simply go to "root" and stay there all
* the time. That should give sufficient privilege (understatement!),
* and give the right uids for subprocesses.
*
* 2) If the set-uid (the initial effective uid) is "root", and we
* change uid to the real uid, we can't change it back to "root" when
* we need the privilege, for the same reason as in 1). Thus, we can't
* handle programs that are set-user-id to "root" at all. The program
* should be stopped. Use some other uid. "root" is probably too
* privileged for such things, anyway. (The uid is reverted to the
* real uid until termination.)
*
* These two exceptions have the effect that the "root" uid will never
* be one of the two uids that are being switched between, which also
* means we don't have to check for such cases in the switching
* functions.
*
* Note that exception 1) is handled by these routines (by constantly
* running with uid "root", while exception 2) is a serious error, and
* is not provided for at all in the switching functions.
*/
if (realuid == privuid)
privuid = (UID_T) -1; /* Not running set-user-id. */
/* If running set-gid, go down to real gid, otherwise remember that
* no privileged gid is available.
*
* There are no exception like there is for the user id, since there
* is no group id that is privileged in the manner of uid "root".
* There could be equivalent problems for group changing if the
* program sometimes ran with uid "root" and sometimes not, but
* that is already avoided as explained above.
*
* Thus we can expect always to be able to switch to the "saved set-
* gid" when we want, and back to the real gid again. You may also
* draw the conclusion that set-gid provides for fewer hassles than
* set-uid.
*/
if (realgid == privgid) /* If not running set-user-id, */
privgid = (GID_T) -1; /* remember it this way. */
err = priv_off(); /* Turn off setuid privilege. */
if (privuid == UID_ROOT) /* If setuid to root, */
err |= 4; /* return this error. */
if (realuid == UID_ROOT) { /* If real id is root, */
privuid = (UID_T) -1; /* stay root at all times. */
#ifdef ATT7300
/* If Kermit installed SUID uucp and user is running as root */
err &= ~1; /* System V R0 does not save UID */
#endif /* ATT7300 */
}
return(err);
}
/* Macros for hiding the differences in UID/GID setting between various Unix
* systems. These macros should always be called with both the privileged ID
* and the non-privileged ID. The one in the second argument, will become the
* effective ID. The one in the first argument will be retained for later
* retrieval.
*/
#ifdef SETREUID
#ifdef SAVEDUID
/* On BSD systems with the saved-UID feature, we just juggle the effective
* UID back and forth, and leave the real UID at its true value. The kernel
* allows switching to both the current real UID, the effective UID, and the
* UID which the program is set-UID to. The saved set-UID always holds the
* privileged UID for us, and the real UID will always be the non-privileged,
* and we can freely choose one of them for the effective UID at any time.
*/
#define switchuid(hidden,active) setreuid( (UID_T) -1, active)
#define switchgid(hidden,active) setregid( (GID_T) -1, active)
#else /* SETREUID,!SAVEDUID */
/* On systems with setreXid() but without the saved-UID feature, notably
* BSD 4.2, we swap the real and effective UIDs each time. It's
* the effective UID that we are interested in, but we have to retain the
* unused UID somewhere to enable us to restore it later, and we do this
* in the real UID. The kernel only allows switching to either the current
* real or the effective UID, unless you're "root".
*/
#define switchuid(hidden,active) setreuid(hidden,active)
#define switchgid(hidden,active) setregid(hidden,active)
#endif
#else /* !SETREUID, !SAVEDUID */
#ifdef SETEUID
/*
BSD 4.4 works similarly to System V and POSIX (see below), but uses
seteXid() instead of setXid() to change effective IDs. In addition, the
seteXid() functions work the same for "root" as for other users.
*/
#define switchuid(hidden,active) seteuid(active)
#define switchgid(hidden,active) setegid(active)
#else /* !SETEUID */
/* On System V and POSIX, the only thing we can change is the effective UID
* (unless the current effective UID is "root", but initsuid() avoids that for
* us). The kernel allows switching to the current real UID or to the saved
* set-UID. These are always set to the non-privileged UID and the privileged
* UID, respectively, and we only change the effective UID. This breaks if
* the current effective UID is "root", though, because for "root" setuid/gid
* becomes more powerful, which is why initsuid() treats "root" specially.
* Note: That special treatment maybe could be ignored for BSD? Note: For
* systems that don't fit any of these four cases, we simply can't support
* set-UID.
*/
#define switchuid(hidden,active) setuid(active)
#define switchgid(hidden,active) setgid(active)
#endif /* SETEUID */
#endif /* SETREUID */
/* P R I V _ O N -- Turn on the setuid and/or setgid */
/* Go to the privileged uid (gid) that the program is set-user-id
* (set-group-id) to, unless the program is running unprivileged.
* If setuid() fails, return value will be 1. If getuid() fails it
* will be 2. Return immediately after first failure, and the function
* tries to restore any partial work done. Returns 0 on success.
* Group id is changed first, since it is less serious than user id.
*/
int
priv_on() {
if (privgid != (GID_T) -1)
if (switchgid(realgid,privgid))
return(2);
if (privuid != (UID_T) -1)
if (switchuid(realuid,privuid)) {
if (privgid != (GID_T) -1)
switchgid(privgid,realgid);
return(1);
}
return(0);
}
/* P R I V _ O F F -- Turn on the real uid and gid */
/* Return to the unprivileged uid (gid) after an temporary visit to
* privileged status, unless the program is running without set-user-id
* (set-group-id). Returns 1 for failure in setuid() and 2 for failure
* in setgid() or:ed together. The functions tries to return both uid
* and gid to unprivileged state, regardless of errors. Returns 0 on
* success.
*/
int
priv_off() {
int err = 0;
if (privuid != (UID_T) -1)
if (switchuid(privuid,realuid))
err |= 1;
if (privgid != (GID_T) -1)
if (switchgid(privgid,realgid))
err |= 2;
return(err);
}
/* Turn off privilege permanently. No going back. This is necessary before
* a fork() on BSD43 machines that don't save the setUID or setGID, because
* we swap the real and effective ids, and we don't want to let the forked
* process swap them again and get the privilege back. It will work on other
* machines too, such that you can rely on its effect always being the same,
* for instance, even when you're in priv_on() state when this is called.
* (Well, that part about "permanent" is on System V only true if you follow
* this with a call to exec(), but that's what we want it for anyway.)
* Added by Dean Long -- dlong@midgard.ucsc.edu
*/
int
priv_can() {
#ifdef SETREUID
int err = 0;
if (privuid != (UID_T) -1)
if (setreuid(realuid,realuid))
err |= 1;
if (privgid != (GID_T) -1)
if (setregid(realgid,realgid))
err |= 2;
return(err);
#else
#ifdef SETEUID
int err = 0;
if (privuid != (UID_T) -1)
if (setuid(realuid)) {
debug(F101,"setuid failed","",errno);
err |= 1;
debug(F101,"ruid","",getuid());
debug(F101,"euid","",geteuid());
}
debug(F101,"setuid","",realuid);
if (privgid != (GID_T) -1)
if (setgid(realgid)) {
debug(F101,"setgid failed","",errno);
err |= 2;
debug(F101,"rgid","",getgid());
debug(F101,"egid","",getegid());
}
debug(F101,"setgid","",realgid);
return(err);
#else
/* Easy way of using setuid()/setgid() instead of setreuid()/setregid().*/
return(priv_off());
#endif /* SETEUID */
#endif /* SETREUID */
}
/* P R I V _ O P N -- For opening protected files or devices. */
int
priv_opn(name, modes) char *name; int modes; {
int x;
priv_on(); /* Turn privileges on */
x = open(name, modes); /* Try to open the device */
priv_off(); /* Turn privileges off */
return(x); /* Return open's return code */
}
/* P R I V _ C H K -- Check privileges. */
/* Try to turn them off. If turning them off did not succeed, cancel them */
int
priv_chk() {
int x, y = 0;
x = priv_off(); /* Turn off privs. */
if (x != 0 || getuid() == privuid || geteuid() == privuid)
y = priv_can();
if (x != 0 || getgid() == privgid || getegid() == privgid)
y = y | priv_can();
return(y);
}
UID_T
real_uid() {
return(realuid);
}
VOID
ttimoff() { /* Turn off any timer interrupts */
/* int xx; */
/*
As of 5A(183), we set SIGALRM to SIG_IGN (to ignore alarms) rather than to
SIG_DFL (to catch alarms, or if there is no handler, to exit). This is to
cure (mask, really) a deeper problem with stray alarms that occurs on some
systems, possibly having to do with sleep(), that caused core dumps. It
should be OK to do this, because no code in this module uses nested alarms.
(But we still have to watch out for SCRIPT and DIAL...)
*/
/* xx = */ alarm(0);
/* debug(F101,"ttimoff alarm","",xx); */
if (saval) { /* Restore any previous */
signal(SIGALRM,saval); /* alarm handler. */
/* debug(F101,"ttimoff alarm restoring saval","",saval); */
saval = NULL;
} else {
signal(SIGALRM,SIG_IGN); /* Used to be SIG_DFL */
/* debug(F100,"ttimoff alarm SIG_IGN","",0); */
}
}
#ifdef CK_REDIR
#ifdef COMMENT
/* Old way - not portable */
int
ttruncmd(s) char *s; {
int r = 0; /* Return code */
/* 0 = failure, 1 = success */
#ifdef WIFEXITED
#ifndef WEXITSTATUS
#ifdef w_retcode
#define WEXITSTATUS(x) ((x).w_retcode)
#endif /* w_retcode */
#endif /* WEXITSTATUS */
#ifdef WEXITSTATUS
#define CK_FUN_OK
#endif /* WEXITSTATUS */
#endif /* WIFEXITED */
#ifdef NEXT
#define waitpid(pid,status,option) wait4((pid),(status),(option),NULL)
#else
#ifdef sony_news
#define waitpid(pid,status,option) wait4((pid),(status),(option),NULL)
#endif /* sony_news */
#endif /* NEXT */
#ifdef CK_FUN_OK
PID_T pid;
if (ttyfd == -1) {
printf("?Sorry, device is not open\n");
return(0);
}
conres(); /* Make console normal */
if ((pid = fork()) == 0) { /* Make a child fork */
/* give it stdin,out to the line */
if (priv_can()) /* Turn off privs. */
exit(1);
dup2(ttyfd, 0);
dup2(ttyfd, 1);
_exit(system(s) ? BAD_EXIT : 0);
} else {
WAIT_T status; /* This is int for all but NeXT */
SIGTYP (*istat)(), (*qstat)();
if (pid == (PID_T) -1) /* fork() failed? */
return(0);
istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
if (waitpid(pid, &status, 0) != pid) {
printf("?Can't wait for child process?\r\n");
} else {
if (WIFEXITED(status)) {
if (WEXITSTATUS(status)) {
printf("?Command exit status: %d\r\n",
WEXITSTATUS(status));
} else r = 1;
} else {
printf("?Command did not exit - cancelling it now.\r\n");
kill(pid, SIGKILL);
}
}
signal(SIGINT,istat); /* Restore interrupts */
signal(SIGQUIT,qstat);
}
concb((char)escchr); /* Restore console to CBREAK mode */
#else
printf("?Sorry, can't execute this command - pieces missing.\n");
#endif /* CK_FUN_OK */
return(r);
}
#else
int
ttruncmd(s) char *s; {
PID_T pid; /* pid of lower fork */
int wstat; /* for wait() */
int x;
#ifdef OSF40
/*
This is to shut up warnings from DECC - if it causes trouble, just remove
it, since the warnings don't seem to affect correct operation at runtime.
*/
union wait statusp_w;
int statusp;
#else
int statusp;
#endif /* OSF40 */
if (ttyfd == -1) {
printf("?Sorry, device is not open\n");
return(0);
}
conres(); /* Make console normal */
pexitstat = -4;
if ((pid = fork()) == 0) { /* Make a child fork */
if (priv_can()) /* Child: turn off privs. */
exit(1);
dup2(ttyfd, 0); /* Give stdin/out to the line */
dup2(ttyfd, 1);
x = system(s);
debug(F101,"ttruncmd system",s,x);
_exit(x ? BAD_EXIT : 0);
} else {
SIGTYP (*istat)(), (*qstat)();
if (pid == (PID_T) -1) /* fork() failed? */
return(0);
istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
#ifdef COMMENT
while (((wstat = wait(
#ifdef OSF40
&statusp_w
#else
&statusp
#endif /* OSF40 */
)) != pid)
&& (wstat != -1))
;
#else /* Not COMMENT */
while (1) {
wstat = wait(
#ifdef OSF40
&statusp_w
#else
&statusp
#endif /* OSF40 */
);
debug(F101,"ttruncmd wait","",wstat);
if (wstat == pid || wstat == -1)
break;
}
#endif /* COMMENT */
#ifdef OSF40
statusp = (*(int *)&(statusp_w));
#endif /* OSF40 */
pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
debug(F101,"ttruncmd wait statusp","",statusp);
debug(F101,"ttruncmd wait pexitstat","",pexitstat);
signal(SIGINT,istat); /* Restore interrupts */
signal(SIGQUIT,qstat);
}
concb((char)escchr); /* Restore console to CBREAK mode */
return(statusp == 0 ? 1 : 0);
}
#endif /* COMMENT */
#endif /* CK_REDIR */
#ifdef OXOS
#undef kill
#endif /* OXOS */
#ifdef OXOS
int
priv_kill(pid, sig) int pid, sig; {
int i;
if (priv_on())
debug(F100,"priv_kill priv_on failed","",0);
i = kill(pid, sig);
if (priv_off())
debug(F100,"priv_kill priv_off failed","",0);
return(i);
}
#endif /* OXOS */
#ifdef BEBOX
#ifdef BE_DR_7
/*
alarm() function not supplied with Be OS DR7 - this one contributed by
Neal P. Murphy.
*/
/*
This should mimic the UNIX/POSIX alarm() function well enough, with the
caveat that one's SIGALRM handler must call alarm_expired() to clean up vars
and wait for the alarm thread to finish.
*/
unsigned int
alarm(unsigned int seconds) {
long time_left = 0;
/* If an alarm is active, turn it off, saving the unused time */
if (alarm_thread != -1) {
/* We'll be generous and count partial seconds as whole seconds. */
time_left = alarm_struct.time -
((system_time() - time_started) / 1000000.0);
/* Kill the alarm thread */
kill_thread (alarm_thread);
/* We need to clean up as though the alarm occured. */
time_started = 0;
alarm_struct.thread = -1;
alarm_struct.time = 0;
alarm_expired();
}
/* Set a new alarm clock, if requested. */
if (seconds > 0) {
alarm_struct.thread = find_thread(NULL);
alarm_struct.time = seconds;
time_started = system_time();
alarm_thread = spawn_thread (do_alarm,
"alarm_thread",
B_NORMAL_PRIORITY,
(void *) &alarm_struct
);
resume_thread (alarm_thread);
}
/* Now return [unused time | 0] */
return ((unsigned int) time_left);
}
/*
This function is the departure from UNIX/POSIX alarm handling. In the case
of Be's missing alarm() function, this stuff needs to be done in the SIGALRM
handler. When Be implements alarm(), this function call can be eliminated
from user's SIGALRM signal handlers.
*/
void
alarm_expired(void) {
long ret_val;
if (alarm_thread != -1) {
wait_for_thread (alarm_thread, &ret_val);
alarm_thread = -1;
}
}
/*
This is the function that snoozes the requisite number of seconds and then
SIGALRMs the calling thread. Note that kill() wants a pid_t arg, whilst Be
uses thread_id; currently they are both typdef'ed as long, but I'll do the
cast anyway. This function is run in a separate thread.
*/
long
do_alarm (void *alarm_struct) {
snooze ((double) ((struct ALARM_STRUCT *) alarm_struct)->time * 1000000.0);
kill ((pid_t)((struct ALARM_STRUCT *) alarm_struct)->thread, SIGALRM);
time_started = 0;
((struct ALARM_STRUCT *) alarm_struct)->thread = -1;
((struct ALARM_STRUCT *) alarm_struct)->time = 0;
}
#endif /* BE_DR_7 */
#endif /* BEBOX */
#ifdef Plan9
int
p9ttyctl(char letter, int num, int param) {
char cmd[20];
int len;
if (ttyctlfd < 0)
return -1;
cmd[0] = letter;
if (num)
len = sprintf(cmd + 1, "%d", param) + 1;
else {
cmd[1] = param;
len = 2;
}
if (write(ttyctlfd, cmd, len) == len) {
cmd[len] = 0;
/* fprintf(stdout, "wrote '%s'\n", cmd); */
return 0;
}
return -1;
}
int
p9ttyparity(char l) {
return p9ttyctl('p', 0, l);
}
int
p9tthflow(int flow, int status) {
return p9ttyctl('m', 1, status);
}
int
p9ttsspd(int cps) {
if (p9ttyctl('b', 1, cps * 10) < 0)
return -1;
ttylastspeed = cps * 10;
return 0;
}
int
p9openttyctl(char *ttname) {
char name[100];
if (ttyctlfd >= 0) {
close(ttyctlfd);
ttyctlfd = -1;
ttylastspeed = -1;
}
sprintf(name, "%sctl", ttname);
ttyctlfd = open(name, 1);
return ttyctlfd;
}
int
p9concb() {
if (consctlfd >= 0) {
if (write(consctlfd, "rawon", 5) == 5)
return 0;
}
return -1;
}
int
p9conbin() {
return p9concb();
}
int
p9conres() {
if (consctlfd >= 0) {
if (write(consctlfd, "rawoff", 6) == 6)
return 0;
}
return -1;
}
int
p9sndbrk(int msec) {
if (ttyctlfd >= 0) {
char cmd[20];
int i = sprintf(cmd, "k%d", msec);
if (write(ttyctlfd, cmd, i) == i)
return 0;
}
return -1;
}
int
conwrite(char *buf, int n) {
int x;
static int length = 0;
static int holdingcr = 0;
int normal = 0;
for (x = 0; x < n; x++) {
char c = buf[x];
if (c == 007) {
if (normal) {
write(1, buf + (x - normal), normal);
length += normal;
normal = 0;
}
/* write(noisefd, "1000 300", 8); */
holdingcr = 0;
} else if (c == '\r') {
if (normal) {
write(1, buf + (x - normal), normal);
length += normal;
normal = 0;
}
holdingcr = 1;
} else if (c == '\n') {
write(1, buf + (x - normal), normal + 1);
normal = 0;
length = 0;
holdingcr = 0;
} else if (c == '\b') {
if (normal) {
write(1, buf + (x - normal), normal);
length += normal;
normal = 0;
}
if (length) {
write(1, &c, 1);
length--;
}
holdingcr = 0;
} else {
if (holdingcr) {
char b = '\b';
while (length-- > 0)
write(1, &b, 1);
length = 0; /* compiler bug */
}
holdingcr = 0;
normal++;
}
}
if (normal) {
write(1, buf + (x - normal), normal);
length += normal;
}
return n;
}
void
conprint(char *fmt, ...) {
char buf[1000];
va_list ap;
int i;
va_start(ap, fmt);
i = vsprintf(buf, fmt, ap);
conwrite(buf, i);
}
#endif /* Plan9 */
|