regress: use parsecmd() instead of strncmp on user pointers
[akaros.git] / kern / drivers / dev / regress.c
1 /*
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9
10 // regression device.
11 // Currently, has only one file, monitor, which is used to send
12 // commands to the monitor.
13 // TODO: read them back :-)
14
15 #include <slab.h>
16 #include <kmalloc.h>
17 #include <kref.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <assert.h>
21 #include <error.h>
22 #include <cpio.h>
23 #include <pmap.h>
24 #include <smp.h>
25 #include <net/ip.h>
26 #include <monitor.h>
27 #include <ktest.h>
28
29 struct dev regressdevtab;
30
31 static char *devname(void)
32 {
33         return regressdevtab.name;
34 }
35
36 struct regress
37 {
38         spinlock_t lock;
39         struct queue *monitor;
40 };
41 struct regress regress;
42
43 enum{
44         Monitordirqid = 0,
45         Monitordataqid,
46         Monitorctlqid,
47 };
48
49 struct dirtab regresstab[]={
50         {".",           {Monitordirqid, 0, QTDIR},      0,      DMDIR|0550},
51         {"mondata",     {Monitordataqid},               0,      0600},
52         {"monctl",      {Monitorctlqid},                0,      0600},
53 };
54
55 static char *ctlcommands = "ktest";
56
57 static struct chan *regressattach(char *spec)
58 {
59         uint32_t n;
60
61         regress.monitor = qopen(2 << 20, 0, 0, 0);
62         if (! regress.monitor) {
63                 printk("monitor allocate failed. No monitor output\n");
64         }
65         return devattach(devname(), spec);
66 }
67
68 static void regressinit(void)
69 {
70 }
71
72 static struct walkqid *regresswalk(struct chan *c, struct chan *nc, char **name,
73                                    unsigned int nname)
74 {
75         return devwalk(c, nc, name, nname, regresstab, ARRAY_SIZE(regresstab),
76                        devgen);
77 }
78
79 static size_t regressstat(struct chan *c, uint8_t *db, size_t n)
80 {
81         if (regress.monitor)
82                 regresstab[Monitordataqid].length = qlen(regress.monitor);
83         else
84                 regresstab[Monitordataqid].length = 0;
85
86         return devstat(c, db, n, regresstab, ARRAY_SIZE(regresstab), devgen);
87 }
88
89 static struct chan *regressopen(struct chan *c, int omode)
90 {
91         if (c->qid.type & QTDIR) {
92                 if (openmode(omode) != O_READ)
93                         error(EPERM, ERROR_FIXME);
94         }
95         c->mode = openmode(omode);
96         c->flag |= COPEN;
97         c->offset = 0;
98         return c;
99 }
100
101 static void regressclose(struct chan *unused)
102 {
103 }
104
105 static size_t regressread(struct chan *c, void *va, size_t n, off64_t off)
106 {
107         uint64_t w, *bp;
108         char *a, *ea;
109         uintptr_t offset = off;
110         uint64_t pc;
111         int snp_ret, ret = 0;
112
113         switch((int)c->qid.path){
114         case Monitordirqid:
115                 n = devdirread(c, va, n, regresstab, ARRAY_SIZE(regresstab),
116                                devgen);
117                 break;
118
119         case Monitorctlqid:
120                 n = readstr(off, va, n, ctlcommands);
121                 break;
122
123         case Monitordataqid:
124                 if (regress.monitor) {
125                         printd("monitordataqid: regress.monitor %p len %p\n",
126                                regress.monitor, qlen(kprof.monitor));
127                         if (qlen(regress.monitor) > 0)
128                                 n = qread(regress.monitor, va, n);
129                         else
130                                 n = 0;
131                 } else
132                         error(EFAIL, "no monitor queue");
133                 break;
134         default:
135                 n = 0;
136                 break;
137         }
138         return n;
139 }
140
141 static size_t regresswrite(struct chan *c, void *a, size_t n, off64_t unused)
142 {
143         ERRSTACK(1);
144         uintptr_t pc;
145         struct cmdbuf *cb;
146         cb = parsecmd(a, n);
147
148         if (waserror()) {
149                 kfree(cb);
150                 nexterror();
151         }
152
153         switch ((int)(c->qid.path)) {
154         case Monitorctlqid:
155                 if (cb->nf < 1)
156                         error(EFAIL, "%s no command, need %s", __func__,
157                               ctlcommands);
158                 if (!strcmp(cb->f[0], "ktest")) {
159                         run_registered_ktest_suites();
160                 } else {
161                         error(EFAIL, "regresswrite: only commands are %s",
162                               ctlcommands);
163                 }
164                 break;
165
166         case Monitordataqid:
167                 if (onecmd(cb->nf, cb->f, NULL) < 0)
168                         n = -1;
169                 break;
170         default:
171                 error(EBADFD, ERROR_FIXME);
172         }
173         kfree(cb);
174         poperror();
175         return n;
176 }
177
178 struct dev regressdevtab __devtab = {
179         .name = "regress",
180
181         .reset = devreset,
182         .init = regressinit,
183         .shutdown = devshutdown,
184         .attach = regressattach,
185         .walk = regresswalk,
186         .stat = regressstat,
187         .open = regressopen,
188         .create = devcreate,
189         .close = regressclose,
190         .read = regressread,
191         .bread = devbread,
192         .write = regresswrite,
193         .bwrite = devbwrite,
194         .remove = devremove,
195         .wstat = devwstat,
196 };