scp.c 14 KB

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