dlang.c (6880B)
1 #include <os9/os9.h> 2 3 #include <libk.h> 4 5 #include <ctype.h> 6 #include <errno.h> 7 #include <setjmp.h> 8 #include <stdarg.h> 9 #include <stdlib.h> 10 #include <string.h> 11 12 #define PREFIX "> " 13 #define PREFIX2 "# " 14 #define NR_ARGC_MAX 5 15 16 struct args { 17 char *argv[NR_ARGC_MAX]; 18 int argc; 19 int status; 20 }; 21 22 struct cmd { 23 char *name; 24 char *helpmsg; 25 int (*eval)(const struct cmd *, struct args *); 26 unsigned char min; 27 unsigned char max; 28 }; 29 30 unsigned in_debug; 31 jmp_buf dbgrecover; 32 33 static const struct cmd cmds[]; 34 35 static void 36 error(char *fmt, ...) 37 { 38 va_list va; 39 40 va_start(va, fmt); 41 kprint(PREFIX "ERR "); 42 kvprint(fmt, va); 43 kprint("\n"); 44 longjmp(dbgrecover, 1); 45 } 46 47 static void 48 ready(void) 49 { 50 kprint(PREFIX "READY\n"); 51 } 52 53 /* Get cmd struct for named cmd */ 54 static const struct cmd * 55 get_cmd(char *name) 56 { 57 const struct cmd *cmd; 58 59 for (cmd = cmds; cmd->name; cmd++) { 60 if (strcmp(cmd->name, name) == 0) 61 return cmd; 62 } 63 return NULL; 64 } 65 66 static int 67 do_exit(const struct cmd *cmd, struct args *args) 68 { 69 args->status = 0; 70 if (args->argc == 2) 71 args->status = atoi(args->argv[1]); 72 return -1; 73 } 74 75 static int 76 do_help(const struct cmd *cmd, struct args *args) 77 { 78 for (cmd = cmds; cmd->name; cmd++) { 79 char *s = cmd->helpmsg; 80 kprint(PREFIX2 "%s\n", s); 81 } 82 return 0; 83 } 84 85 static int 86 do_read(const struct cmd *cmd, struct args *args) 87 { 88 int n, ch; 89 Chan *c; 90 char buf[100], *bp; 91 92 if ((c = namec(args->argv[1], O_READ)) == NULL) 93 goto err; 94 95 ch = -1; 96 kprint(PREFIX2); 97 while ((n = chanread(c, buf, sizeof(buf))) > 0) { 98 for (bp = buf; bp < &buf[n]; bp++) { 99 if (ch == '\n') 100 kprint(PREFIX2); 101 ch = *bp; 102 kprint("%c", ch); 103 } 104 } 105 if (ch != '\n') 106 kprint("\n"); 107 108 if (chanclose(c) < 0 || n < 0) 109 goto err; 110 111 return 0; 112 113 err: 114 kprint(PREFIX "ERR read: %e\n"); 115 return 0; 116 } 117 118 static int 119 do_ls(const struct cmd *cmd, struct args *args) 120 { 121 int n; 122 Chan *c; 123 Dir dentry; 124 unsigned char buf[DIRLEN]; 125 126 if ((c = namec(args->argv[1], O_READ)) == NULL) 127 goto err; 128 129 while ((n = chanread(c, buf, DIRLEN)) > 0) { 130 if (p9todir(&dentry, buf, n) < 0) 131 goto err; 132 kprint(PREFIX2 "%s\n", dentry.name); 133 } 134 135 if (chanclose(c) || n < 0) 136 goto err; 137 138 return 0; 139 140 err: 141 kprint(PREFIX "ERR ls:%e\n"); 142 return 0; 143 } 144 145 static int 146 do_write(const struct cmd *cmd, struct args *args) 147 { 148 int i, len, offset, n; 149 Chan *c; 150 char *s, buffer[LINELEN]; 151 152 if ((c = namec(args->argv[1], O_WRITE)) == NULL) 153 goto err; 154 155 offset = 0; 156 for (i = 2; i < args->argc; i++) { 157 s = args->argv[i]; 158 len = strlen(s); 159 if (len + offset >= LINELEN-2) 160 error("line too long"); 161 memcpy(buffer + offset, s, len); 162 offset += len; 163 buffer[offset++] = ' '; 164 } 165 buffer[offset] = '\n'; 166 n = chanwrite(c, buffer, offset); 167 168 if (chanclose(c) < 0 || n < 0) 169 goto err; 170 171 return 0; 172 err: 173 kprint(PREFIX "ERR write:%e\n"); 174 return 0; 175 } 176 177 static int 178 do_stat(const struct cmd *cmd, struct args *args) 179 { 180 Dir dir; 181 182 if (dirstat(args->argv[1], &dir) < 0) 183 goto err; 184 kprint(PREFIX2 "name: %s\n" 185 PREFIX2 "length: %ld\n" 186 PREFIX2 "mode: %x\n" 187 PREFIX2 "type: %d\n" 188 PREFIX2 "dev: %d\n" 189 PREFIX2 "qid: %x,%lx,%llx\n", 190 dir.name, 191 dir.length, 192 dir.mode, 193 dir.type, 194 dir.dev, 195 dir.qid.type, dir.qid.vers, dir.qid.path); 196 197 return 0; 198 199 err: 200 kprint(PREFIX "ERR stat:%e\n"); 201 return 0; 202 } 203 204 static int 205 do_bind(const struct cmd *cmd, struct args *args) 206 { 207 if (bind(args->argv[1], args->argv[2]) < 0) 208 kprint(PREFIX "ERR bind:%e\n"); 209 return 0; 210 } 211 212 static int 213 do_mount(const struct cmd *cmd, struct args *args) 214 { 215 if (mount(args->argv[1], args->argv[2], args->argv[3]) < 0) 216 kprint(PREFIX "ERR mount:%e\n"); 217 return 0; 218 } 219 220 static int 221 do_x(const struct cmd *cmd, struct args *args) 222 { 223 char *p, *s; 224 int n; 225 void *addr; 226 size_t len; 227 uint16_t *u16; 228 uint32_t *u32; 229 uint64_t *u64; 230 231 s = args->argv[1]; 232 if ((p = strchr(s, '/')) == NULL) 233 goto badfmt; 234 *p++ = '\0'; 235 236 addr = (void *) strtoll(s, NULL, 0); 237 n = atoi(p); 238 if (n == 0) 239 n = 1; 240 241 len = strspn(p, "0123456789"); 242 switch (p[len]) { 243 case 'x': 244 u16 = addr; 245 while (n-- > 0) 246 kprint(PREFIX2 "%x\n", (int) *u16++); 247 return 0; 248 case 'X': 249 u32 = addr; 250 while (n-- > 0) 251 kprint(PREFIX2 "%lx\n", (long) *u32++); 252 return 0; 253 case 'Y': 254 u64 = addr; 255 while (n-- > 0) 256 kprint(PREFIX2 "%x\n", (long long) *u64++); 257 return 0; 258 default: 259 goto badfmt; 260 } 261 262 badfmt: 263 kprint(PREFIX "ERR x: bad format\n"); 264 return 0; 265 } 266 267 static const struct cmd * 268 parse_cmd(char *buf, struct args *args) 269 { 270 char *p; 271 const struct cmd *cmd; 272 const static char ws[] = " \t\r"; 273 274 args->argc = 0; 275 for (p = strtok(buf, ws); p; p = strtok(NULL, ws)) { 276 if (args->argc == NR_ARGC_MAX) 277 error("too many parameters"); 278 args->argv[args->argc++] = p; 279 } 280 281 if (args->argc == 0) 282 return NULL; 283 284 if ((cmd = get_cmd(args->argv[0])) == NULL) 285 error("%s: not found", args->argv[0]); 286 287 return cmd; 288 } 289 290 static int 291 run(struct args *args) 292 { 293 const struct cmd *cmd; 294 size_t len; 295 char buffer[LINELEN]; 296 297 if (kgets(buffer, sizeof(buffer)) == NULL) { 298 args->status = 1; 299 return -1; 300 } 301 302 if ((len = strlen(buffer)) != 0) { 303 if (buffer[len-1] != '\n') 304 error("line too long"); 305 buffer[len-1] = '\0'; 306 cmd = parse_cmd(buffer, args); 307 if (cmd) { 308 int (*fn)(const struct cmd *, struct args *); 309 void *bp; 310 311 if (args->argc < cmd->min || args->argc > cmd->max) 312 error(cmd->helpmsg); 313 bp = cmd->eval; 314 fn = (int (*)(const struct cmd *, struct args *)) bp; 315 return (*fn)(cmd, args); 316 } 317 } 318 319 return 0; 320 } 321 322 int 323 debug(void) 324 { 325 struct args args; 326 327 kprint("begin debug language interface\n"); 328 in_debug = 1; 329 setjmp(dbgrecover); 330 331 for (ready(); !run(&args); ready()) 332 ; 333 kprint("end debug language interface\n"); 334 in_debug = 0; 335 336 return args.status; 337 } 338 339 /* 340 * definition of arrays 341 */ 342 static const struct cmd cmds[] = { 343 { 344 .name = "exit", 345 .eval = do_exit, 346 .min = 1, 347 .max = 2, 348 .helpmsg = "Exit debug environment: exit [status]", 349 }, 350 { 351 .name = "help", 352 .eval = do_help, 353 .min = 1, 354 .max = 1, 355 .helpmsg = "Print this help menu: help", 356 }, 357 { 358 .name = "ls", 359 .eval = do_ls, 360 .min = 2, 361 .max = 2, 362 .helpmsg = "List content of a directory: ls path", 363 }, 364 { 365 .name = "read", 366 .eval = do_read, 367 .min = 2, 368 .max = 2, 369 .helpmsg = "Read content from a file: read path", 370 }, 371 { 372 .name = "write", 373 .eval = do_write, 374 .min = 3, 375 .max = NR_ARGC_MAX, 376 .helpmsg = "Write content to a file: write path string ...", 377 }, 378 { 379 .name = "stat", 380 .eval = do_stat, 381 .min = 2, 382 .max = 2, 383 .helpmsg = "Display stat attribute: stat path", 384 }, 385 { 386 .name = "bind", 387 .eval = do_bind, 388 .min = 3, 389 .max = 3, 390 .helpmsg = "bind one directory in other: bind from to", 391 }, 392 { 393 .name = "mount", 394 .eval = do_mount, 395 .min = 4, 396 .max = 4, 397 .helpmsg = "mount one directory in other: mount from to spec", 398 }, 399 { 400 .name = "x", 401 .eval = do_x, 402 .min = 2, 403 .max = 2, 404 .helpmsg = "Examine memory: x addr/fmt", 405 }, 406 { 407 .name = NULL 408 } 409 };