PageRenderTime 52ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/sys/src/9k/port/sysfile.c

https://bitbucket.org/ericvh/hare/
C | 1579 lines | 1135 code | 211 blank | 233 comment | 198 complexity | d0cffa42884eab9eea96d2b3d001bc7c MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "../port/error.h"
  7. /*
  8. * The sys*() routines needn't poperror() as they return directly to syscall().
  9. */
  10. static void
  11. unlockfgrp(Fgrp *f)
  12. {
  13. int ex;
  14. ex = f->exceed;
  15. f->exceed = 0;
  16. unlock(f);
  17. if(ex)
  18. pprint("warning: process exceeds %d file descriptors\n", ex);
  19. }
  20. static int
  21. growfd(Fgrp *f, int fd) /* fd is always >= 0 */
  22. {
  23. Chan **newfd, **oldfd;
  24. if(fd < f->nfd)
  25. return 0;
  26. if(fd >= f->nfd+DELTAFD)
  27. return -1; /* out of range */
  28. /*
  29. * Unbounded allocation is unwise; besides, there are only 16 bits
  30. * of fid in 9P
  31. */
  32. if(f->nfd >= 5000){
  33. Exhausted:
  34. print("no free file descriptors\n");
  35. return -1;
  36. }
  37. newfd = malloc((f->nfd+DELTAFD)*sizeof(Chan*));
  38. if(newfd == 0)
  39. goto Exhausted;
  40. oldfd = f->fd;
  41. memmove(newfd, oldfd, f->nfd*sizeof(Chan*));
  42. f->fd = newfd;
  43. free(oldfd);
  44. f->nfd += DELTAFD;
  45. if(fd > f->maxfd){
  46. if(fd/100 > f->maxfd/100)
  47. f->exceed = (fd/100)*100;
  48. f->maxfd = fd;
  49. }
  50. return 1;
  51. }
  52. /*
  53. * this assumes that the fgrp is locked
  54. */
  55. static int
  56. findfreefd(Fgrp *f, int start)
  57. {
  58. int fd;
  59. for(fd=start; fd<f->nfd; fd++)
  60. if(f->fd[fd] == 0)
  61. break;
  62. if(fd >= f->nfd && growfd(f, fd) < 0)
  63. return -1;
  64. return fd;
  65. }
  66. int
  67. newfd(Chan *c)
  68. {
  69. int fd;
  70. Fgrp *f;
  71. f = up->fgrp;
  72. lock(f);
  73. fd = findfreefd(f, 0);
  74. if(fd < 0){
  75. unlockfgrp(f);
  76. return -1;
  77. }
  78. if(fd > f->maxfd)
  79. f->maxfd = fd;
  80. f->fd[fd] = c;
  81. unlockfgrp(f);
  82. return fd;
  83. }
  84. static int
  85. newfd2(int fd[2], Chan *c[2])
  86. {
  87. Fgrp *f;
  88. f = up->fgrp;
  89. lock(f);
  90. fd[0] = findfreefd(f, 0);
  91. if(fd[0] < 0){
  92. unlockfgrp(f);
  93. return -1;
  94. }
  95. fd[1] = findfreefd(f, fd[0]+1);
  96. if(fd[1] < 0){
  97. unlockfgrp(f);
  98. return -1;
  99. }
  100. if(fd[1] > f->maxfd)
  101. f->maxfd = fd[1];
  102. f->fd[fd[0]] = c[0];
  103. f->fd[fd[1]] = c[1];
  104. unlockfgrp(f);
  105. return 0;
  106. }
  107. Chan*
  108. fdtochan(int fd, int mode, int chkmnt, int iref)
  109. {
  110. Chan *c;
  111. Fgrp *f;
  112. c = nil;
  113. f = up->fgrp;
  114. lock(f);
  115. if(fd<0 || f->nfd<=fd || (c = f->fd[fd])==0) {
  116. unlock(f);
  117. error(Ebadfd);
  118. }
  119. if(iref)
  120. incref(c);
  121. unlock(f);
  122. if(chkmnt && (c->flag&CMSG)) {
  123. if(iref)
  124. cclose(c);
  125. error(Ebadusefd);
  126. }
  127. if(mode<0 || c->mode==ORDWR)
  128. return c;
  129. if((mode&OTRUNC) && c->mode==OREAD) {
  130. if(iref)
  131. cclose(c);
  132. error(Ebadusefd);
  133. }
  134. if((mode&~OTRUNC) != c->mode) {
  135. if(iref)
  136. cclose(c);
  137. error(Ebadusefd);
  138. }
  139. return c;
  140. }
  141. int
  142. openmode(int omode)
  143. {
  144. omode &= ~(OTRUNC|OCEXEC|ORCLOSE);
  145. if(omode > OEXEC)
  146. error(Ebadarg);
  147. if(omode == OEXEC)
  148. return OREAD;
  149. return omode;
  150. }
  151. void
  152. sysfd2path(Ar0* ar0, va_list list)
  153. {
  154. Chan *c;
  155. char *buf;
  156. int fd;
  157. usize nbuf;
  158. /*
  159. * int fd2path(int fd, char* buf, int nbuf);
  160. * should be
  161. * int fd2path(int fd, char* buf, usize nbuf);
  162. */
  163. fd = va_arg(list, int);
  164. buf = va_arg(list, char*);
  165. nbuf = va_arg(list, usize);
  166. buf = validaddr(buf, nbuf, 1);
  167. c = fdtochan(fd, -1, 0, 1);
  168. snprint(buf, nbuf, "%s", chanpath(c));
  169. cclose(c);
  170. ar0->i = 0;
  171. }
  172. void
  173. syspipe(Ar0* ar0, va_list list)
  174. {
  175. int *a, fd[2];
  176. Chan *c[2];
  177. static char *datastr[] = {"data", "data1"};
  178. /*
  179. * int pipe(int fd[2]);
  180. */
  181. a = va_arg(list, int*);
  182. a = validaddr(a, sizeof(fd), 1);
  183. evenaddr(PTR2UINT(a));
  184. c[0] = namec("#|", Atodir, 0, 0);
  185. c[1] = nil;
  186. fd[0] = -1;
  187. fd[1] = -1;
  188. if(waserror()){
  189. cclose(c[0]);
  190. if(c[1])
  191. cclose(c[1]);
  192. nexterror();
  193. }
  194. c[1] = cclone(c[0]);
  195. if(walk(&c[0], datastr+0, 1, 1, nil) < 0)
  196. error(Egreg);
  197. if(walk(&c[1], datastr+1, 1, 1, nil) < 0)
  198. error(Egreg);
  199. c[0] = c[0]->dev->open(c[0], ORDWR);
  200. c[1] = c[1]->dev->open(c[1], ORDWR);
  201. if(newfd2(fd, c) < 0)
  202. error(Enofd);
  203. poperror();
  204. a[0] = fd[0];
  205. a[1] = fd[1];
  206. ar0->i = 0;
  207. }
  208. void
  209. sysdup(Ar0* ar0, va_list list)
  210. {
  211. int nfd, ofd;
  212. Chan *nc, *oc;
  213. Fgrp *f;
  214. /*
  215. * int dup(int oldfd, int newfd);
  216. *
  217. * Close after dup'ing, so date > #d/1 works
  218. */
  219. ofd = va_arg(list, int);
  220. oc = fdtochan(ofd, -1, 0, 1);
  221. nfd = va_arg(list, int);
  222. if(nfd != -1){
  223. f = up->fgrp;
  224. lock(f);
  225. if(nfd < 0 || growfd(f, nfd) < 0) {
  226. unlockfgrp(f);
  227. cclose(oc);
  228. error(Ebadfd);
  229. }
  230. if(nfd > f->maxfd)
  231. f->maxfd = nfd;
  232. nc = f->fd[nfd];
  233. f->fd[nfd] = oc;
  234. unlockfgrp(f);
  235. if(nc != nil)
  236. cclose(nc);
  237. }else{
  238. if(waserror()) {
  239. cclose(oc);
  240. nexterror();
  241. }
  242. nfd = newfd(oc);
  243. if(nfd < 0)
  244. error(Enofd);
  245. poperror();
  246. }
  247. ar0->i = nfd;
  248. }
  249. void
  250. sysopen(Ar0* ar0, va_list list)
  251. {
  252. char *aname;
  253. int fd, omode;
  254. Chan *c;
  255. /*
  256. * int open(char* file, int omode);
  257. */
  258. aname = va_arg(list, char*);
  259. omode = va_arg(list, int);
  260. openmode(omode); /* error check only */
  261. c = nil;
  262. if(waserror()){
  263. if(c != nil)
  264. cclose(c);
  265. nexterror();
  266. }
  267. aname = validaddr(aname, 1, 0);
  268. c = namec(aname, Aopen, omode, 0);
  269. fd = newfd(c);
  270. if(fd < 0)
  271. error(Enofd);
  272. poperror();
  273. ar0->i = fd;
  274. }
  275. void
  276. fdclose(int fd, int flag)
  277. {
  278. int i;
  279. Chan *c;
  280. Fgrp *f;
  281. f = up->fgrp;
  282. lock(f);
  283. c = f->fd[fd];
  284. if(c == nil){
  285. /* can happen for users with shared fd tables */
  286. unlock(f);
  287. return;
  288. }
  289. if(flag){
  290. if(c == nil || !(c->flag&flag)){
  291. unlock(f);
  292. return;
  293. }
  294. }
  295. f->fd[fd] = nil;
  296. if(fd == f->maxfd)
  297. for(i = fd; --i >= 0 && f->fd[i] == 0; )
  298. f->maxfd = i;
  299. unlock(f);
  300. cclose(c);
  301. }
  302. void
  303. sysclose(Ar0* ar0, va_list list)
  304. {
  305. int fd;
  306. /*
  307. * int close(int fd);
  308. */
  309. fd = va_arg(list, int);
  310. fdtochan(fd, -1, 0, 0);
  311. fdclose(fd, 0);
  312. ar0->i = 0;
  313. }
  314. static long
  315. unionread(Chan *c, void *va, long n)
  316. {
  317. int i;
  318. long nr;
  319. Mhead *mh;
  320. Mount *mount;
  321. qlock(&c->umqlock);
  322. mh = c->umh;
  323. rlock(&mh->lock);
  324. mount = mh->mount;
  325. /* bring mount in sync with c->uri and c->umc */
  326. for(i = 0; mount != nil && i < c->uri; i++)
  327. mount = mount->next;
  328. nr = 0;
  329. while(mount != nil){
  330. /* Error causes component of union to be skipped */
  331. if(mount->to && !waserror()){
  332. if(c->umc == nil){
  333. c->umc = cclone(mount->to);
  334. c->umc = c->umc->dev->open(c->umc, OREAD);
  335. }
  336. nr = c->umc->dev->read(c->umc, va, n, c->umc->offset);
  337. c->umc->offset += nr;
  338. poperror();
  339. }
  340. if(nr > 0)
  341. break;
  342. /* Advance to next element */
  343. c->uri++;
  344. if(c->umc){
  345. cclose(c->umc);
  346. c->umc = nil;
  347. }
  348. mount = mount->next;
  349. }
  350. runlock(&mh->lock);
  351. qunlock(&c->umqlock);
  352. return nr;
  353. }
  354. static void
  355. unionrewind(Chan *c)
  356. {
  357. qlock(&c->umqlock);
  358. c->uri = 0;
  359. if(c->umc){
  360. cclose(c->umc);
  361. c->umc = nil;
  362. }
  363. qunlock(&c->umqlock);
  364. }
  365. static usize
  366. dirfixed(uchar *p, uchar *e, Dir *d)
  367. {
  368. int len;
  369. Dev *dev;
  370. len = GBIT16(p)+BIT16SZ;
  371. if(p + len > e)
  372. return 0;
  373. p += BIT16SZ; /* ignore size */
  374. dev = devtabget(GBIT16(p), 1); //XDYNX
  375. if(dev != nil){
  376. d->type = dev->dc;
  377. //devtabdecr(dev);
  378. }
  379. else
  380. d->type = -1;
  381. p += BIT16SZ;
  382. d->dev = GBIT32(p);
  383. p += BIT32SZ;
  384. d->qid.type = GBIT8(p);
  385. p += BIT8SZ;
  386. d->qid.vers = GBIT32(p);
  387. p += BIT32SZ;
  388. d->qid.path = GBIT64(p);
  389. p += BIT64SZ;
  390. d->mode = GBIT32(p);
  391. p += BIT32SZ;
  392. d->atime = GBIT32(p);
  393. p += BIT32SZ;
  394. d->mtime = GBIT32(p);
  395. p += BIT32SZ;
  396. d->length = GBIT64(p);
  397. return len;
  398. }
  399. static char*
  400. dirname(uchar *p, usize *n)
  401. {
  402. p += BIT16SZ+BIT16SZ+BIT32SZ+BIT8SZ+BIT32SZ+BIT64SZ
  403. + BIT32SZ+BIT32SZ+BIT32SZ+BIT64SZ;
  404. *n = GBIT16(p);
  405. return (char*)p+BIT16SZ;
  406. }
  407. static usize
  408. dirsetname(char *name, usize len, uchar *p, usize n, usize maxn)
  409. {
  410. char *oname;
  411. usize nn, olen;
  412. if(n == BIT16SZ)
  413. return BIT16SZ;
  414. oname = dirname(p, &olen);
  415. nn = n+len-olen;
  416. PBIT16(p, nn-BIT16SZ);
  417. if(nn > maxn)
  418. return BIT16SZ;
  419. if(len != olen)
  420. memmove(oname+len, oname+olen, p+n-(uchar*)(oname+olen));
  421. PBIT16((uchar*)(oname-2), len);
  422. memmove(oname, name, len);
  423. return nn;
  424. }
  425. /*
  426. * Mountfix might have caused the fixed results of the directory read
  427. * to overflow the buffer. Catch the overflow in c->dirrock.
  428. */
  429. static void
  430. mountrock(Chan *c, uchar *p, uchar **pe)
  431. {
  432. uchar *e, *r;
  433. int len, n;
  434. e = *pe;
  435. /* find last directory entry */
  436. for(;;){
  437. len = BIT16SZ+GBIT16(p);
  438. if(p+len >= e)
  439. break;
  440. p += len;
  441. }
  442. /* save it away */
  443. qlock(&c->rockqlock);
  444. if(c->nrock+len > c->mrock){
  445. n = ROUNDUP(c->nrock+len, 1024);
  446. r = smalloc(n);
  447. memmove(r, c->dirrock, c->nrock);
  448. free(c->dirrock);
  449. c->dirrock = r;
  450. c->mrock = n;
  451. }
  452. memmove(c->dirrock+c->nrock, p, len);
  453. c->nrock += len;
  454. qunlock(&c->rockqlock);
  455. /* drop it */
  456. *pe = p;
  457. }
  458. /*
  459. * Satisfy a directory read with the results saved in c->dirrock.
  460. */
  461. static int
  462. mountrockread(Chan *c, uchar *op, long n, long *nn)
  463. {
  464. long dirlen;
  465. uchar *rp, *erp, *ep, *p;
  466. /* common case */
  467. if(c->nrock == 0)
  468. return 0;
  469. /* copy out what we can */
  470. qlock(&c->rockqlock);
  471. rp = c->dirrock;
  472. erp = rp+c->nrock;
  473. p = op;
  474. ep = p+n;
  475. while(rp+BIT16SZ <= erp){
  476. dirlen = BIT16SZ+GBIT16(rp);
  477. if(p+dirlen > ep)
  478. break;
  479. memmove(p, rp, dirlen);
  480. p += dirlen;
  481. rp += dirlen;
  482. }
  483. if(p == op){
  484. qunlock(&c->rockqlock);
  485. return 0;
  486. }
  487. /* shift the rest */
  488. if(rp != erp)
  489. memmove(c->dirrock, rp, erp-rp);
  490. c->nrock = erp - rp;
  491. *nn = p - op;
  492. qunlock(&c->rockqlock);
  493. return 1;
  494. }
  495. static void
  496. mountrewind(Chan *c)
  497. {
  498. c->nrock = 0;
  499. }
  500. /*
  501. * Rewrite the results of a directory read to reflect current
  502. * name space bindings and mounts. Specifically, replace
  503. * directory entries for bind and mount points with the results
  504. * of statting what is mounted there. Except leave the old names.
  505. */
  506. static long
  507. mountfix(Chan *c, uchar *op, long n, long maxn)
  508. {
  509. char *name;
  510. int nbuf;
  511. Chan *nc;
  512. Mhead *mh;
  513. Mount *mount;
  514. usize dirlen, nname, r, rest;
  515. long l;
  516. uchar *buf, *e, *p;
  517. Dir d;
  518. p = op;
  519. buf = nil;
  520. nbuf = 0;
  521. for(e=&p[n]; p+BIT16SZ<e; p+=dirlen){
  522. dirlen = dirfixed(p, e, &d);
  523. if(dirlen == 0)
  524. break;
  525. nc = nil;
  526. mh = nil;
  527. if(findmount(&nc, &mh, d.type, d.dev, d.qid)){
  528. /*
  529. * If it's a union directory and the original is
  530. * in the union, don't rewrite anything.
  531. */
  532. for(mount=mh->mount; mount; mount=mount->next)
  533. if(eqchanddq(mount->to, d.type, d.dev, d.qid, 1))
  534. goto Norewrite;
  535. name = dirname(p, &nname);
  536. /*
  537. * Do the stat but fix the name. If it fails,
  538. * leave old entry.
  539. * BUG: If it fails because there isn't room for
  540. * the entry, what can we do? Nothing, really.
  541. * Might as well skip it.
  542. */
  543. if(buf == nil){
  544. buf = smalloc(4096);
  545. nbuf = 4096;
  546. }
  547. if(waserror())
  548. goto Norewrite;
  549. l = nc->dev->stat(nc, buf, nbuf);
  550. r = dirsetname(name, nname, buf, l, nbuf);
  551. if(r == BIT16SZ)
  552. error("dirsetname");
  553. poperror();
  554. /*
  555. * Shift data in buffer to accomodate new entry,
  556. * possibly overflowing into rock.
  557. */
  558. rest = e - (p+dirlen);
  559. if(r > dirlen){
  560. while(p+r+rest > op+maxn){
  561. mountrock(c, p, &e);
  562. if(e == p){
  563. dirlen = 0;
  564. goto Norewrite;
  565. }
  566. rest = e - (p+dirlen);
  567. }
  568. }
  569. if(r != dirlen){
  570. memmove(p+r, p+dirlen, rest);
  571. dirlen = r;
  572. e = p+dirlen+rest;
  573. }
  574. /*
  575. * Rewrite directory entry.
  576. */
  577. memmove(p, buf, r);
  578. Norewrite:
  579. cclose(nc);
  580. putmhead(mh);
  581. }
  582. }
  583. if(buf)
  584. free(buf);
  585. if(p != e)
  586. error("oops in mountfix");
  587. return e-op;
  588. }
  589. static long
  590. read(va_list list, int ispread)
  591. {
  592. int fd;
  593. long n, nn, nnn;
  594. void *p;
  595. Chan *c;
  596. vlong off;
  597. fd = va_arg(list, int);
  598. p = va_arg(list, void*);
  599. n = va_arg(list, long);
  600. p = validaddr(p, n, 1);
  601. c = fdtochan(fd, OREAD, 1, 1);
  602. if(waserror()){
  603. cclose(c);
  604. nexterror();
  605. }
  606. /*
  607. * The offset is passed through on directories, normally.
  608. * Sysseek complains, but pread is used by servers like exportfs,
  609. * that shouldn't need to worry about this issue.
  610. *
  611. * Notice that c->devoffset is the offset that c's dev is seeing.
  612. * The number of bytes read on this fd (c->offset) may be different
  613. * due to rewritings in mountfix.
  614. */
  615. if(ispread){
  616. off = va_arg(list, vlong);
  617. if(off == ~0LL){ /* use and maintain channel's offset */
  618. off = c->offset;
  619. ispread = 0;
  620. }
  621. }
  622. else
  623. off = c->offset;
  624. if(c->qid.type & QTDIR){
  625. /*
  626. * Directory read:
  627. * rewind to the beginning of the file if necessary;
  628. * try to fill the buffer via mountrockread;
  629. * clear ispread to always maintain the Chan offset.
  630. */
  631. if(off == 0LL){
  632. if(!ispread){
  633. c->offset = 0;
  634. c->devoffset = 0;
  635. }
  636. mountrewind(c);
  637. unionrewind(c);
  638. }
  639. if(!mountrockread(c, p, n, &nn)){
  640. if(c->umh)
  641. nn = unionread(c, p, n);
  642. else{
  643. if(off != c->offset)
  644. error(Eisdir);
  645. nn = c->dev->read(c, p, n, c->devoffset);
  646. }
  647. }
  648. nnn = mountfix(c, p, nn, n);
  649. ispread = 0;
  650. }
  651. else
  652. nnn = nn = c->dev->read(c, p, n, off);
  653. if(!ispread){
  654. lock(c);
  655. c->devoffset += nn;
  656. c->offset += nnn;
  657. unlock(c);
  658. }
  659. poperror();
  660. cclose(c);
  661. return nnn;
  662. }
  663. void
  664. sys_read(Ar0* ar0, va_list list)
  665. {
  666. /*
  667. * long read(int fd, void* buf, long nbytes);
  668. */
  669. ar0->l = read(list, 0);
  670. }
  671. void
  672. syspread(Ar0* ar0, va_list list)
  673. {
  674. /*
  675. * long pread(int fd, void* buf, long nbytes, vlong offset);
  676. */
  677. ar0->l = read(list, 1);
  678. }
  679. static long
  680. write(va_list list, int ispwrite)
  681. {
  682. int fd;
  683. long n, r;
  684. void *p;
  685. Chan *c;
  686. vlong off;
  687. fd = va_arg(list, int);
  688. p = va_arg(list, void*);
  689. r = n = va_arg(list, long);
  690. p = validaddr(p, n, 0);
  691. n = 0;
  692. c = fdtochan(fd, OWRITE, 1, 1);
  693. if(waserror()) {
  694. if(!ispwrite){
  695. lock(c);
  696. c->offset -= n;
  697. unlock(c);
  698. }
  699. cclose(c);
  700. nexterror();
  701. }
  702. if(c->qid.type & QTDIR)
  703. error(Eisdir);
  704. n = r;
  705. off = ~0LL;
  706. if(ispwrite)
  707. off = va_arg(list, vlong);
  708. if(off == ~0LL){ /* use and maintain channel's offset */
  709. lock(c);
  710. off = c->offset;
  711. c->offset += n;
  712. unlock(c);
  713. }
  714. r = c->dev->write(c, p, n, off);
  715. if(!ispwrite && r < n){
  716. lock(c);
  717. c->offset -= n - r;
  718. unlock(c);
  719. }
  720. poperror();
  721. cclose(c);
  722. return r;
  723. }
  724. void
  725. sys_write(Ar0* ar0, va_list list)
  726. {
  727. /*
  728. * long write(int fd, void* buf, long nbytes);
  729. */
  730. ar0->l = write(list, 0);
  731. }
  732. void
  733. syspwrite(Ar0* ar0, va_list list)
  734. {
  735. /*
  736. * long pwrite(int fd, void *buf, long nbytes, vlong offset);
  737. */
  738. ar0->l = write(list, 1);
  739. }
  740. static vlong
  741. sseek(int fd, vlong offset, int whence)
  742. {
  743. Chan *c;
  744. uchar buf[sizeof(Dir)+100];
  745. Dir dir;
  746. int n;
  747. c = fdtochan(fd, -1, 1, 1);
  748. if(waserror()){
  749. cclose(c);
  750. nexterror();
  751. }
  752. if(c->dev->dc == '|')
  753. error(Eisstream);
  754. switch(whence){
  755. case 0:
  756. if((c->qid.type & QTDIR) && offset != 0LL)
  757. error(Eisdir);
  758. c->offset = offset;
  759. break;
  760. case 1:
  761. if(c->qid.type & QTDIR)
  762. error(Eisdir);
  763. lock(c); /* lock for read/write update */
  764. offset += c->offset;
  765. c->offset = offset;
  766. unlock(c);
  767. break;
  768. case 2:
  769. if(c->qid.type & QTDIR)
  770. error(Eisdir);
  771. n = c->dev->stat(c, buf, sizeof buf);
  772. if(convM2D(buf, n, &dir, nil) == 0)
  773. error("internal error: stat error in seek");
  774. offset += dir.length;
  775. c->offset = offset;
  776. break;
  777. default:
  778. error(Ebadarg);
  779. }
  780. c->uri = 0;
  781. c->dri = 0;
  782. cclose(c);
  783. poperror();
  784. return offset;
  785. }
  786. void
  787. sysseek(Ar0* ar0, va_list list)
  788. {
  789. int fd, whence;
  790. vlong offset, *rv;
  791. /*
  792. * vlong seek(int fd, vlong n, int type);
  793. *
  794. * The system call actually has 4 arguments,
  795. * int _seek(vlong*, int, vlong, int);
  796. * and the first argument is where the offset
  797. * is returned. The C library arranges the
  798. * argument/return munging if necessary.
  799. */
  800. rv = va_arg(list, vlong*);
  801. rv = validaddr(rv, sizeof(vlong), 1);
  802. fd = va_arg(list, int);
  803. offset = va_arg(list, vlong);
  804. whence = va_arg(list, int);
  805. *rv = sseek(fd, offset, whence);
  806. ar0->i = 0;
  807. }
  808. void
  809. sysoseek(Ar0* ar0, va_list list)
  810. {
  811. long offset;
  812. int fd, whence;
  813. /*
  814. * long oseek(int fd, long n, int type);
  815. *
  816. * Deprecated; backwards compatibility only.
  817. */
  818. fd = va_arg(list, int);
  819. offset = va_arg(list, long);
  820. whence = va_arg(list, int);
  821. ar0->l = sseek(fd, offset, whence);
  822. }
  823. void
  824. validstat(uchar *s, usize n)
  825. {
  826. usize m;
  827. char buf[64];
  828. if(statcheck(s, n) < 0)
  829. error(Ebadstat);
  830. /* verify that name entry is acceptable */
  831. s += STATFIXLEN - 4*BIT16SZ; /* location of first string */
  832. /*
  833. * s now points at count for first string.
  834. * if it's too long, let the server decide; this is
  835. * only for his protection anyway. otherwise
  836. * we'd have to allocate and waserror.
  837. */
  838. m = GBIT16(s);
  839. s += BIT16SZ;
  840. if(m+1 > sizeof buf)
  841. return;
  842. memmove(buf, s, m);
  843. buf[m] = '\0';
  844. /* name could be '/' */
  845. if(strcmp(buf, "/") != 0)
  846. validname(buf, 0);
  847. }
  848. static char*
  849. pathlast(Path *p)
  850. {
  851. char *s;
  852. if(p == nil)
  853. return nil;
  854. if(p->len == 0)
  855. return nil;
  856. s = strrchr(p->s, '/');
  857. if(s)
  858. return s+1;
  859. return p->s;
  860. }
  861. void
  862. sysfstat(Ar0* ar0, va_list list)
  863. {
  864. int fd;
  865. Chan *c;
  866. usize n;
  867. int r;
  868. uchar *p;
  869. /*
  870. * int fstat(int fd, uchar* edir, int nedir);
  871. * should really be
  872. * usize fstat(int fd, uchar* edir, usize nedir);
  873. * but returning an unsigned is probably too
  874. * radical.
  875. */
  876. fd = va_arg(list, int);
  877. p = va_arg(list, uchar*);
  878. n = va_arg(list, usize);
  879. p = validaddr(p, n, 1);
  880. c = fdtochan(fd, -1, 0, 1);
  881. if(waserror()) {
  882. cclose(c);
  883. nexterror();
  884. }
  885. r = c->dev->stat(c, p, n);
  886. poperror();
  887. cclose(c);
  888. ar0->i = r;
  889. }
  890. void
  891. sysstat(Ar0* ar0, va_list list)
  892. {
  893. char *aname;
  894. Chan *c;
  895. usize n;
  896. int r;
  897. uchar *p;
  898. /*
  899. * int stat(char* name, uchar* edir, int nedir);
  900. * should really be
  901. * usize stat(char* name, uchar* edir, usize nedir);
  902. * but returning an unsigned is probably too
  903. * radical.
  904. */
  905. aname = va_arg(list, char*);
  906. aname = validaddr(aname, 1, 0);
  907. p = va_arg(list, uchar*);
  908. n = va_arg(list, usize);
  909. p = validaddr(p, n, 1);
  910. c = namec(aname, Aaccess, 0, 0);
  911. if(waserror()){
  912. cclose(c);
  913. nexterror();
  914. }
  915. r = c->dev->stat(c, p, n);
  916. aname = pathlast(c->path);
  917. if(aname)
  918. r = dirsetname(aname, strlen(aname), p, r, n);
  919. poperror();
  920. cclose(c);
  921. ar0->i = r;
  922. }
  923. void
  924. syschdir(Ar0* ar0, va_list list)
  925. {
  926. Chan *c;
  927. char *aname;
  928. /*
  929. * int chdir(char* dirname);
  930. */
  931. aname = va_arg(list, char*);
  932. aname = validaddr(aname, 1, 0);
  933. c = namec(aname, Atodir, 0, 0);
  934. cclose(up->dot);
  935. up->dot = c;
  936. ar0->i = 0;
  937. }
  938. static int
  939. bindmount(int ismount, int fd, int afd, char* arg0, char* arg1, int flag, char* spec)
  940. {
  941. int i;
  942. Dev *dev;
  943. Chan *c0, *c1, *ac, *bc;
  944. struct{
  945. Chan *chan;
  946. Chan *authchan;
  947. char *spec;
  948. int flags;
  949. }bogus;
  950. if((flag&~MMASK) || (flag&MORDER)==(MBEFORE|MAFTER))
  951. error(Ebadarg);
  952. bogus.flags = flag & MCACHE;
  953. if(ismount){
  954. if(up->pgrp->noattach)
  955. error(Enoattach);
  956. ac = nil;
  957. bc = fdtochan(fd, ORDWR, 0, 1);
  958. if(waserror()) {
  959. if(ac)
  960. cclose(ac);
  961. cclose(bc);
  962. nexterror();
  963. }
  964. if(afd >= 0)
  965. ac = fdtochan(afd, ORDWR, 0, 1);
  966. bogus.chan = bc;
  967. bogus.authchan = ac;
  968. bogus.spec = validaddr(spec, 1, 0);
  969. if(waserror())
  970. error(Ebadspec);
  971. spec = validnamedup(spec, 1);
  972. poperror();
  973. if(waserror()){
  974. free(spec);
  975. nexterror();
  976. }
  977. dev = devtabget('M', 0); //XDYNX
  978. if(waserror()){
  979. //devtabdecr(dev);
  980. nexterror();
  981. }
  982. c0 = dev->attach((char*)&bogus);
  983. poperror();
  984. //devtabdecr(dev);
  985. poperror(); /* spec */
  986. free(spec);
  987. poperror(); /* ac bc */
  988. if(ac)
  989. cclose(ac);
  990. cclose(bc);
  991. }else{
  992. bogus.spec = nil;
  993. c0 = namec(validaddr(arg0, 1, 0), Abind, 0, 0);
  994. }
  995. if(waserror()){
  996. cclose(c0);
  997. nexterror();
  998. }
  999. c1 = namec(validaddr(arg1, 1, 0), Amount, 0, 0);
  1000. if(waserror()){
  1001. cclose(c1);
  1002. nexterror();
  1003. }
  1004. i = cmount(&c0, c1, flag, bogus.spec);
  1005. poperror();
  1006. cclose(c1);
  1007. poperror();
  1008. cclose(c0);
  1009. if(ismount)
  1010. fdclose(fd, 0);
  1011. return i;
  1012. }
  1013. void
  1014. sysbind(Ar0* ar0, va_list list)
  1015. {
  1016. int flag;
  1017. char *name, *old;
  1018. /*
  1019. * int bind(char* name, char* old, int flag);
  1020. * should be
  1021. * long bind(char* name, char* old, int flag);
  1022. */
  1023. name = va_arg(list, char*);
  1024. old = va_arg(list, char*);
  1025. flag = va_arg(list, int);
  1026. ar0->i = bindmount(0, -1, -1, name, old, flag, nil);
  1027. }
  1028. void
  1029. sysmount(Ar0* ar0, va_list list)
  1030. {
  1031. int afd, fd, flag;
  1032. char *aname, *old;
  1033. /*
  1034. * int mount(int fd, int afd, char* old, int flag, char* aname);
  1035. * should be
  1036. * long mount(int fd, int afd, char* old, int flag, char* aname);
  1037. */
  1038. fd = va_arg(list, int);
  1039. afd = va_arg(list, int);
  1040. old = va_arg(list, char*);
  1041. flag = va_arg(list, int);
  1042. aname = va_arg(list, char*);
  1043. ar0->i = bindmount(1, fd, afd, nil, old, flag, aname);
  1044. }
  1045. void
  1046. sys_mount(Ar0* ar0, va_list list)
  1047. {
  1048. int fd, flag;
  1049. char *aname, *old;
  1050. /*
  1051. * int mount(int fd, char *old, int flag, char *aname);
  1052. * should be
  1053. * long mount(int fd, char *old, int flag, char *aname);
  1054. *
  1055. * Deprecated; backwards compatibility only.
  1056. */
  1057. fd = va_arg(list, int);
  1058. old = va_arg(list, char*);
  1059. flag = va_arg(list, int);
  1060. aname = va_arg(list, char*);
  1061. ar0->i = bindmount(1, fd, -1, nil, old, flag, aname);
  1062. }
  1063. void
  1064. sysunmount(Ar0* ar0, va_list list)
  1065. {
  1066. char *name, *old;
  1067. Chan *cmount, *cmounted;
  1068. /*
  1069. * int unmount(char* name, char* old);
  1070. */
  1071. name = va_arg(list, char*);
  1072. old = va_arg(list, char*);
  1073. cmount = namec(validaddr(old, 1, 0), Amount, 0, 0);
  1074. cmounted = nil;
  1075. if(name != nil) {
  1076. if(waserror()) {
  1077. cclose(cmount);
  1078. nexterror();
  1079. }
  1080. /*
  1081. * This has to be namec(..., Aopen, ...) because
  1082. * if arg[0] is something like /srv/cs or /fd/0,
  1083. * opening it is the only way to get at the real
  1084. * Chan underneath.
  1085. */
  1086. cmounted = namec(validaddr(name, 1, 0), Aopen, OREAD, 0);
  1087. poperror();
  1088. }
  1089. if(waserror()) {
  1090. cclose(cmount);
  1091. if(cmounted != nil)
  1092. cclose(cmounted);
  1093. nexterror();
  1094. }
  1095. cunmount(cmount, cmounted);
  1096. cclose(cmount);
  1097. if(cmounted != nil)
  1098. cclose(cmounted);
  1099. poperror();
  1100. ar0->i = 0;
  1101. }
  1102. void
  1103. syscreate(Ar0* ar0, va_list list)
  1104. {
  1105. char *aname;
  1106. int fd, omode, perm;
  1107. Chan *c;
  1108. /*
  1109. * int create(char* file, int omode, ulong perm);
  1110. * should be
  1111. * int create(char* file, int omode, int perm);
  1112. */
  1113. aname = va_arg(list, char*);
  1114. omode = va_arg(list, int);
  1115. perm = va_arg(list, int);
  1116. openmode(omode & ~OEXCL); /* error check only; OEXCL okay here */
  1117. c = nil;
  1118. if(waserror()) {
  1119. if(c != nil)
  1120. cclose(c);
  1121. nexterror();
  1122. }
  1123. c = namec(validaddr(aname, 1, 0), Acreate, omode, perm);
  1124. fd = newfd(c);
  1125. if(fd < 0)
  1126. error(Enofd);
  1127. poperror();
  1128. ar0->i = fd;
  1129. }
  1130. void
  1131. sysremove(Ar0* ar0, va_list list)
  1132. {
  1133. Chan *c;
  1134. char *aname;
  1135. /*
  1136. * int remove(char* file);
  1137. */
  1138. aname = va_arg(list, char*);
  1139. c = namec(validaddr(aname, 1, 0), Aremove, 0, 0);
  1140. /*
  1141. * Removing mount points is disallowed to avoid surprises
  1142. * (which should be removed: the mount point or the mounted Chan?).
  1143. */
  1144. if(c->ismtpt){
  1145. cclose(c);
  1146. error(Eismtpt);
  1147. }
  1148. if(waserror()){
  1149. c->dev = nil; /* see below */
  1150. cclose(c);
  1151. nexterror();
  1152. }
  1153. c->dev->remove(c);
  1154. /*
  1155. * Remove clunks the fid, but we need to recover the Chan
  1156. * so fake it up. rootclose() is known to be a nop.
  1157. Not sure this dicking around is right for Dev ref counts.
  1158. */
  1159. c->dev = nil;
  1160. poperror();
  1161. cclose(c);
  1162. ar0->i = 0;
  1163. }
  1164. static long
  1165. wstat(Chan* c, uchar* p, usize n)
  1166. {
  1167. long l;
  1168. usize namelen;
  1169. if(waserror()){
  1170. cclose(c);
  1171. nexterror();
  1172. }
  1173. /*
  1174. * Renaming mount points is disallowed to avoid surprises
  1175. * (which should be renamed? the mount point or the mounted Chan?).
  1176. */
  1177. if(c->ismtpt){
  1178. dirname(p, &namelen);
  1179. if(namelen)
  1180. nameerror(chanpath(c), Eismtpt);
  1181. }
  1182. l = c->dev->wstat(c, p, n);
  1183. poperror();
  1184. cclose(c);
  1185. return l;
  1186. }
  1187. void
  1188. syswstat(Ar0* ar0, va_list list)
  1189. {
  1190. Chan *c;
  1191. char *aname;
  1192. uchar *p;
  1193. usize n;
  1194. /*
  1195. * int wstat(char* name, uchar* edir, int nedir);
  1196. * should really be
  1197. * usize wstat(char* name, uchar* edir, usize nedir);
  1198. * but returning an unsigned is probably too
  1199. * radical.
  1200. */
  1201. aname = va_arg(list, char*);
  1202. p = va_arg(list, uchar*);
  1203. n = va_arg(list, usize);
  1204. p = validaddr(p, n, 0);
  1205. validstat(p, n);
  1206. c = namec(validaddr(aname, 1, 0), Aaccess, 0, 0);
  1207. ar0->l = wstat(c, p, n);
  1208. }
  1209. void
  1210. sysfwstat(Ar0* ar0, va_list list)
  1211. {
  1212. Chan *c;
  1213. int fd;
  1214. uchar *p;
  1215. usize n;
  1216. /*
  1217. * int fwstat(int fd, uchar* edir, int nedir);
  1218. * should really be
  1219. * usize wstat(int fd, uchar* edir, usize nedir);
  1220. * but returning an unsigned is probably too
  1221. * radical.
  1222. */
  1223. fd = va_arg(list, int);
  1224. p = va_arg(list, uchar*);
  1225. n = va_arg(list, usize);
  1226. p = validaddr(p, n, 0);
  1227. validstat(p, n);
  1228. c = fdtochan(fd, -1, 1, 1);
  1229. ar0->l = wstat(c, p, n);
  1230. }
  1231. static void
  1232. packoldstat(uchar *buf, Dir *d)
  1233. {
  1234. uchar *p;
  1235. ulong q;
  1236. /* lay down old stat buffer - grotty code but it's temporary */
  1237. p = buf;
  1238. strncpy((char*)p, d->name, 28);
  1239. p += 28;
  1240. strncpy((char*)p, d->uid, 28);
  1241. p += 28;
  1242. strncpy((char*)p, d->gid, 28);
  1243. p += 28;
  1244. q = d->qid.path & ~DMDIR; /* make sure doesn't accidentally look like directory */
  1245. if(d->qid.type & QTDIR) /* this is the real test of a new directory */
  1246. q |= DMDIR;
  1247. PBIT32(p, q);
  1248. p += BIT32SZ;
  1249. PBIT32(p, d->qid.vers);
  1250. p += BIT32SZ;
  1251. PBIT32(p, d->mode);
  1252. p += BIT32SZ;
  1253. PBIT32(p, d->atime);
  1254. p += BIT32SZ;
  1255. PBIT32(p, d->mtime);
  1256. p += BIT32SZ;
  1257. PBIT64(p, d->length);
  1258. p += BIT64SZ;
  1259. PBIT16(p, d->type);
  1260. p += BIT16SZ;
  1261. PBIT16(p, d->dev);
  1262. }
  1263. void
  1264. sys_stat(Ar0* ar0, va_list list)
  1265. {
  1266. Chan *c;
  1267. long l;
  1268. uchar buf[128], *p;
  1269. char *aname, *name, strs[128];
  1270. Dir d;
  1271. char old[] = "old stat system call - recompile";
  1272. /*
  1273. * int stat(char* name, char* edir);
  1274. * should have been
  1275. * usize stat(char* name, uchar* edir));
  1276. *
  1277. * Deprecated; backwards compatibility only.
  1278. */
  1279. aname = va_arg(list, char*);
  1280. p = va_arg(list, uchar*);
  1281. /*
  1282. * Old DIRLEN (116) plus a little should be plenty
  1283. * for the buffer sizes.
  1284. */
  1285. p = validaddr(p, 116, 1);
  1286. c = namec(validaddr(aname, 1, 0), Aaccess, 0, 0);
  1287. if(waserror()){
  1288. cclose(c);
  1289. nexterror();
  1290. }
  1291. l = c->dev->stat(c, buf, sizeof buf);
  1292. /*
  1293. * Buf contains a new stat buf; convert to old.
  1294. * Yuck.
  1295. * If buffer too small, time to face reality.
  1296. */
  1297. if(l <= BIT16SZ)
  1298. error(old);
  1299. name = pathlast(c->path);
  1300. if(name)
  1301. l = dirsetname(name, strlen(name), buf, l, sizeof buf);
  1302. l = convM2D(buf, l, &d, strs);
  1303. if(l == 0)
  1304. error(old);
  1305. packoldstat(p, &d);
  1306. poperror();
  1307. cclose(c);
  1308. ar0->i = 0;
  1309. }
  1310. void
  1311. sys_fstat(Ar0* ar0, va_list list)
  1312. {
  1313. Chan *c;
  1314. char *name;
  1315. long l;
  1316. uchar buf[128], *p;
  1317. char strs[128];
  1318. Dir d;
  1319. int fd;
  1320. char old[] = "old fstat system call - recompile";
  1321. /*
  1322. * int fstat(int fd, char* edir);
  1323. * should have been
  1324. * usize fstat(int fd, uchar* edir));
  1325. *
  1326. * Deprecated; backwards compatibility only.
  1327. */
  1328. fd = va_arg(list, int);
  1329. p = va_arg(list, uchar*);
  1330. /*
  1331. * Old DIRLEN (116) plus a little should be plenty
  1332. * for the buffer sizes.
  1333. */
  1334. p = validaddr(p, 116, 1);
  1335. c = fdtochan(fd, -1, 0, 1);
  1336. if(waserror()){
  1337. cclose(c);
  1338. nexterror();
  1339. }
  1340. l = c->dev->stat(c, buf, sizeof buf);
  1341. /*
  1342. * Buf contains a new stat buf; convert to old.
  1343. * Yuck.
  1344. * If buffer too small, time to face reality.
  1345. */
  1346. if(l <= BIT16SZ)
  1347. error(old);
  1348. name = pathlast(c->path);
  1349. if(name)
  1350. l = dirsetname(name, strlen(name), buf, l, sizeof buf);
  1351. l = convM2D(buf, l, &d, strs);
  1352. if(l == 0)
  1353. error(old);
  1354. packoldstat(p, &d);
  1355. poperror();
  1356. cclose(c);
  1357. ar0->i = 0;
  1358. }
  1359. void
  1360. sys_wstat(Ar0*, va_list)
  1361. {
  1362. error("old wstat system call - recompile");
  1363. }
  1364. void
  1365. sys_fwstat(Ar0*, va_list)
  1366. {
  1367. error("old fwstat system call - recompile");
  1368. }