| 0. 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. | /* * Copyright, 1991, 1992, by Leendert van Doorn ([email protected]) * * This material is copyrighted by Leendert van Doorn, 1991, 1992. The usual * standard disclaimer applies, especially the fact that the author nor the * Vrije Universiteit, Amsterdam are liable for any damages caused by direct or * indirect use of the information or functionality provided by this program. */ /* * nfs - A shell that provides access to NFS file systems */ #include <stdio.h> #include <string.h> #include <ctype.h> #include <signal.h> #include <setjmp.h> #include <netdb.h> #include <errno.h> #include <rpc/rpc.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/time.h> #include "mount.h" #include "nfs_prot.h" /* * Fundamental constants */ #define NARGVEC 100 /* maximum number of arguments */ /* * List of command identifiers */ #define CMD_UNKNOWN 0 /* unknown command */ #define CMD_HOST 1 /* host <host> */ #define CMD_UID 2 /* uid [<uid>] */ #define CMD_GID 3 /* gid [<gid>] */ #define CMD_CD 4 /* cd [<path>] */ #define CMD_LCD 5 /* lcd [<path>] */ #define CMD_CAT 6 /* cat <filespec> */ #define CMD_LS 7 /* ls [-l] <filespec> */ #define CMD_GET 8 /* get <filespec> */ #define CMD_DF 9 /* df */ #define CMD_MOUNT 10 /* mount [-u] [-p] [<host>:]<path> */ #define CMD_UMOUNT 11 /* umount */ #define CMD_UMOUNTALL 12 /* umountall */ #define CMD_EXPORT 13 /* export */ #define CMD_DUMP 14 /* dump */ #define CMD_STATUS 15 /* status */ #define CMD_HELP 16 /* help */ #define CMD_QUIT 17 /* quit */ #define CMD_RM 18 /* rm <file> */ #define CMD_LN 19 /* ln <file1> <file2> */ #define CMD_MV 20 /* mv <file1> <file2> */ #define CMD_MKDIR 21 /* mkdir <dir> */ #define CMD_RMDIR 22 /* rmdir <dir> */ #define CMD_CHMOD 23 /* chmod <mode> <file> */ #define CMD_CHOWN 24 /* chown <uid>[.<gid>] <file> */ #define CMD_PUT 25 /* put <local-file> [<remote-file>] */ #define CMD_HANDLE 26 /* handle [<file-handle>] /* * Key word table */ struct keyword { char *kw_command; int kw_value; char *kw_help; } keyword[] = { "host", CMD_HOST, "<host> - set remote host name", "uid", CMD_UID, "[<uid>] - set remote user id", "gid", CMD_GID, "[<gid>] - set remote group id", "cd", CMD_CD, "[<path>] - change remote working directory", "lcd", CMD_LCD, "[<path>] - change local working directory", "cat", CMD_CAT, "<filespec> - display remote file", "ls", CMD_LS, "[-l] <filespec> - list remote directory", "get", CMD_GET, "<filespec> - get remote files", "df", CMD_DF, "- file system information", "rm", CMD_RM, "<file> - delete remote file", "ln", CMD_LN, "<file1> <file2> - link file", "mv", CMD_MV, "<file1> <file2> - move file", "mkdir", CMD_MKDIR, "<dir> - make remote directory", "rmdir", CMD_RMDIR, "<dir> - remove remote directory", "chmod", CMD_CHMOD, "<mode> <file> - change mode", "chown", CMD_CHOWN, "<uid>[.<gid>] <file> - change owner", "put", CMD_PUT, "<local-file> [<remote-file>] - put file", "mount", CMD_MOUNT, "[-u] [-p] [<host>:]<path> - mount file system", "umount", CMD_UMOUNT, "- umount remote file system", "umountall",CMD_UMOUNTALL, "- umount all remote file systems", "export", CMD_EXPORT, "- show all exported file systems", "dump", CMD_DUMP, "- show all remote mounted file systems", "status", CMD_STATUS, "- general status report", "help", CMD_HELP, "- this help message", "quit", CMD_QUIT, "- name says it all", "handle", CMD_HANDLE, "[<handle>] - get/set directory file handle", }; /* run-time settable flags */ int verbose = 1; /* verbosity flag */ int interact = 1; /* interactive mode */ /* user provided credentials */ int uid = -2; /* remote user id (initialy nobody) */ int gid = -2; /* remote group id (initialy nobody) */ /* server information (also used as state information) */ char *mountpath; /* remote mount path */ char *remotehost; /* remote host name */ struct sockaddr_in server_addr; /* remote server address information */ struct sockaddr_in mntserver_addr; /* remote mount server address */ struct sockaddr_in nfsserver_addr; /* remote mount server address */ CLIENT *mntclient; /* mount RPC client */ CLIENT *nfsclient; /* nfs RPC client */ fhstatus *mountpoint; /* remote mount point */ fhandle directory_handle; /* current directory handle */ struct timeval timeout = { 60, 0 }; /* default time out */ int transfersize; /* NFS default transfer size */ /* interrupt environments */ jmp_buf intenv; /* where to go in interrupts */ fhstatus *pmap_mnt(); char *malloc(); char *calloc(); char *realloc(); char *strsave(); char *strchr(); char *nfs_error(); char *getenv(); void interrupt(); main(argc, argv) int argc; char **argv; { int opt, cmd, argcount; char *argvec[NARGVEC]; char buffer[BUFSIZ]; /* command line option processing */ while ((opt = getopt(argc, argv, "vi")) != EOF) { switch (opt) { case 'v': verbose = 0; break; case 'i': interact = 0; break; default: fprintf(stderr, "Usage: %s [-v]\n", argv[0]); exit(1); } } signal(SIGINT, interrupt); /* interpreter's main command loop */ if (setjmp(intenv)) putchar('\n'); while (getline(buffer, BUFSIZ, &argcount, argvec, NARGVEC)) { if (argcount == 0) continue; if ((cmd = command(argvec[0])) == CMD_QUIT) break; else switch (cmd) { case CMD_HOST: do_host(argcount, argvec); break; case CMD_UID: do_setid(&uid, argcount, argvec); break; case CMD_GID: do_setid(&gid, argcount, argvec); break; case CMD_CD: do_cd(argcount, argvec); break; case CMD_LCD: do_lcd(argcount, argvec); break; case CMD_CAT: do_cat(argcount, argvec); break; case CMD_LS: do_ls(argcount, argvec); break; case CMD_GET: do_get(argcount, argvec); break; case CMD_DF: do_df(argcount, argvec); break; case CMD_RM: do_rm(argcount, argvec); break; case CMD_LN: do_ln(argcount, argvec); break; case CMD_MV: do_mv(argcount, argvec); break; case CMD_MKDIR: do_mkdir(argcount, argvec); break; case CMD_RMDIR: do_rmdir(argcount, argvec); break; case CMD_CHMOD: do_chmod(argcount, argvec); break; case CMD_CHOWN: do_chown(argcount, argvec); break; case CMD_PUT: do_put(argcount, argvec); break; case CMD_HANDLE: do_handle(argcount, argvec); break; case CMD_MOUNT: do_mount(argcount, argvec); break; case CMD_UMOUNT: do_umount(argcount, argvec); break; case CMD_UMOUNTALL: do_umountall(argcount, argvec); break; case CMD_EXPORT: do_export(argcount, argvec); break; case CMD_DUMP: do_dump(argcount, argvec); break; case CMD_STATUS: do_status(argcount, argvec); break; case CMD_HELP: do_help(argcount, argvec); break; case CMD_UNKNOWN: if (buffer[0] == '!') { system(buffer + 1); printf("!\n"); } else fprintf(stderr, "%s: unrecognized command\n", argvec[0]); break; default: fprintf(stderr, "internal error: '%s' not is case\n", argvec[0]); break; } } if (remotehost) close_mount(); exit(0); } void interrupt() { longjmp(intenv, 1); } /* * Read a line from standard input and break * it up into an argument vector. */ int getline(buf, bufsize, argc, argv, argvsize) char *buf, **argv; int bufsize, *argc, argvsize; { register char *p; if (interact) printf("nfs> "); if (fgets(buf, bufsize, stdin) == NULL) return 0; *argc = 0; for (p = buf; *p == ' ' || *p == '\t'; p++) /* skip white spaces */; while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') { if (*argc > argvsize) break; argv[(*argc)++] = p; for (; *p != ' ' && *p != '\t' && *p != '\n' && *p != '\0'; p++) /* skip word */; if (*p != '\0') *p++ ='\0'; for (; *p == ' ' || *p == '\t'; p++) /* skip white spaces */; } return 1; } /* * Search for command in keyword table */ int command(cmd) char *cmd; { register int i; for (i = 0; i < sizeof(keyword)/sizeof(struct keyword); i++) if (strcmp(keyword[i].kw_command, cmd) == 0) return keyword[i].kw_value; return CMD_UNKNOWN; } /* * Set remote host and initialize RPC channel * to mount daemon. */ do_host(argc, argv) int argc; char **argv; { if (argc != 2) fprintf(stderr, "Usage: host <host>\n"); else open_mount(argv[1]); } /* * Set user or group id (updating RPC authentication info) */ do_setid(var, argc, argv) int *var, argc; char **argv; { *var = argc == 2 ? atoi(argv[1]) : -2; if (nfsclient && nfsclient->cl_auth) { auth_destroy(nfsclient->cl_auth); nfsclient->cl_auth = authunix_create_default(uid, gid); } } /* * Change remote working directory */ do_cd(argc, argv) int argc; char **argv; { register char *p; char *component; diropargs args; diropres *res; fhandle handle; if (mountpath == NULL) { fprintf(stderr, "cd: no remote file system mounted\n"); return; } /* easy case: cd to root */ if (argc == 1) { bcopy(mountpoint->fhstatus_u.fhs_fhandle, directory_handle, NFS_FHSIZE); return; } /* if a directory start with '/', we search from the root */ if (*(p = argv[1]) == '/') { bcopy(mountpoint->fhstatus_u.fhs_fhandle, handle, NFS_FHSIZE); p++; } else bcopy(directory_handle, handle, NFS_FHSIZE); /* * Break path up into directory components and check every * component for its validity. */ for (;;) { if (*p == '\0') break; for (component = p; *p != '/' && *p != '\0'; p++) /* do nothing */; *p++ = '\0'; args.name = component; bcopy(handle, &args.dir, NFS_FHSIZE); if ((res = nfsproc_lookup_2(&args, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_lookup"); return; } if (res->status != NFS_OK) { fprintf(stderr, "%s: %s\n", component, nfs_error(res->status)); return; } if (res->diropres_u.diropres.attributes.type != NFDIR) { fprintf(stderr, "%s: is not a directory\n", component); return; } bcopy(&res->diropres_u.diropres.file, handle, NFS_FHSIZE); } bcopy(handle, directory_handle, NFS_FHSIZE); } /* * Change local working directory */ do_lcd(argc, argv) int argc; char **argv; { if (argc == 1) { char *home = getenv("HOME"); if (home != NULL) if (chdir(home) != 0) perror("lcd"); } else if (chdir(argv[1]) != 0) perror("lcd"); } /* * Display a remote file */ do_cat(argc, argv) int argc; char **argv; { diropargs dargs; diropres *dres; readargs rargs; readres *rres; long offset; if (mountpath == NULL) { fprintf(stderr, "cat: no remote file system mounted\n"); return; } if (argc != 2) { fprintf(stderr, "Usage: cat <filespec>\n"); return; } /* lookup name in current directory */ dargs.name = argv[1]; bcopy(directory_handle, &dargs.dir, NFS_FHSIZE); if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_lookup"); return; } if (dres->status != NFS_OK) { fprintf(stderr, "%s: %s\n", argv[1], nfs_error(dres->status)); return; } if (dres->diropres_u.diropres.attributes.type != NFREG) { fprintf(stderr, "%s: is not a regular file\n", argv[1]); return; } bcopy(&dres->diropres_u.diropres.file, &rargs.file, NFS_FHSIZE); for (offset = 0; offset < dres->diropres_u.diropres.attributes.size; ) { rargs.offset = offset; rargs.count = rargs.totalcount = transfersize; if ((rres = nfsproc_read_2(&rargs, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_read_2"); break; } if (rres->status != NFS_OK) { fprintf(stderr, "%s: %s\n", argv[1], nfs_error(rres->status)); break; } fwrite(rres->readres_u.reply.data.data_val, rres->readres_u.reply.data.data_len, 1, stdout); offset += transfersize; } } /* * List remote directory */ do_ls(argc, argv) int argc; char **argv; { char **table, **ptr, **p; int lflag = 0; argv++; argc--; if (mountpath == NULL) { fprintf(stderr, "ls: no remote file system mounted\n"); return; } if (argc >= 1 && strcmp(argv[0], "-l") == 0) { argv++; argc--; lflag = 1; } if (!getdirentries(directory_handle, &table, &ptr, 20)) return; for (p = table; p < ptr; p++) { if (!match(*p, argc, argv)) continue; if (lflag == 1) printfilestatus(*p); else printf("%s\n", *p); free(*p); } free(table); } /* * Print long listing of a files, much in the way ``ls -l'' does */ printfilestatus(name) char *name; { diropargs args; diropres *res; int mode; args.name = name; bcopy(directory_handle, &args.dir, NFS_FHSIZE); if ((res = nfsproc_lookup_2(&args, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_lookup"); return; } if (res->status != NFS_OK) { fprintf(stderr, "Lookup failed: %s\n", nfs_error(res->status)); return; } switch (res->diropres_u.diropres.attributes.type) { case NFNON: putchar('s'); break; case NFREG: putchar('-'); break; case NFDIR: putchar('d'); break; case NFBLK: putchar('b'); break; case NFCHR: putchar('c'); break; case NFLNK: putchar('l'); break; default: putchar('?'); break; } mode = res->diropres_u.diropres.attributes.mode; if (mode & 0400) putchar('r'); else putchar('-'); if (mode & 0200) putchar('w'); else putchar('-'); if (mode & 0100) if (mode & 04000) putchar('s'); else putchar('x'); else if (mode & 04000) putchar('S'); else putchar('-'); if (mode & 040) putchar('r'); else putchar('-'); if (mode & 020) putchar('w'); else putchar('-'); if (mode & 010) if (mode & 02000) putchar('s'); else putchar('x'); else if (mode & 02000) putchar('S'); else putchar('-'); if (mode & 04) putchar('r'); else putchar('-'); if (mode & 02) putchar('w'); else putchar('-'); if (mode & 01) if (mode & 01000) putchar('t'); else putchar('x'); else if (mode & 01000) putchar('T'); else putchar('-'); printf("%3d%9d%6d%10d ", res->diropres_u.diropres.attributes.nlink, res->diropres_u.diropres.attributes.uid, res->diropres_u.diropres.attributes.gid, res->diropres_u.diropres.attributes.size); writefiledate(res->diropres_u.diropres.attributes.ctime.seconds); printf(" %s", name); if (res->diropres_u.diropres.attributes.type == NFLNK) { readlinkres *rlres; nfs_fh rlargs; bcopy(&res->diropres_u.diropres.file, &rlargs, NFS_FHSIZE); if ((rlres = nfsproc_readlink_2(&rlargs, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_readlink"); return; } if (res->status != NFS_OK) { fprintf(stderr, "Lookup failed: %s\n", nfs_error(res->status)); return; } printf(" -> %s\n", rlres->readlinkres_u.data); } else putchar('\n'); } int writefiledate(d) time_t d; { time_t now, sixmonthsago, onehourfromnow; char *cp; (void) time(&now); sixmonthsago = now - 6L*30L*24L*60L*60L; onehourfromnow = now + 60L*60L; cp = ctime(&d); if ((d < sixmonthsago) || (d > onehourfromnow)) return printf(" %-7.7s %-4.4s ", cp+4, cp+20); else return printf(" %-12.12s ", cp+4); } /* * Get remote files */ do_get(argc, argv) int argc; char **argv; { char **table, **ptr, **p; char answer[512]; diropargs args; diropres *res; readargs rargs; readres *rres; int iflag = 0; long offset; FILE *fp; argv++; argc--; if (mountpath == NULL) { fprintf(stderr, "get: no remote file system mounted\n"); return; } if (argc >= 1 && strcmp(argv[0], "-i") == 0) { argv++; argc--; iflag = 1; } if (!getdirentries(directory_handle, &table, &ptr, 20)) return; for (p = table; p < ptr; p++) { /* match before going over the wire */ if (!match(*p, argc, argv)) continue; /* only regular files can be transfered */ args.name = *p; bcopy(directory_handle, &args.dir, NFS_FHSIZE); if ((res = nfsproc_lookup_2(&args, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_lookup"); return; } if (res->status != NFS_OK) { fprintf(stderr, "Lookup failed: %s\n", nfs_error(res->status)); return; } if (res->diropres_u.diropres.attributes.type != NFREG) continue; /* ask for confirmation */ printf("%s? ", *p); if (!iflag) { gets(answer); if (answer[0] != 'y' && answer[0] != 'Y') continue; } else printf("Yes\n"); /* get actual file */ if ((fp = fopen(*p, "w")) == NULL) { fprintf(stderr, "get: cannot create %s\n", *p); continue; } bcopy(&res->diropres_u.diropres.file, &rargs.file, NFS_FHSIZE); for (offset = 0; offset < res->diropres_u.diropres.attributes.size; ) { rargs.offset = offset; rargs.count = rargs.totalcount = transfersize; if ((rres = nfsproc_read_2(&rargs, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_read"); break; } if (rres->status != NFS_OK) { fprintf(stderr, "%s: %s\n", argv[1], nfs_error(rres->status)); break; } fwrite(rres->readres_u.reply.data.data_val, rres->readres_u.reply.data.data_len, 1, fp); offset += transfersize; } fclose(fp); free(*p); } free(table); } /* * Show file system information */ /* ARGUSED */ do_df(argc, argv) int argc; char **argv; { statfsres *res; if (mountpath == NULL) { fprintf(stderr, "df: no remote file system mounted\n"); return; } if (argc != 1) { fprintf(stderr, "Usage: df\n"); return; } if ((res = nfsproc_statfs_2(directory_handle, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_statfs"); return; } if (res->status != NFS_OK) { fprintf(stderr, "Df failed: %s\n", nfs_error(res->status)); return; } #define x res->statfsres_u.reply printf("%s:%s %dK, %dK used, %dK free (%dK useable).\n", remotehost, mountpath, x.blocks, (x.blocks-x.bfree), x.bfree, x.bavail); if (x.bsize != 1024) printf("Warning: This filesystem has a blocksize of %d bytes.\n", x.bsize); #undef x } /* * Delete a remote file */ do_rm(argc, argv) int argc; char **argv; { diropargs args; nfsstat *res; if (mountpath == NULL) { fprintf(stderr, "rm: no remote file system mounted\n"); return; } if (argc != 2) { fprintf(stderr, "Usage: rm <file>\n"); return; } args.name = argv[1]; bcopy(directory_handle, &args.dir, NFS_FHSIZE); if ((res = nfsproc_remove_2(&args, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_remove"); return; } if (*res != NFS_OK) { fprintf(stderr, "Remove failed: %s\n", nfs_error(*res)); return; } } /* * Link a file */ do_ln(argc, argv) int argc; char **argv; { diropargs dargs; linkargs largs; diropres *dres; nfsstat *lres; if (mountpath == NULL) { fprintf(stderr, "ln: no remote file system mounted\n"); return; } if (argc != 3) { fprintf(stderr, "Usage: ln <file1> <file2>\n"); return; } dargs.name = argv[1]; bcopy(directory_handle, &dargs.dir, NFS_FHSIZE); if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_lookup"); return; } if (dres->status != NFS_OK) { fprintf(stderr, "%s: %s\n", argv[1], nfs_error(dres->status)); return; } bcopy(&dres->diropres_u.diropres.file, &largs.from, NFS_FHSIZE); largs.to.name = argv[2]; bcopy(directory_handle, &largs.to.dir, NFS_FHSIZE); if ((lres = nfsproc_link_2(&largs, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_link"); return; } if (*lres != NFS_OK) { fprintf(stderr, "Link failed: %s\n", nfs_error(*lres)); return; } } /* * Move a file or directory */ do_mv(argc, argv) int argc; char **argv; { renameargs args; nfsstat *res; if (mountpath == NULL) { fprintf(stderr, "mv: no remote file system mounted\n"); return; } if (argc != 3) { fprintf(stderr, "Usage: mv <file1> <file2>\n"); return; } args.from.name = argv[1]; bcopy(directory_handle, &args.from.dir, NFS_FHSIZE); args.to.name = argv[2]; bcopy(directory_handle, &args.to.dir, NFS_FHSIZE); if ((res = nfsproc_rename_2(&args, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_rename"); return; } if (*res != NFS_OK) { fprintf(stderr, "Rename failed: %s\n", nfs_error(*res)); return; } } /* * Make remote directory */ do_mkdir(argc, argv) int argc; char **argv; { createargs args; diropres *res; if (mountpath == NULL) { fprintf(stderr, "mkdir: no remote file system mounted\n"); return; } if (argc != 2) { fprintf(stderr, "Usage: mkdir <directory>\n"); return; } args.where.name = argv[1]; bcopy(directory_handle, &args.where.dir, NFS_FHSIZE); args.attributes.mode = 040755; args.attributes.uid = uid; args.attributes.gid = gid; args.attributes.size = -1; args.attributes.atime.seconds = -1; args.attributes.atime.useconds = -1; args.attributes.mtime.seconds = -1; args.attributes.mtime.useconds = -1; if ((res = nfsproc_mkdir_2(&args, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_mkdir"); return; } if (res->status != NFS_OK) { fprintf(stderr, "Make directory failed: %s\n", nfs_error(res->status)); return; } } /* * Remove remote directory */ do_rmdir(argc, argv) int argc; char **argv; { diropargs args; nfsstat *res; if (mountpath == NULL) { fprintf(stderr, "rmdir: no remote file system mounted\n"); return; } if (argc != 2) { fprintf(stderr, "Usage: rmdir <directory>\n"); return; } args.name = argv[1]; bcopy(directory_handle, &args.dir, NFS_FHSIZE); if ((res = nfsproc_rmdir_2(&args, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_rmdir"); return; } if (*res != NFS_OK) { fprintf(stderr, "Remove directory failed: %s\n", nfs_error(*res)); return; } } /* * Change mode of remote file or directory */ do_chmod(argc, argv) int argc; char **argv; { sattrargs aargs; diropargs dargs; attrstat *ares; diropres *dres; int mode; if (mountpath == NULL) { fprintf(stderr, "chmod: no remote file system mounted\n"); return; } if (argc != 3) { fprintf(stderr, "Usage: chmod <mode> <file>\n"); return; } if (sscanf(argv[1], "%o", &mode) != 1) { fprintf(stderr, "chmod: invalid mode\n"); return; } dargs.name = argv[2]; bcopy(directory_handle, &dargs.dir, NFS_FHSIZE); if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_lookup"); return; } if (dres->status != NFS_OK) { fprintf(stderr, "%s: %s\n", argv[2], nfs_error(dres->status)); return; } bcopy(&dres->diropres_u.diropres.file, &aargs.file, NFS_FHSIZE); aargs.attributes.mode = mode; aargs.attributes.uid = -1; aargs.attributes.gid = -1; aargs.attributes.size = -1; aargs.attributes.atime.seconds = -1; aargs.attributes.atime.useconds = -1; aargs.attributes.mtime.seconds = -1; aargs.attributes.mtime.useconds = -1; if ((ares = nfsproc_setattr_2(&aargs, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_setattr"); return; } if (ares->status != NFS_OK) { fprintf(stderr, "Set attributes failed: %s\n", nfs_error(ares->status)); return; } } /* * Change owner (and group) of remote file or directory */ do_chown(argc, argv) int argc; char **argv; { sattrargs aargs; diropargs dargs; attrstat *ares; diropres *dres; int own_uid, own_gid; if (mountpath == NULL) { fprintf(stderr, "chown: no remote file system mounted\n"); return; } if (argc != 3) { fprintf(stderr, "Usage: chown <uid>[.<gid>] <file>\n"); return; } if (sscanf(argv[1], "%d.%d", &own_uid, &own_gid) != 2) { own_gid = -1; if (sscanf(argv[1], "%d", &own_uid) != 1) { fprintf(stderr, "chown: invalid uid[.gid]\n"); return; } } dargs.name = argv[2]; bcopy(directory_handle, &dargs.dir, NFS_FHSIZE); if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_lookup"); return; } if (dres->status != NFS_OK) { fprintf(stderr, "%s: %s\n", argv[2], nfs_error(dres->status)); return; } bcopy(&dres->diropres_u.diropres.file, &aargs.file, NFS_FHSIZE); aargs.attributes.mode = -1; aargs.attributes.uid = own_uid; aargs.attributes.gid = own_gid; aargs.attributes.size = -1; aargs.attributes.atime.seconds = -1; aargs.attributes.atime.useconds = -1; aargs.attributes.mtime.seconds = -1; aargs.attributes.mtime.useconds = -1; if ((ares = nfsproc_setattr_2(&aargs, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_setattr"); return; } if (ares->status != NFS_OK) { fprintf(stderr, "Set attributes failed: %s\n", nfs_error(ares->status)); return; } } /* * Put file from local to remote */ do_put(argc, argv) int argc; char **argv; { createargs cargs; diropargs dargs; diropres *cres; diropres *dres; char buf[BUFSIZ]; fhandle handle; FILE *fp; int n; long offset; if (mountpath == NULL) { fprintf(stderr, "put: no remote file system mounted\n"); return; } if (argc != 2 && argc != 3) { fprintf(stderr, "Usage: put <local-file> [<remote-file>]\n"); return; } if ((fp = fopen(argv[1], "r")) == NULL) { fprintf(stderr, "put: cannot open %s\n", argv[1]); return; } /* * Create remote file name */ cargs.where.name = argc == 3 ? argv[2] : argv[1]; bcopy(directory_handle, &cargs.where.dir, NFS_FHSIZE); cargs.attributes.mode = 0666; cargs.attributes.uid = uid; cargs.attributes.gid = gid; cargs.attributes.size = -1; cargs.attributes.atime.seconds = -1; cargs.attributes.atime.useconds = -1; cargs.attributes.mtime.seconds = -1; cargs.attributes.mtime.useconds = -1; if ((cres = nfsproc_create_2(&cargs, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_create"); fclose(fp); return; } if (cres->status != NFS_OK) fprintf(stderr, "WARNING: Create failed: %s\n", nfs_error(*cres)); /* * Look up remote file name, to get its handle */ dargs.name = argc == 3 ? argv[2] : argv[1]; bcopy(directory_handle, &dargs.dir, NFS_FHSIZE); if ((dres = nfsproc_lookup_2(&dargs, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_lookup"); fclose(fp); return; } if (dres->status != NFS_OK) { fprintf(stderr, "%s: %s\n", argv[1], nfs_error(dres->status)); fclose(fp); return; } bcopy(&dres->diropres_u.diropres.file, handle, NFS_FHSIZE); for (offset = 0; (n = fread(buf, 1, sizeof(buf), fp)) > 0; offset += n) { writeargs wargs; attrstat *wres; bcopy(handle, &wargs.file, NFS_FHSIZE); wargs.beginoffset = wargs.offset = offset; wargs.totalcount = n; wargs.data.data_len = n; wargs.data.data_val = buf; if ((wres = nfsproc_write_2(&wargs, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_write"); fclose(fp); return; } if (wres->status != NFS_OK) { fprintf(stderr, "Write failed: %s\n", nfs_error(wres->status)); fclose(fp); return; } } fclose(fp); } /* * Get/set file handle */ do_handle(argc, argv) int argc; char **argv; { register char *p; register int i; int sock; if (argc <= 1) { if (mountpath == NULL) { fprintf(stderr, "handle: no remote file system mounted\n"); return; } printf("%s:", mountpath); for (i = 0, p = (char *)directory_handle; i < NFS_FHSIZE; i++) printf(" %02x", *p++ & 0xFF); printf("\n"); return; } if (argc != NFS_FHSIZE + 1) { fprintf(stderr, "Usage: handle [<file handle>]\n"); return; } /* umount previous mounted remote file system */ if (mountpath != NULL) close_nfs(); /* setup communication channel with NFS server */ sock = privileged(); nfsserver_addr = server_addr; if ((nfsclient = clntudp_create(&nfsserver_addr, NFS_PROGRAM, NFS_VERSION, timeout, &sock)) == NULL) { clnt_pcreateerror("nfs clntudp_create"); return 0; } clnt_control(nfsclient, CLSET_TIMEOUT, &timeout); nfsclient->cl_auth = authunix_create_default(uid, gid); /* provide some generic name for it */ if ((mountpath = malloc(8 + 1)) == NULL) { fprintf(stderr, "internal error: no more core for mountpath\n"); return; } strcpy(mountpath, "<handle>"); /* copy handle from command line argument */ for (i = 0, p = (char *)directory_handle; i < NFS_FHSIZE; i++) *p++ = (char) xtoa(argv[i + 1]); /* get transfer size */ if ((transfersize = determine_transfersize()) <= 0) { fprintf(stderr, "Handle failed: Unable to obtain transfer size\n"); return; } } int xtoa(s) char *s; { register int n; for (n = 0; *s; s++) { n <<= 4; if (*s >= '0' && *s <= '9') n += *s - '0'; else if (*s >= 'a' && *s <= 'f') n += *s - 'a' + 10; else if (*s >= 'A' && *s <= 'F') n += *s - 'A' + 10; else break; } return n; } /* * Set up a channel to the NFS server and * mount remote file system. */ do_mount(argc, argv) int argc; char **argv; { char *host, *path; int umount = 0, portmap = 0; argv++; argc--; if (argc >= 1 && strcmp(argv[0], "-u") == 0) { argv++; argc--; umount = 1; } if (argc >= 1 && strcmp(argv[0], "-p") == 0) { argv++; argc--; portmap = 1; } if (argc == 0) { fprintf(stderr, "Usage: mount [-u] [-p] [<host>:]<path>\n"); return; } if ((path = strchr(host = argv[0], ':')) != NULL) { *path++ = '\0'; /* this heuristic is far too simple */ if (remotehost && strcmp(remotehost, host) == 0) { if (mountpath) close_nfs(); } else if (!open_mount(host)) return; } else path = argv[0]; if (remotehost == NULL) { fprintf(stderr, "mount: no host specified\n"); return; } open_nfs(path, umount, portmap); } /* * Unmount remote file system, and close * RPC channel. */ /* ARGUSED */ do_umount(argc, argv) int argc; char **argv; { if (argc != 1) { fprintf(stderr, "Usage: umount\n"); return; } if (mountpath == NULL) fprintf(stderr, "umount: no remote file system mounted\n"); else close_nfs(); } /* * Unmount all remote file system from this host */ /* ARGUSED */ do_umountall(argc, argv) int argc; char **argv; { if (argc != 1) { fprintf(stderr, "Usage: umountall\n"); return; } if (remotehost == NULL) { fprintf(stderr, "umountall: no host specified\n"); return; } if (mountpath != NULL) close_nfs(); (void) mountproc_umntall_1(NULL, mntclient); } /* * Display all exported file systems on remote system */ /* ARGUSED */ do_export(argc, argv) int argc; char **argv; { exports ex, *exp; groups gr; if (argc != 1) { fprintf(stderr, "Usage: export\n"); return; } if (remotehost == NULL) { fprintf(stderr, "export: no host specified\n"); return; } if ((exp = mountproc_export_1(NULL, mntclient)) == NULL) { clnt_perror(mntclient, "mountproc_export"); return; } printf("Export list for %s:\n", remotehost); for (ex = *exp; ex != NULL; ex = ex->ex_next) { printf("%-25s", ex->ex_dir); if (strlen(ex->ex_dir) >= 25) printf("\n "); if ((gr = ex->ex_groups) == NULL) printf("everyone"); while (gr) { printf("%s ", gr->gr_name); gr = gr->gr_next; } putchar('\n'); } } /* * Display all remote mounted file systems */ /* ARGUSED */ do_dump(argc, argv) int argc; char **argv; { mountlist ml, *mlp; if (argc != 1) { fprintf(stderr, "Usage: dump\n"); return; } if (remotehost == NULL) { fprintf(stderr, "dump: no host specified\n"); return; } if ((mlp = mountproc_dump_1(NULL, mntclient)) == NULL) { clnt_perror(mntclient, "mountproc_dump"); return; } for (ml = *mlp; ml != NULL; ml = ml->ml_next) printf("%s:%s\n", ml->ml_hostname, ml->ml_directory); } /* * Generic status report */ /* ARGUSED */ do_status(argc, argv) int argc; char **argv; { if (argc != 1) { fprintf(stderr, "Usage: status\n"); return; } printf("User id : %d\n", uid); printf("Group id : %d\n", gid); if (remotehost) printf("Remote host : `%s'\n", remotehost); if (mountpath) printf("Mount path : `%s'\n", mountpath); printf("Transfer size: %d\n", transfersize); } /* * Simple on-line help facility */ /* ARGUSED */ do_help(argc, argv) int argc; char **argv; { register int i; for (i = 0; i < sizeof(keyword)/sizeof(struct keyword); i++) { if (argc == 2 && strcmp(keyword[i].kw_command, argv[1]) != 0) continue; printf("%s %s\n", keyword[i].kw_command, keyword[i].kw_help); } } /* * Open a channel to remote Mount daemon, * possibly closing an already open connection. */ int open_mount(host) char *host; { int sock = privileged(); /* close previous mounted host */ if (remotehost != NULL) close_mount(); /* convert hostname to IP address */ if (isdigit(*host)) { server_addr.sin_addr.s_addr = inet_addr(host); } else { struct hostent *hp = gethostbyname(host); if (hp == NULL) { fprintf(stderr, "%s: unknown host\n", host); return 0; } bcopy(hp->h_addr, &server_addr.sin_addr.s_addr, hp->h_length); host = hp->h_name; } server_addr.sin_family = AF_INET; server_addr.sin_port = 0; /* set host name */ if ((remotehost = malloc(strlen(host) + 1)) == NULL) { fprintf(stderr, "internal error: no more core for host\n"); return 0; } strcpy(remotehost, host); /* setup communication channel with mount daemon */ mntserver_addr = server_addr; if ((mntclient = clntudp_create(&mntserver_addr, MOUNTPROG, MOUNTVERS, timeout, &sock)) == NULL) { clnt_pcreateerror("mount clntudp_create"); return 0; } clnt_control(mntclient, CLSET_TIMEOUT, &timeout); mntclient->cl_auth = authunix_create_default(0, 0); if (verbose) printf("Open %s (%s)\n", remotehost, inet_ntoa(server_addr.sin_addr)); return 1; } /* * Close channel to mount daemon, * possibly umounting a NFS file system. */ close_mount() { if (mountpath) close_nfs(); if (verbose) printf("Close `%s'\n", remotehost); free(remotehost); remotehost = NULL; if (mntclient) { auth_destroy(mntclient->cl_auth); clnt_destroy(mntclient); } } /* * Mount an NFS file system, perhaps closing * a previous mounted one. The umount option * fools the accounting system. */ int open_nfs(path, umount, portmap) char *path; int umount, portmap; { int sock = privileged(); /* umount previous mounted remote file system */ if (mountpath != NULL) close_nfs(); /* setup communication channel with NFS server */ nfsserver_addr = server_addr; if ((nfsclient = clntudp_create(&nfsserver_addr, NFS_PROGRAM, NFS_VERSION, timeout, &sock)) == NULL) { clnt_pcreateerror("nfs clntudp_create"); return 0; } clnt_control(nfsclient, CLSET_TIMEOUT, &timeout); nfsclient->cl_auth = authunix_create_default(uid, gid); /* * Get file handle for this path from the mount daemon. There * are two ways to get it, either ask it directly or get it * through the port mapper. */ if (portmap) { if ((mountpoint = pmap_mnt(&path, &mntserver_addr)) == NULL) return 0; } else if ((mountpoint = mountproc_mnt_1(&path, mntclient)) == NULL) { clnt_perror(mntclient, "mountproc_mnt"); return 0; } if (mountpoint->fhs_status != NFS_OK) { fprintf(stderr, "Mount failed: %s\n", nfs_error(mountpoint->fhs_status)); return 0; } bcopy(mountpoint->fhstatus_u.fhs_fhandle, directory_handle, NFS_FHSIZE); if (umount) (void) mountproc_umnt_1(&path, mntclient); /* get transfer size */ if ((transfersize = determine_transfersize()) <= 0) { fprintf(stderr, "Mount failed: Unable to obtain transfer size\n"); (void) mountproc_umnt_1(&path, mntclient); return 0; } /* set mount path */ if ((mountpath = malloc(strlen(path) + 1)) == NULL) { fprintf(stderr, "internal error: no more core for mountpath\n"); return 0; } strcpy(mountpath, path); if (verbose) printf("Mount `%s'%s, transfer size %d bytes.\n", mountpath, umount ? " (unmount)":"", transfersize); return 1; } /* * Make a mount call via the port mapper */ fhstatus * pmap_mnt(argp, server_addr) dirpath *argp; struct sockaddr_in *server_addr; { enum clnt_stat stat; static fhstatus res; u_long port; bzero((char *)&res, sizeof(res)); if ((stat = pmap_rmtcall(server_addr, MOUNTPROG, MOUNTVERS, MOUNTPROC_MNT, xdr_dirpath, argp, xdr_fhstatus, &res, timeout, &port)) != RPC_SUCCESS) { clnt_perrno(stat); return NULL; } return &res; } /* * Determine NFS server's transfer size */ static int determine_transfersize() { statfsres *res; if ((res = nfsproc_statfs_2(directory_handle, nfsclient)) == NULL) return 0; if (res->status != NFS_OK) return 0; return res->statfsres_u.reply.tsize; } /* * Acquire a privileged port when possible */ int privileged() { int lport = IPPORT_RESERVED - 1; struct sockaddr_in sin; int s, dontblock = 1; sin.sin_family = AF_INET; sin.sin_addr.s_addr = 0; s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (s < 0) return RPC_ANYSOCK; for (;;) { sin.sin_port = htons((u_short)lport); if (bind(s, (caddr_t)&sin, sizeof (sin), 0) >= 0) { (void)ioctl(s, FIONBIO, (char *) &dontblock); if (verbose) fprintf(stderr, "Using a privileged port (%d)\n", lport); fflush(stderr); return s; } if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) return RPC_ANYSOCK; (lport)--; if (lport == IPPORT_RESERVED/2) { fprintf(stderr, "privileged socket: All ports in use\n"); return RPC_ANYSOCK; } } } /* * Close an NFS mounted file system */ close_nfs() { if (mountpath == NULL) return; if (verbose) printf("Unmount `%s'\n", mountpath); (void) mountproc_umnt_1(&mountpath, mntclient); free(mountpath); mountpath = NULL; if (nfsclient) { auth_destroy(nfsclient->cl_auth); clnt_destroy(nfsclient); } } /* * Returns an auth handle with parameters determined by doing lots of * syscalls. */ AUTH * authunix_create_default(uid, gid) int uid, gid; { char machname[MAX_MACHINE_NAME + 1]; int gids[1]; if (gethostname(machname, MAX_MACHINE_NAME) == -1) { fprintf(stderr, "authunix_create_default: cannot get hostname\n"); exit(1); } machname[MAX_MACHINE_NAME] = 0; gids[0] = gid; return (authunix_create(machname, uid, gid, 1, gids)); } /* * Read all entries (names) in directory 'dirhandle' into * a dynamically build table. It is up to the caller to free * this table. */ getdirentries(dirhandle, table, ptr, nentries) fhandle *dirhandle; register char ***table; register char ***ptr; int nentries; { readdirargs args; readdirres *res; entry *ep; int dircmp(); char **last; *ptr = *table = (char **) calloc(nentries, sizeof(char *)); last = *ptr + nentries; if (*ptr == NULL) { fprintf(stderr, "getdirentries: out of memory\n"); return 0; } bcopy(*dirhandle, &args.dir, NFS_FHSIZE); bzero(args.cookie, NFS_COOKIESIZE); args.count = 1000; for (;;) { if ((res = nfsproc_readdir_2(&args, nfsclient)) == NULL) { clnt_perror(nfsclient, "nfsproc_readdir"); break; } if (res->status != NFS_OK) { fprintf(stderr, "Readdir failed: %s\n", nfs_error(res->status)); break; } ep = res->readdirres_u.reply.entries; while (ep != NULL) { if (*ptr == last) { *table = (char **)realloc(*table, 2*nentries*sizeof(char *)); if (*table == NULL) { fprintf(stderr, "getdirentries: out of memory\n"); exit(1); } *ptr = *table + nentries; last = *ptr + nentries; nentries *= 2; } if ((*(*ptr)++ = strsave(ep->name)) == NULL) return 0; if (ep->nextentry == NULL) break; ep = ep->nextentry; } if (res->readdirres_u.reply.eof) break; bcopy(ep->cookie, args.cookie, NFS_COOKIESIZE); } qsort(*table, *ptr - *table, sizeof(char **), dircmp); return 1; } char * strsave(str) char *str; { char *cp = malloc(strlen(str) + 1); if (cp == NULL) { fprintf(stderr, "strsave: out of memory\n"); return NULL; } strcpy(cp, str); return cp; } int dircmp(p, q) char **p, **q; { return strcmp(*p, *q); } /* * Match string against a normal shell pattern (*?[]) */ int match(s, argc, argv) char *s; int argc; char **argv; { register int i; if (argc == 0) return 1; for (i = 0; i < argc; i++) if (matchpattern(s, argv[i])) return 1; return 0; } int matchpattern(s, p) char *s, *p; { if (*s == '.' && *p != '.') return 0; return amatchpattern(s, p); } int amatchpattern(s, p) register char *s, *p; { register int scc; int c, cc, ok, lc; if (scc = *s++) if ((scc &= 0177) == 0) scc = 0200; switch (c = *p++) { case '[': ok = 0; lc = 077777; while (cc = *p++) { if (cc == ']') { if (ok) return amatchpattern(s, p); else return 0; } else if (cc == '-') { if (lc <= scc && scc <= (c = *p++)) ok++; } else if (scc == (lc = cc)) ok++; } return 0; case '*': return umatchpattern(--s, p); case '\0': return !scc; default: if (c != scc) return 0; case '?': if (scc) return amatchpattern(s, p); return 0; } } int umatchpattern(s, p) register char *s, *p; { if (*p == '\0') return 1; while (*s != '\0') if (amatchpattern(s++, p)) return 1; return 0; } /* * NFS errors */ char * nfs_error(nfsstat) enum nfsstat nfsstat; { switch (nfsstat) { case NFS_OK: return "No error"; case NFSERR_PERM: return "Not owner"; case NFSERR_NOENT: return "No such file or directory"; case NFSERR_IO: return "I/O error"; case NFSERR_NXIO: return "No such device or address"; case NFSERR_ACCES: return "Permission denied"; case NFSERR_EXIST: return "File exists"; case NFSERR_NODEV: return "No such device"; case NFSERR_NOTDIR: return "Not a directory"; case NFSERR_ISDIR: return "Is a directory"; case NFSERR_FBIG: return "File too large"; case NFSERR_NOSPC: return "No space left on device"; case NFSERR_ROFS: return "Read-only file system"; case NFSERR_NAMETOOLONG: return "File name too long"; case NFSERR_NOTEMPTY: return "Directory not empty"; case NFSERR_DQUOT: return "Disc quota exceeded"; case NFSERR_STALE: return "Stale NFS file handle"; case NFSERR_WFLUSH: return "Write cache flushed"; default: return "UKNOWN NFS ERROR"; } } |