Thread: [Libsysio-commit] namespace_assembly: libsysio/src init.c module.mk command.c parser.c
Brought to you by:
lward
|
From: Sonja T. <so...@us...> - 2004-01-30 21:56:03
|
Update of /cvsroot/libsysio/libsysio/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv25378/src Modified Files: Tag: namespace_assembly init.c module.mk Removed Files: Tag: namespace_assembly command.c parser.c Log Message: Cleaned up namespace_assembly code. Accepts commands with arbitrary ws in them. Also moved 'put' command to just be a part of the creat command Index: init.c =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/init.c,v retrieving revision 1.3.12.1 retrieving revision 1.3.12.2 diff -u -w -b -B -p -r1.3.12.1 -r1.3.12.2 --- init.c 28 Jan 2004 13:16:56 -0000 1.3.12.1 +++ init.c 30 Jan 2004 21:54:22 -0000 1.3.12.2 @@ -46,6 +46,9 @@ #include <sys/types.h> #include <sys/queue.h> +#include <sys/stat.h> +#include <fcntl.h> + #include "sysio.h" #include "inode.h" #include "mount.h" @@ -56,6 +59,25 @@ #include "stdfd.h" #endif +struct arg_list; + +struct arg_list { + char arg_name[4]; /* Argument specifier */ + char* arg; /* Arbitray length arg value*/ + struct arg_list *next; +}; + +/* Command structure (well, duh... */ +struct command_t { + char command[6]; + struct arg_list *args; +}; + +struct command_function_t { + char *cmd; + int (*func)(struct arg_list *args); +}; + /* * Sysio library initialization. Must be called before anything else in the * library. @@ -114,3 +136,670 @@ _sysio_shutdown() _sysio_unmount_all() == 0)) abort(); } + + +/* + * Determines if the ch character is in the string + * set. If it is, it returns the pos that it is + * in + */ +static int +in_set(char ch, const char *set) +{ + int i; + + if (set == NULL) + return -1; + + for (i=0; set[i] != '\0'; i++) + if (ch == set[i]) + return i; + + return -1; +} + +static int is_ws(char ch) +{ + if (ch == ' ' || ch == '\n' || ch == '\t') + return 1; + return 0; +} + +/* + * Not sure if I can rely on having strcpy, so just to + * be safe, I implemented my own + */ +static void +cpystr(char *dest, const char *src, int max_size) +{ + int i; + + for (i=0; i < max_size; i++) { + dest[i] = src[i]; + if (src[i] == '\0') + return; + } +} + +/* Returns length of string */ +static int +lenstr(char *str) +{ + int i; + + for (i=0; str[i] != '\0'; i++); + + return i; +} + +/* + * My own strcmp function. Since I am lazy, it returns a 0 if + * they match and a 1 otherwise + */ +static int +cmpstr(char *str1, char *str2) +{ + int i; + + for (i=0; *str1 != '\0' && *str2 != '\0'; i++) { + if (*str1 != *str2) + return 1; + *str1++; + *str2++; + } + /* Make sure they are the same size */ + if (*str1 == *str2) + return 0; + + return 1; +} + + +/* + * (kind of)Duplicates strtok function. + * + * Given a buffer, pulls off the longest string + * that does not contain any delim characters. Will + * remove ws and any characters in the ignore string. + * Returns the token. + * + */ +static char * +get_token(char **buf, const char *delim, const char *ignore) +{ + int i, j, size=0; + int in_quotes = 0; + char *token; + char *buf_ptr = *buf; + + if (buf_ptr == NULL) { + return NULL; + } + + if (*buf_ptr == '\0') + return NULL; + + /* Chop off any initial deliminators */ + while (buf_ptr && (in_set(*buf_ptr, delim)>=0)) + buf_ptr++; + + if (buf_ptr == NULL) + return NULL; + + + /* + * Find the first occurance of delim, recording how many + * characters lead up to it. Ignore ws characters. This + * is really inefficient. A better way to do it would be + * to copy the characters into the token buffer as the buf + * is processed, but there is no way of knowing how big the + * token will be, so the choices are to make some sort of guess + * at the size and clean up later or to make two passes + */ + for (i=0; + (buf_ptr && (buf_ptr[i] != '\0') && + (in_set(buf_ptr[i],delim) < 0)); + i++) { + if ((buf_ptr[i] == '"') && (in_set('"', ignore))<0) { + /* Allow escaping quotes */ + if ((i==0) || (buf_ptr[i-1] != '\\')) + in_quotes ^= 0x1; + } + + if ((in_quotes || !is_ws(buf_ptr[i])) && + (in_set(buf_ptr[i], ignore) < 0)) + size++; + } + + if ((token = malloc(size+1)) == NULL) + return NULL; + + in_quotes = 0; + for (i=0, j=0; + (buf_ptr && (buf_ptr[i] != '\0') && + (in_set(buf_ptr[i],delim) < 0)); + i++) { + if ((buf_ptr[i] == '"') && (in_set('"', ignore)<0)) { + /* Allow escaping quotes */ + if ((i==0) || (buf_ptr[i-1] != '\\')) + in_quotes ^= 0x1; + } + if ((in_quotes || !is_ws(buf_ptr[i])) && + (in_set(buf_ptr[i], ignore)< 0)){ + token[j] = buf_ptr[i]; + j++; + } + } + + token[j] = '\0'; + + if (buf_ptr) { + if ((*buf_ptr == '\0') || (*(buf_ptr+i) == '\0')) + buf_ptr = NULL; + else + buf_ptr += i+1; + } + + *buf = buf_ptr; + return token; +} + +/* + * Create an argument list for use in a command_t structure + */ +static struct arg_list * +get_args(char **buf) +{ + struct arg_list *new_list, *start_list; + struct arg_list *prev_list = NULL; + char *delim=",={"; + char *arg_name, *arg; + int pos,last_tok = 0; + + + if ((start_list = malloc(sizeof(struct arg_list))) == NULL) + return NULL; + + start_list->next = NULL; + new_list = start_list; + while(1) { + arg_name = get_token(buf, delim, "\\"); + + if (arg_name == NULL) { + return start_list; + } + + cpystr(new_list->arg_name, arg_name, 4); + + arg = get_token(buf, delim, "\\"); + if (arg == NULL) { + return NULL; + } + + /* See if we have arrived at the last token */ + if ((pos=in_set('}',arg)) >= 0) { + arg[pos] = '\0'; + last_tok = 1; + } + + new_list->arg = arg; + + if (new_list != start_list) { + prev_list->next = new_list; + } + + if (last_tok) + return start_list; + + prev_list = new_list; + if ((new_list = malloc(sizeof(struct arg_list))) == NULL) + return NULL; + new_list->next = NULL; + } + + return start_list; +} + + +/* + * Get a command. Fills in the cmd structure with a complete command + * Return 0 on successful completion, 1 if unable to get a token (due + * to a parsing error or to end of string), and -1 if some other problem + * occurs + */ +static int +get_command(char **commands_str, struct command_t *cmd) +{ + char *delim = "{},="; + char *cmd_str; + + if (cmd == NULL) { + return -1; + } + + /* Get the command name, removing any quotes */ + cmd_str = get_token(commands_str, delim, "\"\\"); + if (cmd_str == NULL) + return 1; + + /* + * Copy in the command. The command may be shorter + * than 6 chars, but it doesn't really matter since + * it is null-terminated + */ + cpystr(cmd->command, cmd_str, 6); + + /* + * Get all the arguments. If we fail here, we return -1 to indicate + * that this was not simply a matter of finishing processing the + * commands (since, if we have a cmd_str, we should have arguments) + */ + cmd->args = get_args(commands_str); + if (cmd->args == NULL) + return -1; + + return 0; +} + + +/* frees a command structure */ +static void +free_cmd(struct command_t *cmd) +{ + struct arg_list *curr_arg, *next_arg; + + curr_arg = cmd->args; + + while (curr_arg != NULL) { + next_arg = curr_arg->next; + free(curr_arg->arg); + free(curr_arg); + + curr_arg = next_arg; + } + + free(cmd); +} + +/* + * Given an argument name and a list of possible arg names, + * returns an index for the given argument name + */ +static int +get_arg(char *arg, char** prefix) +{ + int i; + + for (i=0; prefix[i] != NULL; i++) + if (!cmpstr(arg, prefix[i]) ) + return i; + + return -1; +} + +/* + * Takes a string with permission bits (in octal + * format) and returns the permission numbers + */ +static int +get_perms(char *perms) +{ + int total, i, j, digit; + char c[2]; + int len = lenstr(perms); + + total = 0; + for (i=0; i < len; i++) { + c[0] = perms[i]; + c[1] = '\0'; + digit = atoi(c); + if (digit > 7) { + return 0; + } + for (j=len-i-1; j >0; j--) + digit *= 8; + total += digit; + } + return total; +} + +/* + * Performs the creat command for the namespace assembly + */ +static int +do_creat(struct arg_list *args) +{ + struct arg_list *curr_arg = args; + char *tmp_str, *type=NULL; + char *prefixs[] = {"ft", "nm", "pm", "ow", "gr", "mm", "str", NULL }; + int argnum, perms=-1; + char *path=NULL, *own=NULL, *group=NULL; + int i, ret, maj_num=-1, min_num=-1; + char *maj_num_str; + char *min_num_str; + char *vals[10]; + int fd, size, num_vals=0; + + /* Needs to be at least one argument */ + if (args == NULL){ + return EINVAL; + } + + while (curr_arg != NULL) { + + if ((argnum =get_arg(curr_arg->arg_name, prefixs)) < 0) + return EINVAL; + + tmp_str = curr_arg->arg; + + if (tmp_str == NULL) { + return EINVAL; + } + switch (argnum) { + case 0: + type = tmp_str; + break; + + case 1: + path = tmp_str; + break; + + case 2: + + perms = get_perms(tmp_str); + break; + + case 3: + own = tmp_str; + break; + + case 4: + group = tmp_str; + break; + + case 5: + maj_num_str = get_token(&tmp_str, "+", NULL); + min_num_str = get_token(&tmp_str, "+", NULL); + + maj_num = atoi(maj_num_str); + min_num = atoi(min_num_str); + + free(maj_num_str); + free(min_num_str); + break; + + case 6: + /* + * Put the given string into the given file + */ + if (num_vals >= 9) { + /* Too many strings */ + return EINVAL; + } + + /* + * Remove the surronding quotes from tmp_str + * It is done here instead of in get_token because + * it is not a behavior wanted for any other + * token + */ + tmp_str++; + size = lenstr(tmp_str); + tmp_str[size-1] = '\0'; + vals[num_vals++] = tmp_str; + break; + + default: + return EINVAL; + + } + curr_arg = curr_arg->next; + } + + if ((type == NULL) || (perms == -1) || (path == NULL)) { + return EINVAL; + } + + ret = 0; + if (cmpstr(type, "dir") == 0) { + ret = mkdir(path, perms); + } else if ((cmpstr(type, "chr") == 0) || (cmpstr(type, "blk") == 0)) { + int mode; + int devnum = SYSIO_MKDEV(maj_num, min_num); + + if (cmpstr(type, "chr") == 0) + mode = perms | S_IFCHR; + else + mode = perms | S_IFBLK; + + if ((maj_num == -1) || (min_num == -1)) { + return EINVAL; + } + ret = mknod(path, mode, devnum); + + } else if (cmpstr(type, "file") == 0) { + fd = creat(path, perms); + + if (fd < 0) + return fd; + + for (i=0; i < num_vals; i++) { + size = lenstr(vals[i]); + if ((ret = write(fd, vals[i], size)) != size) + return -1; + } + ret = close(fd); + + } else { + return EINVAL; + } + return 0; +} + +static int +do_mnt(struct arg_list *args) +{ + int argnum, flags = 0; + int err, is_root =0; /* Are we mounting the root dir? */ + char *src=NULL, *to=NULL; + char *tmp_str, *data=NULL; + char *fstype; + char *prefixs[] = { "dev", "dir", "fl", "da", NULL}; + struct arg_list *curr_arg = args; + + /* Needs to be at least one argument */ + if (args == NULL){ + return EINVAL; + } + + while (curr_arg != NULL) { + + if ((argnum =get_arg(curr_arg->arg_name, prefixs)) < 0) + return EINVAL; + tmp_str = curr_arg->arg; + + if (tmp_str == NULL) { + return EINVAL; + } + + switch (argnum) { + case 0 : + + fstype = get_token(&tmp_str, ":", NULL); + src = get_token(&tmp_str, ":", "\""); + + break; + + case 1: + to = tmp_str; + if (cmpstr(to,"/") == 0) + is_root = 1; + break; + + case 2: + flags = atoi(tmp_str); + break; + + case 3: + data = tmp_str; + break; + } + curr_arg = curr_arg->next; + } + + if ((src == NULL) || (to == NULL)) { + return EINVAL; + } + + if (is_root) { + err = _sysio_mount_root(src, fstype, flags, data); + free(src); + return -err; + } else { + err = mount(src, to, fstype, flags, data); + free(src); + return -err; + } + + return 0; + +} + + +static int +do_cd(struct arg_list *args) +{ + char *path; + + /* Must be exactly one argument */ + if ((args == NULL) || (args->next != NULL)) { + return EINVAL; + } + + if (cmpstr(args->arg_name, "dir") != 0) + return EINVAL; + + path = args->arg; + + if (path == NULL) { + return EINVAL; + } + return chdir(path); +} + + +/* Does a chmod */ +static int +do_chmod(struct arg_list *args) +{ + + char *prefixs[] = {"src", "pm", NULL}; + struct arg_list *curr_arg = args; + char *src; + char *tmp_str = NULL; + int argnum, perms; + + + /* Need both the filename and the permissions */ + if ((args == NULL) || (args->next == NULL)) { + return EINVAL; + } + + + while (curr_arg != NULL) { + + argnum = get_arg(curr_arg->arg_name, prefixs); + if (argnum < 0) + return EINVAL; + + tmp_str = curr_arg->arg; + if (tmp_str == NULL) { + return EINVAL; + } + + switch (argnum) { + case 0 : + src = tmp_str; + break; + + case 1: + perms = get_perms(tmp_str); + break; + + case 2: + + errno = EINVAL; + return EINVAL; + break; + } + curr_arg = curr_arg->next; + } + + + return chmod(src, perms); +} + +struct command_function_t cmd_funcs[] = { + {"creat", do_creat}, + {"mnt", do_mnt}, + {"cd", do_cd}, + {"chmd", do_chmod}, + {NULL, NULL} +}; + + +/* Execute the given cmd. Return exit status code */ +static int +do_command(struct command_t *cmd) +{ + int i; + + if (cmd->command == NULL) + return EINVAL; + + for (i=0; cmd_funcs[i].cmd != NULL; i++) { + + if (cmpstr(cmd_funcs[i].cmd, cmd->command) == 0) + return (cmd_funcs[i].func)(cmd->args); + } + + return EINVAL; +} + +/* + * Given a command sequence buffer, parse it and run the given + * commands + */ + +int +run_cmds(char *buf) +{ + struct command_t *cmd; + int err; + + while (1) { + + if ((cmd = (struct command_t *)malloc(sizeof(struct command_t))) + == NULL) + return ENOMEM; + + cmd->args = NULL; + + err= get_command(&buf, cmd); + if ((cmd == NULL) || (err < 0)) + return EINVAL; + + if (err == 1) + return 0; + + if ((err = do_command(cmd)) < 0) { + free_cmd(cmd); + /* Something screwed up, bail */ + return err; + } + free_cmd(cmd); + } + return 0; +} + + Index: module.mk =================================================================== RCS file: /cvsroot/libsysio/libsysio/src/module.mk,v retrieving revision 1.1.2.1 retrieving revision 1.1.2.2 diff -u -w -b -B -p -r1.1.2.1 -r1.1.2.2 --- module.mk 18 Dec 2003 18:44:02 -0000 1.1.2.1 +++ module.mk 30 Jan 2004 21:54:22 -0000 1.1.2.2 @@ -9,5 +9,5 @@ SRCDIR_SRCS = src/access.c src/chdir.c s src/rmdir.c src/stat64.c src/stat.c \ src/statvfs64.c src/statvfs.c src/symlink.c \ src/truncate.c src/unlink.c src/utime.c \ - src/write.c src/parser.c src/command.c + src/write.c SRCDIR_EXTRA = src/module.mk --- command.c DELETED --- --- parser.c DELETED --- |