scp.c 14 KB

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