scp.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <ctype.h>
  4. int
  5. isatty(int fd)
  6. {
  7. char buf[64];
  8. buf[0] = '\0';
  9. fd2path(fd, buf, sizeof buf);
  10. if(strlen(buf)>=9 && strcmp(buf+strlen(buf)-9, "/dev/cons")==0)
  11. return 1;
  12. return 0;
  13. }
  14. #define OK 0x00
  15. #define ERROR 0x01
  16. #define FATAL 0x02
  17. char *progname;
  18. int dflag;
  19. int fflag;
  20. int iflag;
  21. int pflag;
  22. int rflag;
  23. int tflag;
  24. int vflag;
  25. int remote;
  26. char *exitflag = nil;
  27. void scperror(int, char*, ...);
  28. void mustbedir(char*);
  29. void receive(char*);
  30. char *fileaftercolon(char*);
  31. void destislocal(char *cmd, int argc, char *argv[], char *dest);
  32. void destisremote(char *cmd, int argc, char *argv[], char *host, char *dest);
  33. int remotessh(char *host, char *cmd);
  34. void send(char*);
  35. void senddir(char*, int, Dir*);
  36. int getresponse(void);
  37. char theuser[32];
  38. char ssh[] = "/bin/ssh";
  39. int remotefd0;
  40. int remotefd1;
  41. int
  42. runcommand(char *cmd)
  43. {
  44. Waitmsg *w;
  45. int pid;
  46. char *argv[4];
  47. if (cmd == nil)
  48. return -1;
  49. switch(pid = fork()){
  50. case -1:
  51. return -1;
  52. case 0:
  53. argv[0] = "rc";
  54. argv[1] = "-c";
  55. argv[2] = cmd;
  56. argv[3] = nil;
  57. exec("/bin/rc", argv);
  58. exits("exec failed");
  59. }
  60. for(;;){
  61. w = wait();
  62. if(w == nil)
  63. return -1;
  64. if(w->pid == pid)
  65. break;
  66. free(w);
  67. }
  68. if(w->msg[0]){
  69. free(w);
  70. return -1;
  71. }
  72. free(w);
  73. return 1;
  74. }
  75. void
  76. vprint(char *fmt, ...)
  77. {
  78. char buf[1024];
  79. va_list arg;
  80. static char *name;
  81. if(vflag == 0)
  82. return;
  83. va_start(arg, fmt);
  84. vseprint(buf, buf+sizeof(buf), fmt, arg);
  85. va_end(arg);
  86. if(name == nil){
  87. name = sysname();
  88. if(name == nil)
  89. name = "<unknown>";
  90. }
  91. fprint(2, "%s: %s\n", name, buf);
  92. }
  93. void
  94. usage(void)
  95. {
  96. fprint(2, "Usage: scp [-Iidfprtv] source ... destination\n");
  97. exits("usage");
  98. }
  99. #pragma varargck type "F" int
  100. #pragma varargck type "V" char*
  101. static int flag;
  102. /* flag: if integer flag, take following char *value */
  103. int
  104. flagfmt(Fmt *f)
  105. {
  106. flag = va_arg(f->args, int);
  107. return 0;
  108. }
  109. /* flag: if previous integer flag, take char *value */
  110. int
  111. valfmt(Fmt *f)
  112. {
  113. char *value;
  114. value = va_arg(f->args, char*);
  115. if(flag)
  116. return fmtprint(f, " %s", value);
  117. return 0;
  118. }
  119. void
  120. sendokresponse(void)
  121. {
  122. char ok = OK;
  123. write(remotefd1, &ok, 1);
  124. }
  125. void
  126. main(int argc, char *argv[])
  127. {
  128. int i, fd;
  129. char cmd[32];
  130. char *p;
  131. progname = argv[0];
  132. fmtinstall('F', flagfmt);
  133. fmtinstall('V', valfmt);
  134. iflag = -1;
  135. ARGBEGIN {
  136. case 'I':
  137. iflag = 0;
  138. break;
  139. case 'i':
  140. iflag = 1;
  141. break;
  142. case 'd':
  143. dflag++;
  144. break;
  145. case 'f':
  146. fflag++;
  147. remote++;
  148. break;
  149. case 'p':
  150. pflag++;
  151. break;
  152. case 'r':
  153. rflag++;
  154. break;
  155. case 't':
  156. tflag++;
  157. remote++;
  158. break;
  159. case 'v':
  160. vflag++;
  161. break;
  162. default:
  163. scperror(1, "unknown option %c", ARGC());
  164. } ARGEND
  165. if(iflag == -1)
  166. iflag = isatty(0);
  167. remotefd0 = 0;
  168. remotefd1 = 1;
  169. if(fflag){
  170. getresponse();
  171. for(i=0; i<argc; i++)
  172. send(argv[i]);
  173. exits(0);
  174. }
  175. if(tflag){
  176. if(argc != 1)
  177. usage();
  178. receive(argv[0]);
  179. exits(0);
  180. }
  181. if (argc < 2)
  182. usage();
  183. if (argc > 2)
  184. dflag = 1;
  185. i = 0;
  186. fd = open("/dev/user", OREAD);
  187. if(fd >= 0){
  188. i = read(fd, theuser, sizeof theuser - 1);
  189. close(fd);
  190. }
  191. if(i <= 0)
  192. scperror(1, "can't read /dev/user: %r");
  193. remotefd0 = -1;
  194. remotefd1 = -1;
  195. snprint(cmd, sizeof cmd, "scp%F%V%F%V%F%V%F%V",
  196. dflag, "-d",
  197. pflag, "-p",
  198. rflag, "-r",
  199. vflag, "-v");
  200. p = fileaftercolon(argv[argc-1]);
  201. if(p != nil) /* send to remote machine. */
  202. destisremote(cmd, argc-1, argv, argv[argc-1], p);
  203. else{
  204. if(dflag)
  205. mustbedir(argv[argc-1]);
  206. destislocal(cmd, argc-1, argv, argv[argc-1]);
  207. }
  208. exits(exitflag);
  209. }
  210. void
  211. destislocal(char *cmd, int argc, char *argv[], char *dst)
  212. {
  213. int i;
  214. char *src;
  215. char buf[4096];
  216. for(i = 0; i<argc; i++){
  217. src = fileaftercolon(argv[i]);
  218. if(src == nil){
  219. /* local file; no network */
  220. snprint(buf, sizeof buf, "exec cp%F%V%F%V %s %s",
  221. rflag, "-r",
  222. pflag, "-p",
  223. argv[i], dst);
  224. vprint("remotetolocal: %s", buf);
  225. if(runcommand(buf) < 0)
  226. exitflag = "local cp exec";
  227. }else{
  228. /* remote file; use network */
  229. snprint(buf, sizeof buf, "%s -f %s", cmd, src);
  230. if(remotessh(argv[i], buf) < 0)
  231. exitflag = "remote ssh exec";
  232. else{
  233. receive(dst);
  234. close(remotefd0);
  235. remotefd0 = -1;
  236. remotefd1 = -1;
  237. }
  238. }
  239. }
  240. }
  241. void
  242. destisremote(char *cmd, int argc, char *argv[], char *host, char *dest)
  243. {
  244. int i;
  245. char *src;
  246. char buf[4096];
  247. for(i = 0; i < argc; i++){
  248. vprint("remote destination: send %s to %s:%s", argv[i], host, dest);
  249. /* destination is remote, but source may be local */
  250. src = fileaftercolon(argv[i]);
  251. if(src != nil){
  252. /* remote to remote */
  253. snprint(buf, sizeof buf, "exec %s%F%V%F%V %s %s %s '%s:%s'",
  254. ssh,
  255. iflag, " -i",
  256. vflag, "-v",
  257. argv[i], cmd, src,
  258. host, dest);
  259. vprint("localtoremote: %s", buf);
  260. runcommand(buf);
  261. }else{
  262. /* local to remote */
  263. if(remotefd0 == -1){
  264. snprint(buf, sizeof buf, "%s -t %s", cmd, dest);
  265. if(remotessh(host, buf) < 0)
  266. exits("remotessh");
  267. if(getresponse() < 0)
  268. exits("bad response");
  269. }
  270. send(argv[i]);
  271. }
  272. }
  273. }
  274. void
  275. readhdr(char *p, int n)
  276. {
  277. int i;
  278. for(i=0; i<n; i++){
  279. if(read(remotefd0, &p[i], 1) != 1)
  280. break;
  281. if(p[i] == '\n'){
  282. p[i] = '\0';
  283. return;
  284. }
  285. }
  286. /* if at beginning, this is regular EOF */
  287. if(i == 0)
  288. exits(nil);
  289. scperror(1, "read error on receive header: %r");
  290. }
  291. Dir *
  292. receivedir(char *dir, int exists, Dir *d, int settimes, ulong atime, ulong mtime, ulong mode)
  293. {
  294. int setmodes;
  295. setmodes = pflag;
  296. if(exists){
  297. if(d->qid.type != QTDIR) {
  298. scperror(0, "%s: protocol botch: directory requrest for non-directory", dir);
  299. return d;
  300. }
  301. }else{
  302. /* create it writeable; will fix later */
  303. setmodes = 1;
  304. if (create(dir, OREAD, DMDIR|mode|0700) < 0){
  305. scperror(0, "%s: can't create: %r", dir);
  306. return d;
  307. }
  308. }
  309. receive(dir);
  310. if(settimes || setmodes){
  311. free(d);
  312. if((d = dirstat(dir)) == 0){
  313. scperror(0, "can't stat %s: %r", dir);
  314. return d;
  315. }
  316. if(settimes){
  317. d->atime = atime;
  318. d->mtime = mtime;
  319. }
  320. if(setmodes)
  321. d->mode = (d->mode & ~0777) | (mode & 0777);
  322. if(dirwstat(dir, d))
  323. scperror(0, "can't wstat %s: %r", dir);
  324. }
  325. return d;
  326. }
  327. void
  328. receive(char *dest)
  329. {
  330. int isdir, settimes, mode;
  331. int exists, n, i, fd, m;
  332. int errors;
  333. ulong atime, mtime, size;
  334. char buf[8192], *p;
  335. char name[1024];
  336. Dir *d;
  337. mtime = 0L;
  338. atime = 0L;
  339. settimes = 0;
  340. isdir = 0;
  341. if ((d = dirstat(dest)) && d->qid.type == QTDIR) {
  342. isdir = 1;
  343. }
  344. if(dflag && !isdir)
  345. scperror(1, "%s: not a directory: %r", dest);
  346. sendokresponse();
  347. for (;;) {
  348. readhdr(buf, sizeof buf);
  349. switch(buf[0]){
  350. case ERROR:
  351. case FATAL:
  352. if(!remote)
  353. fprint(2, "%s\n", buf+1);
  354. exitflag = "bad receive";
  355. if(buf[0] == FATAL)
  356. exits(exitflag);
  357. continue;
  358. case 'E':
  359. sendokresponse();
  360. return;
  361. case 'T':
  362. settimes = 1;
  363. p = buf + 1;
  364. mtime = strtol(p, &p, 10);
  365. if(*p++ != ' '){
  366. Badtime:
  367. scperror(1, "bad time format: %s", buf+1);
  368. }
  369. strtol(p, &p, 10);
  370. if(*p++ != ' ')
  371. goto Badtime;
  372. atime = strtol(p, &p, 10);
  373. if(*p++ != ' ')
  374. goto Badtime;
  375. strtol(p, &p, 10);
  376. if(*p++ != 0)
  377. goto Badtime;
  378. sendokresponse();
  379. continue;
  380. case 'D':
  381. case 'C':
  382. p = buf + 1;
  383. mode = strtol(p, &p, 8);
  384. if (*p++ != ' '){
  385. Badmode:
  386. scperror(1, "bad mode/size format: %s", buf+1);
  387. }
  388. size = strtoll(p, &p, 10);
  389. if(*p++ != ' ')
  390. goto Badmode;
  391. if(isdir){
  392. if(dest[0] == '\0')
  393. snprint(name, sizeof name, "%s", p);
  394. else
  395. snprint(name, sizeof name, "%s/%s", dest, p);
  396. }else
  397. snprint(name, sizeof name, "%s", dest);
  398. if(strlen(name) > sizeof name-UTFmax)
  399. scperror(1, "file name too long: %s", dest);
  400. exists = 1;
  401. free(d);
  402. if((d = dirstat(name)) == nil)
  403. exists = 0;
  404. if(buf[0] == 'D'){
  405. vprint("receive directory %s", name);
  406. d = receivedir(name, exists, d, settimes, atime, mtime, mode);
  407. settimes = 0;
  408. continue;
  409. }
  410. vprint("receive file %s by %s", name, getuser());
  411. fd = create(name, OWRITE, mode);
  412. if(fd < 0){
  413. scperror(0, "can't create %s: %r", name);
  414. continue;
  415. }
  416. sendokresponse();
  417. /*
  418. * Committed to receive size bytes
  419. */
  420. errors = 0;
  421. for(i = 0; i < size; i += m){
  422. n = sizeof buf;
  423. if(n > size - i)
  424. n = size - i;
  425. m = readn(remotefd0, buf, n);
  426. if(m <= 0)
  427. scperror(1, "read error on connection: %r");
  428. if(errors == 0){
  429. n = write(fd, buf, m);
  430. if(n != m)
  431. errors = 1;
  432. }
  433. }
  434. /* if file exists, modes could be wrong */
  435. if(errors)
  436. scperror(0, "%s: write error: %r", name);
  437. else if(settimes || (exists && (d->mode&0777) != (mode&0777))){
  438. if(!exists && (d = dirfstat(fd)) == nil){
  439. scperror(0, "can't stat %s: %r", name);
  440. continue;
  441. }
  442. if(settimes){
  443. settimes = 0;
  444. d->atime = atime;
  445. d->mtime = mtime;
  446. }
  447. d->mode = (d->mode & ~0777) | (mode & 0777);
  448. if(dirwstat(name, d) < 0)
  449. scperror(0, "can't wstat %s: %r", name);
  450. }
  451. free(d);
  452. d = nil;
  453. close(fd);
  454. getresponse();
  455. if(errors)
  456. exits("write error");
  457. sendokresponse();
  458. break;
  459. default:
  460. scperror(0, "unrecognized header type char %c", buf[0]);
  461. scperror(1, "input line: %s", buf);
  462. }
  463. }
  464. }
  465. /*
  466. * Lastelem is called when we have a Dir with the final element, but if the file
  467. * has been bound, we want the original name that was used rather than
  468. * the contents of the stat buffer, so do this lexically.
  469. */
  470. char*
  471. lastelem(char *file)
  472. {
  473. char *elem;
  474. elem = strrchr(file, '/');
  475. if(elem == nil)
  476. return file;
  477. return elem+1;
  478. }
  479. void
  480. send(char *file)
  481. {
  482. Dir *d;
  483. ulong i;
  484. int m, n, fd;
  485. char buf[8192];
  486. if((fd = open(file, OREAD)) < 0){
  487. scperror(0, "can't open %s: %r", file);
  488. return;
  489. }
  490. if((d = dirfstat(fd)) == nil){
  491. scperror(0, "can't fstat %s: %r", file);
  492. goto Return;
  493. }
  494. if(d->qid.type == QTDIR){
  495. if(rflag)
  496. senddir(file, fd, d);
  497. else
  498. scperror(0, "%s: is a directory", file);
  499. goto Return;
  500. }
  501. if(pflag){
  502. fprint(remotefd1, "T%lud 0 %lud 0\n", d->mtime, d->atime);
  503. if(getresponse() < 0)
  504. goto Return;
  505. }
  506. fprint(remotefd1, "C%.4luo %lld %s\n", d->mode&0777, d->length, lastelem(file));
  507. if(getresponse() < 0)
  508. goto Return;
  509. /*
  510. * We are now committed to send d.length bytes, regardless
  511. */
  512. for(i=0; i<d->length; i+=m){
  513. n = sizeof buf;
  514. if(n > d->length - i)
  515. n = d->length - i;
  516. m = readn(fd, buf, n);
  517. if(m <= 0)
  518. break;
  519. write(remotefd1, buf, m);
  520. }
  521. if(i == d->length)
  522. sendokresponse();
  523. else{
  524. /* continue to send gibberish up to d.length */
  525. for(; i<d->length; i+=n){
  526. n = sizeof buf;
  527. if(n > d->length - i)
  528. n = d->length - i;
  529. write(remotefd1, buf, n);
  530. }
  531. scperror(0, "%s: %r", file);
  532. }
  533. getresponse();
  534. Return:
  535. free(d);
  536. close(fd);
  537. }
  538. int
  539. getresponse(void)
  540. {
  541. uchar first, byte, buf[256];
  542. int i;
  543. if (read(remotefd0, &first, 1) != 1)
  544. scperror(1, "lost connection");
  545. if(first == 0)
  546. return 0;
  547. i = 0;
  548. if(first > FATAL){
  549. fprint(2, "scp: unexpected response character 0x%.2ux\n", first);
  550. buf[i++] = first;
  551. }
  552. /* read error message up to newline */
  553. for(;;){
  554. if(read(remotefd0, &byte, 1) != 1)
  555. scperror(1, "response: dropped connection");
  556. if(byte == '\n')
  557. break;
  558. if(i < sizeof buf)
  559. buf[i++] = byte;
  560. }
  561. exitflag = "bad response";
  562. if(!remote)
  563. fprint(2, "%.*s\n", utfnlen((char*)buf, i), (char*)buf);
  564. if (first == ERROR)
  565. return -1;
  566. exits(exitflag);
  567. return 0; /* not reached */
  568. }
  569. void
  570. senddir(char *name, int fd, Dir *dirp)
  571. {
  572. Dir *d, *dir;
  573. int n;
  574. char file[256];
  575. if(pflag){
  576. fprint(remotefd1, "T%lud 0 %lud 0\n", dirp->mtime, dirp->atime);
  577. if(getresponse() < 0)
  578. return;
  579. }
  580. vprint("directory %s mode: D%.4lo %d %.1024s", name, dirp->mode&0777, 0, lastelem(name));
  581. fprint(remotefd1, "D%.4lo %d %.1024s\n", dirp->mode&0777, 0, dirp->name);
  582. if(getresponse() < 0)
  583. return;
  584. n = dirreadall(fd, &dir);
  585. for(d = dir; d < &dir[n]; d++){
  586. /* shouldn't happen with plan 9, but worth checking anyway */
  587. if(strcmp(d->name, ".")==0 || strcmp(d->name, "..")==0)
  588. continue;
  589. if(snprint(file, sizeof file, "%s/%s", name, d->name) > sizeof file-UTFmax){
  590. scperror(0, "%.20s.../%s: name too long; skipping file", file, d->name);
  591. continue;
  592. }
  593. send(file);
  594. }
  595. free(dir);
  596. fprint(remotefd1, "E\n");
  597. getresponse();
  598. }
  599. int
  600. remotessh(char *host, char *cmd)
  601. {
  602. int i, p[2];
  603. char *arg[32];
  604. vprint("remotessh: %s: %s", host, cmd);
  605. if(pipe(p) < 0)
  606. scperror(1, "pipe: %r");
  607. switch(fork()){
  608. case -1:
  609. scperror(1, "fork: %r");
  610. case 0:
  611. /* child */
  612. close(p[0]);
  613. dup(p[1], 0);
  614. dup(p[1], 1);
  615. for (i = 3; i < 100; i++)
  616. close(i);
  617. i = 0;
  618. arg[i++] = ssh;
  619. arg[i++] = "-x";
  620. arg[i++] = "-a";
  621. arg[i++] = "-m";
  622. if(iflag)
  623. arg[i++] = "-i";
  624. if(vflag)
  625. arg[i++] = "-v";
  626. arg[i++] = host;
  627. arg[i++] = cmd;
  628. arg[i] = nil;
  629. exec(ssh, arg);
  630. exits("exec failed");
  631. default:
  632. /* parent */
  633. close(p[1]);
  634. remotefd0 = p[0];
  635. remotefd1 = p[0];
  636. }
  637. return 0;
  638. }
  639. void
  640. scperror(int exit, char *fmt, ...)
  641. {
  642. char buf[2048];
  643. va_list arg;
  644. va_start(arg, fmt);
  645. vseprint(buf, buf+sizeof(buf), fmt, arg);
  646. va_end(arg);
  647. fprint(remotefd1, "%cscp: %s\n", ERROR, buf);
  648. if (!remote)
  649. fprint(2, "scp: %s\n", buf);
  650. exitflag = buf;
  651. if(exit)
  652. exits(exitflag);
  653. }
  654. char *
  655. fileaftercolon(char *file)
  656. {
  657. char *c, *s;
  658. c = utfrune(file, ':');
  659. if(c == nil)
  660. return nil;
  661. /* colon must be in middle of name to be a separator */
  662. if(c == file)
  663. return nil;
  664. /* does slash occur before colon? */
  665. s = utfrune(file, '/');
  666. if(s != nil && s < c)
  667. return nil;
  668. *c++ = '\0';
  669. if(*c == '\0')
  670. return ".";
  671. return c;
  672. }
  673. void
  674. mustbedir(char *file)
  675. {
  676. Dir *d;
  677. if((d = dirstat(file)) == nil){
  678. scperror(1, "%s: %r", file);
  679. return;
  680. }
  681. if(d->qid.type != QTDIR)
  682. scperror(1, "%s: Not a directory", file);
  683. free(d);
  684. }