qio: Do not kick when calling qdiscard()
[akaros.git] / kern / src / ns / util.c
1 /* misc utilities for plan9 */
2
3 #include <ns.h>
4 #include <string.h>
5 #include <err.h>
6 #include <syscall.h>
7
8 /* Copies n bytes from mem + offset into buf, similar to a read() call. */
9 int readmem(unsigned long offset, char *buf, unsigned long n,
10                         void *mem, size_t mem_len)
11 {
12         if (offset >= mem_len)
13                 return 0;
14         if (offset + n > mem_len)
15                 n = mem_len - offset;
16         memmove(buf, mem + offset, n);
17         return n;
18 }
19
20 /* Read a num/string to user mode, accounting for offset.  Not a huge fan of the
21  * 'size' parameter (the old plan9 users just picked NUMSIZE (12), though they
22  * seem to want to limit it).  */
23 static int __readnum(unsigned long off, char *buf, unsigned long n,
24                      unsigned long val, size_t size, const char *fmt)
25 {
26         char tmp[64];
27         size = MIN(sizeof(tmp), size);
28         /* we really need the %* format. */
29         size = snprintf(tmp, size, fmt, val);
30         /* size is now strlen, so the rest of this is just like readstr. */
31         /* always include the \0 */
32         return readmem(off, buf, n, tmp, size + 1);
33 }
34
35 int readnum(unsigned long off, char *buf, unsigned long n, unsigned long val,
36             size_t size)
37 {
38         return __readnum(off, buf, n, val, size, "%lu");
39 }
40
41 int readnum_hex(unsigned long off, char *buf, unsigned long n,
42                 unsigned long val, size_t size)
43 {
44         return __readnum(off, buf, n, val, size, "0x%lx");
45 }
46
47 int readstr(unsigned long offset, char *buf, unsigned long n, char *str)
48 {
49         /* always include the \0 */
50         return readmem(offset, buf, n, str, strlen(str) + 1);
51 }
52
53 /* Helper: extracts a long from a user buffer (in text). */
54 unsigned long strtoul_from_ubuf(void *ubuf, size_t count, int base)
55 {
56         char num64[NUMSIZE64];
57
58         /* want to give strtoul a null-terminated buf (can't handle random
59          * user strings) */
60         if (count > sizeof(num64)) {
61                 set_errno(EINVAL);
62                 error(EFAIL, "attempted to write %d chars, max %d", count,
63                           sizeof(num64));
64         }
65         memcpy(num64, ubuf, count);
66         num64[count] = 0;       /* enforce trailing 0 */
67         return strtoul(num64, 0, base);
68 }
69
70 /* Converts open mode flags, e.g. O_RDWR, to a rwx------ value, e.g. S_IRUSR */
71 int omode_to_rwx(int open_flags)
72 {
73         static int rwx_opts[] = { [O_RDWR | O_EXEC] = 0700,
74                                   [O_RDWR] = 0600,
75                                   [O_READ | O_EXEC] = 0500,
76                                   [O_READ] = 0400,
77                                   [O_WRITE | O_EXEC] = 0300,
78                                   [O_WRITE] = 0200,
79                                   [O_EXEC] = 0100 };
80         return rwx_opts[open_flags & O_ACCMODE];
81 }
82
83 /* Converts open mode flags related to permissions, e.g. O_RDWR, to 9p.  It's a
84  * bit ugly, since 9p (according to http://man.cat-v.org/plan_9/5/open) seems to
85  * require that O_EXEC is mutually exclusive with the others.  If someone on
86  * Akaros wants EXEC, we'll just substitute READ. */
87 int omode_to_9p_accmode(int open_flags)
88 {
89         static int acc_opts[] = { [O_RDWR | O_EXEC] = 2,
90                                   [O_WRITE | O_EXEC] = 2,
91                                   [O_READ | O_EXEC] = 0,
92                                   [O_EXEC] = 0,
93                                   [O_RDWR] = 2,
94                                   [O_WRITE] = 1,
95                                   [O_READ] = 0,
96                                   [0] = 0 /* we can't express no permissions */
97                                   };
98         return acc_opts[open_flags & O_ACCMODE];
99 }