1
0

devsrv.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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. typedef struct Srv Srv;
  8. struct Srv
  9. {
  10. char *name;
  11. char *owner;
  12. ulong perm;
  13. Chan *chan;
  14. Srv *link;
  15. ulong path;
  16. };
  17. static QLock srvlk;
  18. static Srv *srv;
  19. static int qidpath;
  20. static int
  21. srvgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
  22. {
  23. Srv *sp;
  24. Qid q;
  25. if(s == DEVDOTDOT){
  26. devdir(c, c->qid, "#s", 0, eve, 0555, dp);
  27. return 1;
  28. }
  29. qlock(&srvlk);
  30. for(sp = srv; sp && s; sp = sp->link)
  31. s--;
  32. if(sp == 0) {
  33. qunlock(&srvlk);
  34. return -1;
  35. }
  36. mkqid(&q, sp->path, 0, QTFILE);
  37. /* make sure name string continues to exist after we release lock */
  38. kstrcpy(up->genbuf, sp->name, sizeof up->genbuf);
  39. devdir(c, q, up->genbuf, 0, sp->owner, sp->perm, dp);
  40. qunlock(&srvlk);
  41. return 1;
  42. }
  43. static void
  44. srvinit(void)
  45. {
  46. qidpath = 1;
  47. }
  48. static Chan*
  49. srvattach(char *spec)
  50. {
  51. return devattach('s', spec);
  52. }
  53. static Walkqid*
  54. srvwalk(Chan *c, Chan *nc, char **name, int nname)
  55. {
  56. return devwalk(c, nc, name, nname, 0, 0, srvgen);
  57. }
  58. static Srv*
  59. srvlookup(char *name, ulong qidpath)
  60. {
  61. Srv *sp;
  62. for(sp = srv; sp; sp = sp->link)
  63. if(sp->path == qidpath || (name && strcmp(sp->name, name) == 0))
  64. return sp;
  65. return nil;
  66. }
  67. static int
  68. srvstat(Chan *c, uchar *db, int n)
  69. {
  70. return devstat(c, db, n, 0, 0, srvgen);
  71. }
  72. char*
  73. srvname(Chan *c)
  74. {
  75. Srv *sp;
  76. char *s;
  77. for(sp = srv; sp; sp = sp->link)
  78. if(sp->chan == c){
  79. s = smalloc(3+strlen(sp->name)+1);
  80. sprint(s, "#s/%s", sp->name);
  81. return s;
  82. }
  83. return nil;
  84. }
  85. static Chan*
  86. srvopen(Chan *c, int omode)
  87. {
  88. Srv *sp;
  89. if(c->qid.type == QTDIR){
  90. if(omode & ORCLOSE)
  91. error(Eperm);
  92. if(omode != OREAD)
  93. error(Eisdir);
  94. c->mode = omode;
  95. c->flag |= COPEN;
  96. c->offset = 0;
  97. return c;
  98. }
  99. qlock(&srvlk);
  100. if(waserror()){
  101. qunlock(&srvlk);
  102. nexterror();
  103. }
  104. sp = srvlookup(nil, c->qid.path);
  105. if(sp == 0 || sp->chan == 0)
  106. error(Eshutdown);
  107. if(omode&OTRUNC)
  108. error("srv file already exists");
  109. if(openmode(omode)!=sp->chan->mode && sp->chan->mode!=ORDWR)
  110. error(Eperm);
  111. devpermcheck(sp->owner, sp->perm, omode);
  112. cclose(c);
  113. incref(sp->chan);
  114. qunlock(&srvlk);
  115. poperror();
  116. return sp->chan;
  117. }
  118. static void
  119. srvcreate(Chan *c, char *name, int omode, ulong perm)
  120. {
  121. Srv *sp;
  122. if(openmode(omode) != OWRITE)
  123. error(Eperm);
  124. if(omode & OCEXEC) /* can't happen */
  125. panic("someone broke namec");
  126. sp = malloc(sizeof(Srv));
  127. if(sp == 0)
  128. error(Enomem);
  129. qlock(&srvlk);
  130. if(waserror()){
  131. free(sp);
  132. qunlock(&srvlk);
  133. nexterror();
  134. }
  135. if(srvlookup(name, -1))
  136. error(Eexist);
  137. sp->path = qidpath++;
  138. sp->link = srv;
  139. c->qid.type = QTFILE;
  140. c->qid.path = sp->path;
  141. srv = sp;
  142. qunlock(&srvlk);
  143. poperror();
  144. sp->name = smalloc(strlen(name)+1);
  145. strcpy(sp->name, name);
  146. kstrdup(&sp->owner, up->user);
  147. sp->perm = perm&0777;
  148. c->flag |= COPEN;
  149. c->mode = OWRITE;
  150. }
  151. static void
  152. srvremove(Chan *c)
  153. {
  154. Srv *sp, **l;
  155. if(c->qid.type == QTDIR)
  156. error(Eperm);
  157. qlock(&srvlk);
  158. if(waserror()){
  159. qunlock(&srvlk);
  160. nexterror();
  161. }
  162. l = &srv;
  163. for(sp = *l; sp; sp = sp->link) {
  164. if(sp->path == c->qid.path)
  165. break;
  166. l = &sp->link;
  167. }
  168. if(sp == 0)
  169. error(Enonexist);
  170. if(strcmp(sp->name, "boot") == 0)
  171. error(Eperm);
  172. *l = sp->link;
  173. qunlock(&srvlk);
  174. poperror();
  175. if(sp->chan)
  176. cclose(sp->chan);
  177. if(sp->name){
  178. free(sp->name);
  179. sp->name = nil;
  180. }
  181. free(sp);
  182. }
  183. static int
  184. srvwstat(Chan *c, uchar *dp, int n)
  185. {
  186. Dir d;
  187. Srv *sp;
  188. if(c->qid.type & QTDIR)
  189. error(Eperm);
  190. qlock(&srvlk);
  191. if(waserror()){
  192. qunlock(&srvlk);
  193. nexterror();
  194. }
  195. sp = srvlookup(nil, c->qid.path);
  196. if(sp == 0)
  197. error(Enonexist);
  198. if(strcmp(sp->owner, up->user) && !iseve())
  199. error(Eperm);
  200. n = convM2D(dp, n, &d, nil);
  201. if(n == 0)
  202. error (Eshortstat);
  203. if(d.mode != ~0UL)
  204. sp->perm = d.mode & 0777;
  205. if(d.uid && *d.uid)
  206. kstrdup(&sp->owner, d.uid);
  207. qunlock(&srvlk);
  208. poperror();
  209. return n;
  210. }
  211. static void
  212. srvclose(Chan *c)
  213. {
  214. /*
  215. * in theory we need to override any changes in removability
  216. * since open, but since all that's checked is the owner,
  217. * which is immutable, all is well.
  218. */
  219. if(c->flag & CRCLOSE){
  220. if(waserror())
  221. return;
  222. srvremove(c);
  223. poperror();
  224. }
  225. }
  226. static long
  227. srvread(Chan *c, void *va, long n, vlong)
  228. {
  229. isdir(c);
  230. return devdirread(c, va, n, 0, 0, srvgen);
  231. }
  232. static long
  233. srvwrite(Chan *c, void *va, long n, vlong)
  234. {
  235. Srv *sp;
  236. Chan *c1;
  237. int fd;
  238. char buf[32];
  239. if(n >= sizeof buf)
  240. error(Egreg);
  241. memmove(buf, va, n); /* so we can NUL-terminate */
  242. buf[n] = 0;
  243. fd = strtoul(buf, 0, 0);
  244. c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */
  245. qlock(&srvlk);
  246. if(waserror()) {
  247. qunlock(&srvlk);
  248. cclose(c1);
  249. nexterror();
  250. }
  251. if(c1->flag & (CCEXEC|CRCLOSE))
  252. error("posted fd has remove-on-close or close-on-exec");
  253. if(c1->qid.type & QTAUTH)
  254. error("can't post auth file in srv");
  255. sp = srvlookup(nil, c->qid.path);
  256. if(sp == 0)
  257. error(Enonexist);
  258. if(sp->chan)
  259. error(Ebadusefd);
  260. sp->chan = c1;
  261. qunlock(&srvlk);
  262. poperror();
  263. return n;
  264. }
  265. Dev srvdevtab = {
  266. 's',
  267. "srv",
  268. devreset,
  269. srvinit,
  270. devshutdown,
  271. srvattach,
  272. srvwalk,
  273. srvstat,
  274. srvopen,
  275. srvcreate,
  276. srvclose,
  277. srvread,
  278. devbread,
  279. srvwrite,
  280. devbwrite,
  281. srvremove,
  282. srvwstat,
  283. };