scp.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  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. Dir nd;
  295. int setmodes;
  296. setmodes = pflag;
  297. if(exists){
  298. if(d->qid.type != QTDIR) {
  299. scperror(0, "%s: protocol botch: directory requrest for non-directory", dir);
  300. return d;
  301. }
  302. }else{
  303. /* create it writeable; will fix later */
  304. setmodes = 1;
  305. if (create(dir, OREAD, DMDIR|mode|0700) < 0){
  306. scperror(0, "%s: can't create: %r", dir);
  307. return d;
  308. }
  309. }
  310. receive(dir);
  311. if(settimes || setmodes){
  312. nulldir(&nd);
  313. if(settimes){
  314. nd.atime = atime;
  315. nd.mtime = mtime;
  316. d->atime = nd.atime;
  317. d->mtime = nd.mtime;
  318. }
  319. if(setmodes){
  320. nd.mode = DMDIR | (mode & 0777);
  321. d->mode = nd.mode;
  322. }
  323. if(dirwstat(dir, &nd) < 0){
  324. scperror(0, "can't wstat %s: %r", dir);
  325. free(d);
  326. return nil;
  327. }
  328. }
  329. return d;
  330. }
  331. void
  332. receive(char *dest)
  333. {
  334. int isdir, settimes, mode;
  335. int exists, n, i, fd, m;
  336. int errors;
  337. ulong atime, mtime, size;
  338. char buf[8192], *p;
  339. char name[1024];
  340. Dir *d;
  341. Dir nd;
  342. mtime = 0L;
  343. atime = 0L;
  344. settimes = 0;
  345. isdir = 0;
  346. if ((d = dirstat(dest)) && d->qid.type == QTDIR) {
  347. isdir = 1;
  348. }
  349. if(dflag && !isdir)
  350. scperror(1, "%s: not a directory: %r", dest);
  351. sendokresponse();
  352. for (;;) {
  353. readhdr(buf, sizeof buf);
  354. switch(buf[0]){
  355. case ERROR:
  356. case FATAL:
  357. if(!remote)
  358. fprint(2, "%s\n", buf+1);
  359. exitflag = "bad receive";
  360. if(buf[0] == FATAL)
  361. exits(exitflag);
  362. continue;
  363. case 'E':
  364. sendokresponse();
  365. return;
  366. case 'T':
  367. settimes = 1;
  368. p = buf + 1;
  369. mtime = strtol(p, &p, 10);
  370. if(*p++ != ' '){
  371. Badtime:
  372. scperror(1, "bad time format: %s", buf+1);
  373. }
  374. strtol(p, &p, 10);
  375. if(*p++ != ' ')
  376. goto Badtime;
  377. atime = strtol(p, &p, 10);
  378. if(*p++ != ' ')
  379. goto Badtime;
  380. strtol(p, &p, 10);
  381. if(*p++ != 0)
  382. goto Badtime;
  383. sendokresponse();
  384. continue;
  385. case 'D':
  386. case 'C':
  387. p = buf + 1;
  388. mode = strtol(p, &p, 8);
  389. if (*p++ != ' '){
  390. Badmode:
  391. scperror(1, "bad mode/size format: %s", buf+1);
  392. }
  393. size = strtoll(p, &p, 10);
  394. if(*p++ != ' ')
  395. goto Badmode;
  396. if(isdir){
  397. if(dest[0] == '\0')
  398. snprint(name, sizeof name, "%s", p);
  399. else
  400. snprint(name, sizeof name, "%s/%s", dest, p);
  401. }else
  402. snprint(name, sizeof name, "%s", dest);
  403. if(strlen(name) > sizeof name-UTFmax)
  404. scperror(1, "file name too long: %s", dest);
  405. exists = 1;
  406. free(d);
  407. if((d = dirstat(name)) == nil)
  408. exists = 0;
  409. if(buf[0] == 'D'){
  410. vprint("receive directory %s", name);
  411. d = receivedir(name, exists, d, settimes, atime, mtime, mode);
  412. settimes = 0;
  413. continue;
  414. }
  415. vprint("receive file %s by %s", name, getuser());
  416. fd = create(name, OWRITE, mode);
  417. if(fd < 0){
  418. scperror(0, "can't create %s: %r", name);
  419. continue;
  420. }
  421. sendokresponse();
  422. /*
  423. * Committed to receive size bytes
  424. */
  425. errors = 0;
  426. for(i = 0; i < size; i += m){
  427. n = sizeof buf;
  428. if(n > size - i)
  429. n = size - i;
  430. m = readn(remotefd0, buf, n);
  431. if(m <= 0)
  432. scperror(1, "read error on connection: %r");
  433. if(errors == 0){
  434. n = write(fd, buf, m);
  435. if(n != m)
  436. errors = 1;
  437. }
  438. }
  439. /* if file exists, modes could be wrong */
  440. if(errors)
  441. scperror(0, "%s: write error: %r", name);
  442. else if(settimes || (exists && (d->mode&0777) != (mode&0777))){
  443. nulldir(&nd);
  444. if(settimes){
  445. settimes = 0;
  446. nd.atime = atime;
  447. nd.mtime = mtime;
  448. }
  449. nd.mode = (d->mode & ~0777) | (mode&0777);
  450. if(dirwstat(name, &nd) < 0)
  451. scperror(0, "can't wstat %s: %r", name);
  452. }
  453. free(d);
  454. d = nil;
  455. close(fd);
  456. getresponse();
  457. if(errors)
  458. exits("write error");
  459. sendokresponse();
  460. break;
  461. default:
  462. scperror(0, "unrecognized header type char %c", buf[0]);
  463. scperror(1, "input line: %s", buf);
  464. }
  465. }
  466. }
  467. /*
  468. * Lastelem is called when we have a Dir with the final element, but if the file
  469. * has been bound, we want the original name that was used rather than
  470. * the contents of the stat buffer, so do this lexically.
  471. */
  472. char*
  473. lastelem(char *file)
  474. {
  475. char *elem;
  476. elem = strrchr(file, '/');
  477. if(elem == nil)
  478. return file;
  479. return elem+1;
  480. }
  481. void
  482. send(char *file)
  483. {
  484. Dir *d;
  485. ulong i;
  486. int m, n, fd;
  487. char buf[8192];
  488. if((fd = open(file, OREAD)) < 0){
  489. scperror(0, "can't open %s: %r", file);
  490. return;
  491. }
  492. if((d = dirfstat(fd)) == nil){
  493. scperror(0, "can't fstat %s: %r", file);
  494. goto Return;
  495. }
  496. if(d->qid.type == QTDIR){
  497. if(rflag)
  498. senddir(file, fd, d);
  499. else
  500. scperror(0, "%s: is a directory", file);
  501. goto Return;
  502. }
  503. if(pflag){
  504. fprint(remotefd1, "T%lud 0 %lud 0\n", d->mtime, d->atime);
  505. if(getresponse() < 0)
  506. goto Return;
  507. }
  508. fprint(remotefd1, "C%.4luo %lld %s\n", d->mode&0777, d->length, lastelem(file));
  509. if(getresponse() < 0)
  510. goto Return;
  511. /*
  512. * We are now committed to send d.length bytes, regardless
  513. */
  514. for(i=0; i<d->length; i+=m){
  515. n = sizeof buf;
  516. if(n > d->length - i)
  517. n = d->length - i;
  518. m = readn(fd, buf, n);
  519. if(m <= 0)
  520. break;
  521. write(remotefd1, buf, m);
  522. }
  523. if(i == d->length)
  524. sendokresponse();
  525. else{
  526. /* continue to send gibberish up to d.length */
  527. for(; i<d->length; i+=n){
  528. n = sizeof buf;
  529. if(n > d->length - i)
  530. n = d->length - i;
  531. write(remotefd1, buf, n);
  532. }
  533. scperror(0, "%s: %r", file);
  534. }
  535. getresponse();
  536. Return:
  537. free(d);
  538. close(fd);
  539. }
  540. int
  541. getresponse(void)
  542. {
  543. uchar first, byte, buf[256];
  544. int i;
  545. if (read(remotefd0, &first, 1) != 1)
  546. scperror(1, "lost connection");
  547. if(first == 0)
  548. return 0;
  549. i = 0;
  550. if(first > FATAL){
  551. fprint(2, "scp: unexpected response character 0x%.2ux\n", first);
  552. buf[i++] = first;
  553. }
  554. /* read error message up to newline */
  555. for(;;){
  556. if(read(remotefd0, &byte, 1) != 1)
  557. scperror(1, "response: dropped connection");
  558. if(byte == '\n')
  559. break;
  560. if(i < sizeof buf)
  561. buf[i++] = byte;
  562. }
  563. exitflag = "bad response";
  564. if(!remote)
  565. fprint(2, "%.*s\n", utfnlen((char*)buf, i), (char*)buf);
  566. if (first == ERROR)
  567. return -1;
  568. exits(exitflag);
  569. return 0; /* not reached */
  570. }
  571. void
  572. senddir(char *name, int fd, Dir *dirp)
  573. {
  574. Dir *d, *dir;
  575. int n;
  576. char file[256];
  577. if(pflag){
  578. fprint(remotefd1, "T%lud 0 %lud 0\n", dirp->mtime, dirp->atime);
  579. if(getresponse() < 0)
  580. return;
  581. }
  582. vprint("directory %s mode: D%.4lo %d %.1024s", name, dirp->mode&0777, 0, lastelem(name));
  583. fprint(remotefd1, "D%.4lo %d %.1024s\n", dirp->mode&0777, 0, dirp->name);
  584. if(getresponse() < 0)
  585. return;
  586. n = dirreadall(fd, &dir);
  587. for(d = dir; d < &dir[n]; d++){
  588. /* shouldn't happen with plan 9, but worth checking anyway */
  589. if(strcmp(d->name, ".")==0 || strcmp(d->name, "..")==0)
  590. continue;
  591. if(snprint(file, sizeof file, "%s/%s", name, d->name) > sizeof file-UTFmax){
  592. scperror(0, "%.20s.../%s: name too long; skipping file", file, d->name);
  593. continue;
  594. }
  595. send(file);
  596. }
  597. free(dir);
  598. fprint(remotefd1, "E\n");
  599. getresponse();
  600. }
  601. int
  602. remotessh(char *host, char *cmd)
  603. {
  604. int i, p[2];
  605. char *arg[32];
  606. vprint("remotessh: %s: %s", host, cmd);
  607. if(pipe(p) < 0)
  608. scperror(1, "pipe: %r");
  609. switch(fork()){
  610. case -1:
  611. scperror(1, "fork: %r");
  612. case 0:
  613. /* child */
  614. close(p[0]);
  615. dup(p[1], 0);
  616. dup(p[1], 1);
  617. for (i = 3; i < 100; i++)
  618. close(i);
  619. i = 0;
  620. arg[i++] = ssh;
  621. arg[i++] = "-x";
  622. arg[i++] = "-a";
  623. arg[i++] = "-m";
  624. if(iflag)
  625. arg[i++] = "-i";
  626. if(vflag)
  627. arg[i++] = "-v";
  628. arg[i++] = host;
  629. arg[i++] = cmd;
  630. arg[i] = nil;
  631. exec(ssh, arg);
  632. exits("exec failed");
  633. default:
  634. /* parent */
  635. close(p[1]);
  636. remotefd0 = p[0];
  637. remotefd1 = p[0];
  638. }
  639. return 0;
  640. }
  641. void
  642. scperror(int exit, char *fmt, ...)
  643. {
  644. char buf[2048];
  645. va_list arg;
  646. va_start(arg, fmt);
  647. vseprint(buf, buf+sizeof(buf), fmt, arg);
  648. va_end(arg);
  649. fprint(remotefd1, "%cscp: %s\n", ERROR, buf);
  650. if (!remote)
  651. fprint(2, "scp: %s\n", buf);
  652. exitflag = buf;
  653. if(exit)
  654. exits(exitflag);
  655. }
  656. char *
  657. fileaftercolon(char *file)
  658. {
  659. char *c, *s;
  660. c = utfrune(file, ':');
  661. if(c == nil)
  662. return nil;
  663. /* colon must be in middle of name to be a separator */
  664. if(c == file)
  665. return nil;
  666. /* does slash occur before colon? */
  667. s = utfrune(file, '/');
  668. if(s != nil && s < c)
  669. return nil;
  670. *c++ = '\0';
  671. if(*c == '\0')
  672. return ".";
  673. return c;
  674. }
  675. void
  676. mustbedir(char *file)
  677. {
  678. Dir *d;
  679. if((d = dirstat(file)) == nil){
  680. scperror(1, "%s: %r", file);
  681. return;
  682. }
  683. if(d->qid.type != QTDIR)
  684. scperror(1, "%s: Not a directory", file);
  685. free(d);
  686. }