main.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <auth.h>
  4. #include <fcall.h>
  5. #include <thread.h>
  6. #include <9p.h>
  7. #include <disk.h>
  8. #include "dat.h"
  9. #include "fns.h"
  10. typedef struct Aux Aux;
  11. struct Aux {
  12. int doff;
  13. Otrack *o;
  14. };
  15. static void checktoc(Drive*);
  16. int vflag;
  17. Drive *drive;
  18. int nchange;
  19. enum {
  20. Qdir = 0,
  21. Qctl = 1,
  22. Qwa = 2,
  23. Qwd = 3,
  24. Qtrack = 4,
  25. };
  26. char*
  27. geterrstr(void)
  28. {
  29. static char errbuf[ERRMAX];
  30. rerrstr(errbuf, sizeof errbuf);
  31. return errbuf;
  32. }
  33. void*
  34. emalloc(ulong sz)
  35. {
  36. void *v;
  37. v = malloc(sz);
  38. if(v == nil)
  39. sysfatal("malloc %lud fails\n", sz);
  40. memset(v, 0, sz);
  41. return v;
  42. }
  43. static void
  44. fsattach(Req *r)
  45. {
  46. char *spec;
  47. spec = r->ifcall.aname;
  48. if(spec && spec[0]) {
  49. respond(r, "invalid attach specifier");
  50. return;
  51. }
  52. checktoc(drive);
  53. r->fid->qid = (Qid){Qdir, drive->nchange, QTDIR};
  54. r->ofcall.qid = r->fid->qid;
  55. r->fid->aux = emalloc(sizeof(Aux));
  56. respond(r, nil);
  57. }
  58. static char*
  59. fsclone(Fid *old, Fid *new)
  60. {
  61. Aux *na;
  62. na = emalloc(sizeof(Aux));
  63. *na = *((Aux*)old->aux);
  64. if(na->o)
  65. na->o->nref++;
  66. new->aux = na;
  67. return nil;
  68. }
  69. static char*
  70. fswalk1(Fid *fid, char *name, Qid *qid)
  71. {
  72. int i;
  73. checktoc(drive);
  74. switch((ulong)fid->qid.path) {
  75. case Qdir:
  76. if(strcmp(name, "..") == 0) {
  77. *qid = (Qid){Qdir, drive->nchange, QTDIR};
  78. return nil;
  79. }
  80. if(strcmp(name, "ctl") == 0) {
  81. *qid = (Qid){Qctl, 0, 0};
  82. return nil;
  83. }
  84. if(strcmp(name, "wa") == 0 && drive->writeok) {
  85. *qid = (Qid){Qwa, drive->nchange, QTDIR};
  86. return nil;
  87. }
  88. if(strcmp(name, "wd") == 0 && drive->writeok) {
  89. *qid = (Qid){Qwd, drive->nchange, QTDIR};
  90. return nil;
  91. }
  92. for(i=0; i<drive->ntrack; i++)
  93. if(strcmp(drive->track[i].name, name) == 0)
  94. break;
  95. if(i == drive->ntrack) {
  96. return "file not found";
  97. }
  98. *qid = (Qid){Qtrack+i, 0, 0};
  99. return nil;
  100. case Qwa:
  101. case Qwd:
  102. if(strcmp(name, "..") == 0) {
  103. *qid = (Qid){Qdir, drive->nchange, QTDIR};
  104. return nil;
  105. }
  106. return "file not found";
  107. default: /* bug: lib9p could handle this */
  108. return "walk in non-directory";
  109. }
  110. }
  111. static void
  112. fscreate(Req *r)
  113. {
  114. int omode, type;
  115. Otrack *o;
  116. Fid *fid;
  117. fid = r->fid;
  118. omode = r->ifcall.mode;
  119. if(omode != OWRITE) {
  120. respond(r, "bad mode (use OWRITE)");
  121. return;
  122. }
  123. switch((ulong)fid->qid.path) {
  124. case Qdir:
  125. default:
  126. respond(r, "permission denied");
  127. return;
  128. case Qwa:
  129. type = TypeAudio;
  130. break;
  131. case Qwd:
  132. type = TypeData;
  133. break;
  134. }
  135. if((drive->cap & Cwrite) == 0) {
  136. respond(r, "drive does not write");
  137. return;
  138. }
  139. o = drive->create(drive, type);
  140. if(o == nil) {
  141. respond(r, geterrstr());
  142. return;
  143. }
  144. drive->nchange = -1;
  145. checktoc(drive); /* update directory info */
  146. o->nref = 1;
  147. ((Aux*)fid->aux)->o = o;
  148. fid->qid = (Qid){Qtrack+(o->track - drive->track), drive->nchange, 0};
  149. r->ofcall.qid = fid->qid;
  150. respond(r, nil);
  151. }
  152. static void
  153. fsremove(Req *r)
  154. {
  155. switch((ulong)r->fid->qid.path){
  156. case Qwa:
  157. case Qwd:
  158. if(drive->fixate(drive) < 0)
  159. respond(r, geterrstr());
  160. // let's see if it can figure this out drive->writeok = 0;
  161. else
  162. respond(r, nil);
  163. checktoc(drive);
  164. break;
  165. default:
  166. respond(r, "permission denied");
  167. break;
  168. }
  169. }
  170. int
  171. fillstat(ulong qid, Dir *d)
  172. {
  173. Track *t;
  174. memset(d, 0, sizeof(Dir));
  175. d->uid = "cd";
  176. d->gid = "cd";
  177. d->muid = "";
  178. d->qid = (Qid){qid, drive->nchange, 0};
  179. d->atime = time(0);
  180. d->atime = drive->changetime;
  181. switch(qid){
  182. case Qdir:
  183. d->name = "/";
  184. d->qid.type = QTDIR;
  185. d->mode = DMDIR|0777;
  186. break;
  187. case Qctl:
  188. d->name = "ctl";
  189. d->mode = 0666;
  190. break;
  191. case Qwa:
  192. if(drive->writeok == 0)
  193. return 0;
  194. d->name = "wa";
  195. d->qid.type = QTDIR;
  196. d->mode = DMDIR|0777;
  197. break;
  198. case Qwd:
  199. if(drive->writeok == 0)
  200. return 0;
  201. d->name = "wd";
  202. d->qid.type = QTDIR;
  203. d->mode = DMDIR|0777;
  204. break;
  205. default:
  206. if(qid-Qtrack >= drive->ntrack)
  207. return 0;
  208. t = &drive->track[qid-Qtrack];
  209. if(strcmp(t->name, "") == 0)
  210. return 0;
  211. d->name = t->name;
  212. d->mode = t->mode;
  213. d->length = t->size;
  214. break;
  215. }
  216. return 1;
  217. }
  218. static ulong
  219. cddb_sum(int n)
  220. {
  221. int ret;
  222. ret = 0;
  223. while(n > 0) {
  224. ret += n%10;
  225. n /= 10;
  226. }
  227. return ret;
  228. }
  229. static ulong
  230. diskid(Drive *d)
  231. {
  232. int i, n;
  233. ulong tmp;
  234. Msf *ms, *me;
  235. n = 0;
  236. for(i=0; i < d->ntrack; i++)
  237. n += cddb_sum(d->track[i].mbeg.m*60+d->track[i].mbeg.s);
  238. ms = &d->track[0].mbeg;
  239. me = &d->track[d->ntrack].mbeg;
  240. tmp = (me->m*60+me->s) - (ms->m*60+ms->s);
  241. /*
  242. * the spec says n%0xFF rather than n&0xFF. it's unclear which is correct.
  243. * most CDs are in the database under both entries.
  244. */
  245. return ((n % 0xFF) << 24 | (tmp << 8) | d->ntrack);
  246. }
  247. static void
  248. readctl(Req *r)
  249. {
  250. int i, isaudio;
  251. char s[1024];
  252. Msf *m;
  253. strcpy(s, "");
  254. isaudio = 0;
  255. for(i=0; i<drive->ntrack; i++)
  256. if(drive->track[i].type == TypeAudio)
  257. isaudio = 1;
  258. if(isaudio){
  259. sprint(s, "aux/cddb query %8.8lux %d", diskid(drive), drive->ntrack);
  260. for(i=0; i<drive->ntrack; i++){
  261. m = &drive->track[i].mbeg;
  262. sprint(s+strlen(s), " %d", (m->m*60+m->s)*75+m->f);
  263. }
  264. m = &drive->track[drive->ntrack].mbeg;
  265. sprint(s+strlen(s), " %d\n", m->m*60+m->s);
  266. }
  267. if(drive->readspeed == drive->writespeed)
  268. sprint(s+strlen(s), "speed %d\n", drive->readspeed);
  269. else
  270. sprint(s+strlen(s), "speed read %d write %d\n", drive->readspeed, drive->writespeed);
  271. sprint(s+strlen(s), "maxspeed read %d write %d\n", drive->maxreadspeed, drive->maxwritespeed);
  272. readstr(r, s);
  273. }
  274. static void
  275. fsread(Req *r)
  276. {
  277. int j, n, m;
  278. uchar *p, *ep;
  279. Dir d;
  280. Fid *fid;
  281. Otrack *o;
  282. vlong offset;
  283. void *buf;
  284. long count;
  285. Aux *a;
  286. fid = r->fid;
  287. offset = r->ifcall.offset;
  288. buf = r->ofcall.data;
  289. count = r->ifcall.count;
  290. switch((ulong)fid->qid.path) {
  291. case Qdir:
  292. checktoc(drive);
  293. p = buf;
  294. ep = p+count;
  295. m = Qtrack+drive->ntrack;
  296. a = fid->aux;
  297. if(offset == 0)
  298. a->doff = 1; /* skip root */
  299. for(j=a->doff; j<m; j++) {
  300. if(fillstat(j, &d)) {
  301. if((n = convD2M(&d, p, ep-p)) <= BIT16SZ)
  302. break;
  303. p += n;
  304. }
  305. }
  306. a->doff = j;
  307. r->ofcall.count = p-(uchar*)buf;
  308. respond(r, nil);
  309. return;
  310. case Qwa:
  311. case Qwd:
  312. r->ofcall.count = 0;
  313. respond(r, nil);
  314. return;
  315. case Qctl:
  316. readctl(r);
  317. respond(r, nil);
  318. return;
  319. }
  320. /* a disk track; we can only call read for whole blocks */
  321. o = ((Aux*)fid->aux)->o;
  322. if((count = o->drive->read(o, buf, count, offset)) < 0)
  323. respond(r, geterrstr());
  324. else{
  325. r->ofcall.count = count;
  326. respond(r, nil);
  327. }
  328. return;
  329. }
  330. static char *Ebadmsg = "bad cdfs control message";
  331. static char*
  332. writectl(void *v, long count)
  333. {
  334. char buf[256];
  335. char *f[10], *p;
  336. int i, nf, n, r, w, what;
  337. if(count >= sizeof(buf))
  338. count = sizeof(buf)-1;
  339. memmove(buf, v, count);
  340. buf[count] = '\0';
  341. nf = tokenize(buf, f, nelem(f));
  342. if(nf == 0)
  343. return Ebadmsg;
  344. if(strcmp(f[0], "speed") == 0){
  345. what = 0;
  346. r = w = -1;
  347. if(nf == 1)
  348. return Ebadmsg;
  349. for(i=1; i<nf; i++){
  350. if(strcmp(f[i], "read") == 0 || strcmp(f[i], "write") == 0){
  351. if(what!=0 && what!='?')
  352. return Ebadmsg;
  353. what = f[i][0];
  354. }else{
  355. n = strtol(f[i], &p, 0);
  356. if(*p != '\0' || n <= 0)
  357. return Ebadmsg;
  358. switch(what){
  359. case 0:
  360. if(r >= 0 || w >= 0)
  361. return Ebadmsg;
  362. r = w = n;
  363. what = '?';
  364. break;
  365. case 'r':
  366. if(r >= 0)
  367. return Ebadmsg;
  368. r = n;
  369. what = '?';
  370. break;
  371. case 'w':
  372. if(w >= 0)
  373. return Ebadmsg;
  374. w = n;
  375. what = '?';
  376. break;
  377. default:
  378. return Ebadmsg;
  379. }
  380. }
  381. }
  382. if(what != '?')
  383. return Ebadmsg;
  384. return drive->setspeed(drive, r, w);
  385. }
  386. return drive->ctl(drive, nf, f);
  387. }
  388. static void
  389. fswrite(Req *r)
  390. {
  391. Otrack *o;
  392. Fid *fid;
  393. fid = r->fid;
  394. r->ofcall.count = r->ifcall.count;
  395. if(fid->qid.path == Qctl) {
  396. respond(r, writectl(r->ifcall.data, r->ifcall.count));
  397. return;
  398. }
  399. if((o = ((Aux*)fid->aux)->o) == nil || o->omode != OWRITE) {
  400. respond(r, "permission denied");
  401. return;
  402. }
  403. if(o->drive->write(o, r->ifcall.data, r->ifcall.count) < 0)
  404. respond(r, geterrstr());
  405. else
  406. respond(r, nil);
  407. }
  408. static void
  409. fsstat(Req *r)
  410. {
  411. fillstat((ulong)r->fid->qid.path, &r->d);
  412. r->d.name = estrdup9p(r->d.name);
  413. r->d.uid = estrdup9p(r->d.uid);
  414. r->d.gid = estrdup9p(r->d.gid);
  415. r->d.muid = estrdup9p(r->d.muid);
  416. respond(r, nil);
  417. }
  418. static void
  419. fsopen(Req *r)
  420. {
  421. int omode;
  422. Fid *fid;
  423. Otrack *o;
  424. fid = r->fid;
  425. omode = r->ifcall.mode;
  426. checktoc(drive);
  427. r->ofcall.qid = (Qid){fid->qid.path, drive->nchange, fid->qid.vers};
  428. switch((ulong)fid->qid.path){
  429. case Qdir:
  430. case Qwa:
  431. case Qwd:
  432. if(omode == OREAD)
  433. respond(r, nil);
  434. else
  435. respond(r, "permission denied");
  436. return;
  437. case Qctl:
  438. if(omode&~(OTRUNC|OREAD|OWRITE|ORDWR))
  439. respond(r, "permission denied");
  440. else
  441. respond(r, nil);
  442. return;
  443. default:
  444. if(fid->qid.path >= Qtrack+drive->ntrack) {
  445. respond(r, "file no longer exists");
  446. return;
  447. }
  448. if(omode != OREAD || (o = drive->openrd(drive, fid->qid.path-Qtrack)) == nil) {
  449. respond(r, "permission denied");
  450. return;
  451. }
  452. o->nref = 1;
  453. ((Aux*)fid->aux)->o = o;
  454. respond(r, nil);
  455. }
  456. }
  457. static uchar zero[BScdda];
  458. static void
  459. fsdestroyfid(Fid *fid)
  460. {
  461. Aux *aux;
  462. Otrack *o;
  463. aux = fid->aux;
  464. if(aux == nil)
  465. return;
  466. o = aux->o;
  467. if(o && --o->nref == 0) {
  468. bterm(o->buf);
  469. drive->close(o);
  470. checktoc(drive);
  471. }
  472. }
  473. static void
  474. checktoc(Drive *drive)
  475. {
  476. int i;
  477. Track *t;
  478. drive->gettoc(drive);
  479. if(drive->nameok)
  480. return;
  481. for(i=0; i<drive->ntrack; i++) {
  482. t = &drive->track[i];
  483. if(t->size == 0) /* being created */
  484. t->mode = 0;
  485. else
  486. t->mode = 0444;
  487. sprint(t->name, "?%.3d", i);
  488. switch(t->type){
  489. case TypeNone:
  490. t->name[0] = 'u';
  491. t->mode = 0;
  492. break;
  493. case TypeData:
  494. t->name[0] = 'd';
  495. break;
  496. case TypeAudio:
  497. t->name[0] = 'a';
  498. break;
  499. case TypeBlank:
  500. t->name[0] = '\0';
  501. break;
  502. default:
  503. print("unknown type %d\n", t->type);
  504. break;
  505. }
  506. }
  507. drive->nameok = 1;
  508. }
  509. long
  510. bufread(Otrack *t, void *v, long n, long off)
  511. {
  512. return bread(t->buf, v, n, off);
  513. }
  514. long
  515. bufwrite(Otrack *t, void *v, long n)
  516. {
  517. return bwrite(t->buf, v, n);
  518. }
  519. Srv fs = {
  520. .attach= fsattach,
  521. .destroyfid= fsdestroyfid,
  522. .clone= fsclone,
  523. .walk1= fswalk1,
  524. .open= fsopen,
  525. .read= fsread,
  526. .write= fswrite,
  527. .create= fscreate,
  528. .remove= fsremove,
  529. .stat= fsstat,
  530. };
  531. void
  532. usage(void)
  533. {
  534. fprint(2, "usage: cdfs [-Dv] [-d /dev/sdC0] [-m mtpt]\n");
  535. exits("usage");
  536. }
  537. void
  538. main(int argc, char **argv)
  539. {
  540. Scsi *s;
  541. int fd;
  542. char *dev, *mtpt;
  543. dev = "/dev/sdD0";
  544. mtpt = "/mnt/cd";
  545. ARGBEGIN{
  546. case 'D':
  547. chatty9p++;
  548. break;
  549. case 'd':
  550. dev = ARGF();
  551. break;
  552. case 'm':
  553. mtpt = ARGF();
  554. break;
  555. case 'v':
  556. if((fd = create("/tmp/cdfs.log", OWRITE, 0666)) >= 0) {
  557. dup(fd, 2);
  558. dup(fd, 1);
  559. if(fd != 1 && fd != 2)
  560. close(fd);
  561. vflag++;
  562. scsiverbose++;
  563. }
  564. break;
  565. default:
  566. usage();
  567. }ARGEND
  568. if(dev == nil || mtpt == nil || argc > 0)
  569. usage();
  570. if((s = openscsi(dev)) == nil) {
  571. fprint(2, "openscsi '%s': %r\n", dev);
  572. exits("openscsi");
  573. }
  574. if((drive = mmcprobe(s)) == nil) {
  575. fprint(2, "mmcprobe '%s': %r\n", dev);
  576. exits("mmcprobe");
  577. }
  578. checktoc(drive);
  579. postmountsrv(&fs, nil, mtpt, MREPL|MCREATE);
  580. exits(nil);
  581. }