devsrv.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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)+strlen(name)+1);
  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. sp->name = (char*)(sp+1);
  140. strcpy(sp->name, name);
  141. c->qid.type = QTFILE;
  142. c->qid.path = sp->path;
  143. srv = sp;
  144. qunlock(&srvlk);
  145. poperror();
  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. /*
  171. * Only eve can remove system services.
  172. * No one can remove #s/boot.
  173. */
  174. if(strcmp(sp->owner, eve) == 0 && !iseve())
  175. error(Eperm);
  176. if(strcmp(sp->name, "boot") == 0)
  177. error(Eperm);
  178. /*
  179. * No removing personal services.
  180. */
  181. if((sp->perm&7) != 7 && strcmp(sp->owner, up->user) && !iseve())
  182. error(Eperm);
  183. *l = sp->link;
  184. qunlock(&srvlk);
  185. poperror();
  186. if(sp->chan)
  187. cclose(sp->chan);
  188. free(sp);
  189. }
  190. static int
  191. srvwstat(Chan *c, uchar *dp, int n)
  192. {
  193. Dir d;
  194. Srv *sp;
  195. if(c->qid.type & QTDIR)
  196. error(Eperm);
  197. qlock(&srvlk);
  198. if(waserror()){
  199. qunlock(&srvlk);
  200. nexterror();
  201. }
  202. sp = srvlookup(nil, c->qid.path);
  203. if(sp == 0)
  204. error(Enonexist);
  205. if(strcmp(sp->owner, up->user) && !iseve())
  206. error(Eperm);
  207. n = convM2D(dp, n, &d, nil);
  208. if(n == 0)
  209. error (Eshortstat);
  210. if(d.mode != ~0UL)
  211. sp->perm = d.mode & 0777;
  212. if(d.uid && *d.uid)
  213. kstrdup(&sp->owner, d.uid);
  214. qunlock(&srvlk);
  215. poperror();
  216. return n;
  217. }
  218. static void
  219. srvclose(Chan *c)
  220. {
  221. /*
  222. * in theory we need to override any changes in removability
  223. * since open, but since all that's checked is the owner,
  224. * which is immutable, all is well.
  225. */
  226. if(c->flag & CRCLOSE){
  227. if(waserror())
  228. return;
  229. srvremove(c);
  230. poperror();
  231. }
  232. }
  233. static long
  234. srvread(Chan *c, void *va, long n, vlong)
  235. {
  236. isdir(c);
  237. return devdirread(c, va, n, 0, 0, srvgen);
  238. }
  239. static long
  240. srvwrite(Chan *c, void *va, long n, vlong)
  241. {
  242. Srv *sp;
  243. Chan *c1;
  244. int fd;
  245. char buf[32];
  246. if(n >= sizeof buf)
  247. error(Egreg);
  248. memmove(buf, va, n); /* so we can NUL-terminate */
  249. buf[n] = 0;
  250. fd = strtoul(buf, 0, 0);
  251. c1 = fdtochan(fd, -1, 0, 1); /* error check and inc ref */
  252. qlock(&srvlk);
  253. if(waserror()) {
  254. qunlock(&srvlk);
  255. cclose(c1);
  256. nexterror();
  257. }
  258. if(c1->flag & (CCEXEC|CRCLOSE))
  259. error("posted fd has remove-on-close or close-on-exec");
  260. if(c1->qid.type & QTAUTH)
  261. error("cannot post auth file in srv");
  262. sp = srvlookup(nil, c->qid.path);
  263. if(sp == 0)
  264. error(Enonexist);
  265. if(sp->chan)
  266. error(Ebadusefd);
  267. sp->chan = c1;
  268. qunlock(&srvlk);
  269. poperror();
  270. return n;
  271. }
  272. Dev srvdevtab = {
  273. 's',
  274. "srv",
  275. devreset,
  276. srvinit,
  277. devshutdown,
  278. srvattach,
  279. srvwalk,
  280. srvstat,
  281. srvopen,
  282. srvcreate,
  283. srvclose,
  284. srvread,
  285. devbread,
  286. srvwrite,
  287. devbwrite,
  288. srvremove,
  289. srvwstat,
  290. };