scp.c 14 KB

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