Initial cut at srv device
[akaros.git] / kern / drivers / dev / srv.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 enum {
17         Qtopdir = 1,
18 };
19
20 struct SrvFile {
21         char *name;
22         char *user;
23         uint32_t perm;
24         struct qid qid;
25         /* set to 1 on create; only decremented
26          * by remove.
27          */
28         struct kref ref;
29         struct chan *chan;
30         /* set to 1 on create;
31          * hence will never go to 0
32          * but can be handily used
33          * for exclusive open.*/
34         struct kref opens;
35         struct SrvFile *entry;
36         int length;
37 };
38
39 static int
40 srvgen(struct chan *c, char *name,
41            struct dirtab *tab, int ntab, int s, struct dir *dp)
42 {
43         struct SrvFile *f;
44
45         if (s == DEVDOTDOT) {
46                 devdir(c, c->qid, "#s", 0, eve, 0555, dp);
47                 return 1;
48         }
49         f = c->aux;
50         if ((c->qid.type & QTDIR) == 0) {
51                 if (s > 0)
52                         return -1;
53                 devdir(c, f->qid, f->name, f->length, f->user, f->perm, dp);
54                 return 1;
55         }
56
57         for (f = f->entry; f != NULL; f = f->entry) {
58                 if (s-- == 0)
59                         break;
60         }
61         if (f == NULL)
62                 return -1;
63
64         devdir(c, f->qid, f->name, f->length, f->user, f->perm, dp);
65         return 1;
66 }
67
68 static void srvinit(void)
69 {
70 }
71
72 static int srvcanattach(struct SrvFile * d)
73 {
74         if (strcmp(d->user, current->user) == 0)
75                 return 1;
76
77         /*
78          * Need write permission in other to allow attaches if
79          * we are not the owner
80          */
81         if (d->perm & 2)
82                 return 1;
83
84         return 0;
85 }
86
87 static struct chan *srvattach(char *spec)
88 {
89         /* the inferno attach was pretty complicated, but
90          * we're not sure that complexity is needed.
91          * Assume not. */
92         struct chan *c = devattach('s', spec);
93         mkqid(&c->qid, Qtopdir, 0, QTDIR);
94         return c;
95 }
96
97 static struct walkqid *srvwalk(struct chan *c, struct chan *nc, char **name,
98                                                            int nname)
99 {
100         return devwalk(c, nc, name, nname, 0, 0, srvgen);
101 }
102
103 static int srvstat(struct chan *c, uint8_t * db, int n)
104 {
105         n = devstat(c, db, n, 0, 0, srvgen);
106         return n;
107 }
108
109 static void srvputdir(struct SrvFile * dir)
110 {
111         kfree(dir->user);
112         kfree(dir->name);
113         kfree(dir);
114 }
115
116 static void srv_release(struct kref *kref)
117 {
118         struct SrvFile *f = container_of(kref, struct SrvFile, ref);
119         srvputdir(f);
120 }
121
122 static struct chan *srvopen(struct chan *c, int omode)
123 {
124         ERRSTACK(2);
125         struct SrvFile *sf;
126 /* NEEDS TO RETURN SP->CHAN */
127         openmode(omode);        /* check it */
128         if (c->qid.type & QTDIR) {
129                 if (omode != OREAD)
130                         error(Eisdir);
131                 c->mode = omode;
132                 c->flag |= COPEN;
133                 c->offset = 0;
134                 return c;
135         }
136
137         sf = c->aux;
138
139         devpermcheck(sf->user, sf->perm, omode);
140         /* do we have ORCLOSE yet?
141         if (omode & ORCLOSE && strcmp(sf->user, up->env->user) != 0)
142                 error(Eperm);
143         if (sf->perm & DMEXCL && sf->opens != 0)
144                 error(Einuse);
145         */
146         kref_init(&sf->opens, fake_release, 1);
147         kref_init(&sf->ref, srv_release, 1);
148         /*      if (omode & ORCLOSE)
149          *              sf->flags |= SORCLOSE;
150          */
151         c->offset = 0;
152         c->flag |= COPEN;
153         c->mode = openmode(omode);
154
155         return c;
156 }
157
158 static int srvwstat(struct chan *c, uint8_t * dp, int n)
159 {
160         /* some other time. */
161         error(Eperm);
162         return -1;
163 }
164
165 static void srvclose(struct chan *c)
166 {
167         struct SrvFile *s = c->aux;
168         kref_put(&s->opens);
169 }
170
171 static void srvremove(struct chan *c)
172 {
173         struct SrvFile *s = c->aux;
174         kref_put(&s->ref);
175 }
176
177 /* N.B. srvopen gives the chan back. The only 'reading' we do
178  * in srv is of the top level directory.
179  */
180 static long srvread(struct chan *c, void *va, long count, int64_t offset)
181 {
182         return devdirread(c, va, count, 0, 0, srvgen);
183 }
184
185 static long srvwrite(struct chan *c, void *va, long count, int64_t offset)
186 {
187         /* basic operation. 
188          * Verify the srv entry is there.
189          * Lock it.
190          * get the string from the va.
191          * It is an integer fd, so get the
192          * chan for the fd. 
193          * Set the srv chan to that chan
194          * (if it's not set. If it is, that's bad.)
195          * That that fdtochan increments the ref, so
196          * no need to do that.
197          */
198 #if 0
199         if (c->qid.type & QTDIR)
200                 error(Eperm);
201
202         sp = c->aux;
203 #endif
204         error("srvwrite: notyet");
205         return -1;
206 }
207
208 struct dev srvdevtab = {
209         's',
210         "srv",
211
212         devreset,
213         srvinit,
214         devshutdown,
215         srvattach,
216         srvwalk,
217         srvstat,
218         srvopen,
219         devcreate,
220         srvclose,
221         srvread,
222         devbread,
223         srvwrite,
224         devbwrite,
225         srvremove,
226         srvwstat
227 };