📄 init_parse.c
字号:
static int ctl_match(snd_ctl_elem_id_t *pattern, snd_ctl_elem_id_t *id){ if (snd_ctl_elem_id_get_interface(pattern) != -1 && snd_ctl_elem_id_get_interface(pattern) != snd_ctl_elem_id_get_interface(id)) return 0; if (snd_ctl_elem_id_get_device(pattern) != -1 && snd_ctl_elem_id_get_device(pattern) != snd_ctl_elem_id_get_device(id)) return 0; if (snd_ctl_elem_id_get_subdevice(pattern) != -1 && snd_ctl_elem_id_get_subdevice(pattern) != snd_ctl_elem_id_get_subdevice(id)) return 0; if (snd_ctl_elem_id_get_index(pattern) != -1 && snd_ctl_elem_id_get_index(pattern) != snd_ctl_elem_id_get_index(id)) return 0; if (fnmatch(snd_ctl_elem_id_get_name(pattern), snd_ctl_elem_id_get_name(id), 0) != 0) return 0; return 1;}staticint run_program1(struct space *space, const char *command0, char *result, size_t ressize, size_t *reslen, int log){ char *pos = strchr(command0, ' '); int cmdlen = pos ? pos - command0 : strlen(command0); int err, index; snd_hctl_elem_t *elem; snd_ctl_elem_id_t *id; if (cmdlen == 12 && strncmp(command0, "__ctl_search", 12) == 0) { index = 0; if (pos) index = strtol(pos, NULL, 0); err = snd_ctl_elem_id_malloc(&id); if (err < 0) return EXIT_FAILURE; elem = snd_hctl_first_elem(space->ctl_handle); while (elem) { snd_hctl_elem_get_id(elem, id); if (!ctl_match(space->ctl_id, id)) goto next_search; if (index > 0) { index--; goto next_search; } strlcpy(result, "0", ressize); snd_ctl_elem_id_copy(space->ctl_id, id); snd_ctl_elem_id_free(id); dbg("__ctl_search found a control"); return EXIT_SUCCESS; next_search: elem = snd_hctl_elem_next(elem); } snd_ctl_elem_id_free(id); return EXIT_FAILURE; } if (cmdlen == 11 && strncmp(command0, "__ctl_count", 11) == 0) { index = 0; err = snd_ctl_elem_id_malloc(&id); if (err < 0) return EXIT_FAILURE; elem = snd_hctl_first_elem(space->ctl_handle); while (elem) { snd_hctl_elem_get_id(elem, id); if (!ctl_match(space->ctl_id, id)) goto next_count; index++; next_count: elem = snd_hctl_elem_next(elem); } snd_ctl_elem_id_free(id); if (index > 0) { snprintf(result, ressize, "%u", index); dbg("__ctl_count found %s controls", result); return EXIT_SUCCESS; } dbg("__ctl_count no match"); return EXIT_FAILURE; } if (cmdlen == 11 && strncmp(command0, "__ctl_write", 11) == 0) { } Perror(space, "unknown buildin command '%s'", command0); return EXIT_FAILURE;}static int parse(struct space *space, const char *filename);static char *new_root_dir(const char *filename){ char *res, *tmp; res = strdup(filename); if (res) { tmp = rindex(res, '/'); if (tmp) *tmp = '\0'; } dbg("new_root_dir '%s' '%s'", filename, res); return res;}static int parse_line(struct space *space, char *line, size_t linesize){ char *linepos; char *key, *value, *attr, *temp; struct pair *pair; enum key_op op; int err = 0, count; char string[PATH_SIZE]; char result[PATH_SIZE]; linepos = line; while (*linepos != '\0') { op = KEY_OP_UNSET; err = get_key(&linepos, &key, &op, &value); if (err < 0) goto invalid; if (strncasecmp(key, "LABEL", 5) == 0) { if (op != KEY_OP_ASSIGN) { Perror(space, "invalid LABEL operation"); goto invalid; } if (space->go_to && strcmp(space->go_to, value) == 0) { free(space->go_to); space->go_to = NULL; } continue; } if (space->go_to) { dbg("skip (GOTO '%s')", space->go_to); break; /* not for us */ } if (strncasecmp(key, "CTL{", 4) == 0) { attr = get_key_attribute(space, key + 3, string, sizeof(string)); if (attr == NULL) { Perror(space, "error parsing CTL attribute"); goto invalid; } if (op == KEY_OP_ASSIGN) { strlcpy(result, value, sizeof(result)); apply_format(space, result, sizeof(result)); dbg("ctl assign: '%s' '%s'", value, attr); err = elemid_set(space, attr, result); if (space->program_result) { free(space->program_result); space->program_result = NULL; } snprintf(string, sizeof(string), "%i", err); space->program_result = strdup(string); if (err < 0 || space->program_result == NULL) { err = 0; break; } } else if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { dbg("ctl match: '%s' '%s'", value, attr); temp = (char *)elemid_get(space, attr); if (!do_match(key, op, value, temp)) break; } else { Perror(space, "invalid CTL{} operation"); goto invalid; } continue; } if (strcasecmp(key, "RESULT") == 0) { if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { if (!do_match(key, op, value, space->program_result)) break; } else if (op == KEY_OP_ASSIGN) { if (space->program_result) { free(space->program_result); space->program_result = NULL; } strlcpy(string, value, sizeof(string)); apply_format(space, string, sizeof(string)); space->program_result = strdup(string); if (space->program_result == NULL) break; } else { Perror(space, "invalid RESULT operation"); goto invalid; } continue; } if (strcasecmp(key, "PROGRAM") == 0) { if (op == KEY_OP_UNSET) continue; strlcpy(string, value, sizeof(string)); apply_format(space, string, sizeof(string)); if (space->program_result) { free(space->program_result); space->program_result = NULL; } if (run_program(space, string, result, sizeof(result), NULL, space->log_run) != 0) { dbg("PROGRAM '%s' is false", string); if (op != KEY_OP_NOMATCH) break; } else { remove_trailing_chars(result, '\n'); count = replace_untrusted_chars(result); if (count) info("%i untrusted character(s) replaced", count); dbg("PROGRAM '%s' result is '%s'", string, result); space->program_result = strdup(result); if (space->program_result == NULL) break; dbg("PROGRAM returned successful"); if (op == KEY_OP_NOMATCH) break; } dbg("PROGRAM key is true"); continue; } if (strncasecmp(key, "CARDINFO{", 9) == 0) { attr = get_key_attribute(space, key + 8, string, sizeof(string)); if (attr == NULL) { Perror(space, "error parsing CARDINFO attribute"); goto invalid; } if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { dbg("cardinfo: '%s' '%s'", value, attr); temp = (char *)cardinfo_get(space, attr); if (!do_match(key, op, value, temp)) break; } else { Perror(space, "invalid CARDINFO{} operation"); goto invalid; } continue; } if (strncasecmp(key, "ATTR{", 5) == 0) { attr = get_key_attribute(space, key + 4, string, sizeof(string)); if (attr == NULL) { Perror(space, "error parsing ATTR attribute"); goto invalid; } if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { pair = value_find(space, "sysfs_device"); if (pair == NULL) break; dbg("sysfs_attr: '%s' '%s'", pair->value, attr); temp = sysfs_attr_get_value(pair->value, attr); if (!do_match(key, op, value, temp)) break; } else { Perror(space, "invalid ATTR{} operation"); goto invalid; } continue; } if (strncasecmp(key, "ENV{", 4) == 0) { attr = get_key_attribute(space, key + 3, string, sizeof(string)); if (attr == NULL) { Perror(space, "error parsing ENV attribute"); goto invalid; } if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { temp = getenv(attr); dbg("env: '%s' '%s'", attr, temp); if (!do_match(key, op, value, temp)) break; } else if (op == KEY_OP_ASSIGN || op == KEY_OP_ASSIGN_FINAL) { strlcpy(result, value, sizeof(result)); apply_format(space, result, sizeof(result)); dbg("env set: '%s' '%s'", attr, result); if (setenv(attr, result, op == KEY_OP_ASSIGN_FINAL)) break; } else { Perror(space, "invalid ENV{} operation"); goto invalid; } continue; } if (strcasecmp(key, "GOTO") == 0) { if (op != KEY_OP_ASSIGN) { Perror(space, "invalid GOTO operation"); goto invalid; } space->go_to = strdup(value); if (space->go_to == NULL) { err = -ENOMEM; break; } continue; } if (strcasecmp(key, "INCLUDE") == 0) { char *rootdir, *go_to; const char *filename; struct dirent *dirent; DIR *dir; int linenum; if (op != KEY_OP_ASSIGN) { Perror(space, "invalid INCLUDE operation"); goto invalid; } if (value[0] == '/') strlcpy(string, value, sizeof(string)); else { strlcpy(string, space->rootdir, sizeof(string)); strlcat(string, "/", sizeof(string)); strlcat(string, value, sizeof(string)); } rootdir = space->rootdir; go_to = space->go_to; filename = space->filename; linenum = space->linenum; dir = opendir(string); if (dir) { count = strlen(string); while ((dirent = readdir(dir)) != NULL) { if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) continue; string[count] = '\0'; strlcat(string, "/", sizeof(string)); strlcat(string, dirent->d_name, sizeof(string)); space->go_to = NULL; space->rootdir = new_root_dir(string); if (space->rootdir) { err = parse(space, string); free(space->rootdir); } else err = -ENOMEM; if (space->go_to) { Perror(space, "unterminated GOTO '%s'", space->go_to); free(space->go_to); } if (err) break; } closedir(dir); } else { space->go_to = NULL; space->rootdir = new_root_dir(string); if (space->rootdir) { err = parse(space, string); free(space->rootdir); } else err = -ENOMEM; if (space->go_to) { Perror(space, "unterminated GOTO '%s'", space->go_to); free(space->go_to); } } space->go_to = go_to; space->rootdir = rootdir; space->filename = filename; space->linenum = linenum; if (space->quit) break; if (err) break; continue; } if (strncasecmp(key, "ACCESS", 6) == 0) { if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { if (value[0] != '/') { strlcpy(string, space->rootdir, sizeof(string)); strlcat(string, "/", sizeof(string)); strlcat(string, value, sizeof(string)); } else { strlcat(string, value, sizeof(string)); } count = access(string, F_OK); dbg("access(%s) = %i", value, count); if (op == KEY_OP_MATCH && count != 0) break; if (op == KEY_OP_NOMATCH && count == 0) break; } else { Perror(space, "invalid ACCESS operation"); goto invalid; } continue; } if (strncasecmp(key, "PRINT", 5) == 0) { if (op != KEY_OP_ASSIGN) { Perror(space, "invalid PRINT operation"); goto invalid; } strlcpy(string, value, sizeof(string)); apply_format(space, string, sizeof(string)); fwrite(string, strlen(string), 1, stdout); continue; } if (strncasecmp(key, "ERROR", 5) == 0) { if (op != KEY_OP_ASSIGN) { Perror(space, "invalid ERROR operation"); goto invalid; } strlcpy(string, value, sizeof(string)); apply_format(space, string, sizeof(string)); fwrite(string, strlen(string), 1, stderr); continue; } if (strncasecmp(key, "EXIT", 4) == 0) { if (op != KEY_OP_ASSIGN) { Perror(space, "invalid EXIT operation"); goto invalid; } strlcpy(string, value, sizeof(string)); apply_format(space, string, sizeof(string)); if (strcmp(string, "return") == 0) return -EJUSTRETURN; space->exit_code = strtol(string, NULL, 0); space->quit = 1; break; } if (strncasecmp(key, "CONFIG{", 7) == 0) { attr = get_key_attribute(space, key + 6, string, sizeof(string)); if (attr == NULL) { Perror(space, "error parsing CONFIG attribute"); goto invalid; } strlcpy(result, value, sizeof(result)); apply_format(space, result, sizeof(result)); if (op == KEY_OP_ASSIGN) { err = value_set(space, attr, result); dbg("CONFIG{%s}='%s'", attr, result); break; } else if (op == KEY_OP_MATCH || op == KEY_OP_NOMATCH) { pair = value_find(space, attr); if (pair == NULL) break; if (!do_match(key, op, result, pair->value)) break; } else { Perror(space, "invalid CONFIG{} operation"); goto invalid; } } Perror(space, "unknown key '%s'", key); } return err;invalid: Perror(space, "invalid rule"); return -EINVAL;}static int parse(struct space *space, const char *filename){ char *buf, *bufline, *line; size_t bufsize, pos, count, linesize; unsigned int linenum, i, j, linenum_adj; int err; dbg("start of file '%s'", filename); if (file_map(filename, &buf, &bufsize) != 0) { err = errno; error("Unable to open file '%s': %s", filename, strerror(err)); return -err; } err = 0; pos = 0; linenum = 0; linesize = 128; line = malloc(linesize); if (line == NULL) return -ENOMEM; space->filename = filename; while (!err && pos < bufsize && !space->quit) { count = line_width(buf, bufsize, pos); bufline = buf + pos; pos += count + 1; linenum++; /* skip whitespaces */ while (count > 0 && isspace(bufline[0])) { bufline++; count--; } if (count == 0) continue; /* comment check */ if (bufline[0] == '#') continue; if (count > linesize - 1) { free(line); linesize = (count + 127 + 1) & ~127; if (linesize > 2048) { error("file %s, line %i too long", filename, linenum); err = -EINVAL; break; } line = malloc(linesize); if (line == NULL) { err = -EINVAL; break; } } /* skip backslash and newline from multiline rules */ linenum_adj = 0; for (i = j = 0; i < count; i++) { if (bufline[i] == '\\' && bufline[i+1] == '\n') { linenum_adj++; continue; } line[j++] = bufline[i]; } line[j] = '\0'; dbg("read (%i) '%s'", linenum, line); space->linenum = linenum; err = parse_line(space, line, linesize); if (err == -EJUSTRETURN) { err = 0; break; } linenum += linenum_adj; } free(line); space->filename = NULL; space->linenum = -1; file_unmap(buf, bufsize); dbg("end of file '%s'", filename); return err ? err : -abs(space->exit_code);}int init(const char *filename, const char *cardname){ struct space *space; int err = 0, card, first; sysfs_init(); if (!cardname) { first = 1; card = -1; while (1) { if (snd_card_next(&card) < 0) break; if (card < 0) { if (first) { error("No soundcards found..."); return -ENODEV; } break; } first = 0; err = init_space(&space, card); if (err == 0 && (space->rootdir = new_root_dir(filename)) != NULL) err = parse(space, filename); free_space(space); if (err < 0) break; } } else { card = snd_card_get_index(cardname); if (card < 0) { error("Cannot find soundcard '%s'...", cardname); goto error; } memset(&space, 0, sizeof(space)); err = init_space(&space, card); if (err == 0 && (space->rootdir = new_root_dir(filename)) != NULL) err = parse(space, filename); free_space(space); } error: sysfs_cleanup(); return err;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -