mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	conf: fix context.exec args parsing
The 'args' can be either JSON array, or a string. If a string it should not be parsed as JSON for a second time, but instead split at whitespaces.
This commit is contained in:
		
							parent
							
								
									51b3778f7c
								
							
						
					
					
						commit
						b80d115140
					
				
					 1 changed files with 62 additions and 23 deletions
				
			
		| 
						 | 
					@ -945,9 +945,10 @@ static char **pw_strv_insert_at(char **strv, int len, int pos, const char *str)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	n = realloc(strv, sizeof(char*) * (len + 2));
 | 
						n = realloc(strv, sizeof(char*) * (len + 2));
 | 
				
			||||||
	if (n == NULL) {
 | 
						if (n == NULL) {
 | 
				
			||||||
		free(strv);
 | 
							pw_free_strv(strv);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	strv = n;
 | 
						strv = n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memmove(strv+pos+1, strv+pos, sizeof(char*) * (len+1-pos));
 | 
						memmove(strv+pos+1, strv+pos, sizeof(char*) * (len+1-pos));
 | 
				
			||||||
| 
						 | 
					@ -955,15 +956,16 @@ static char **pw_strv_insert_at(char **strv, int len, int pos, const char *str)
 | 
				
			||||||
	return strv;
 | 
						return strv;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int do_exec(struct pw_context *context, const char *path, const char *args)
 | 
					static int do_exec(struct pw_context *context, char *const *argv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int pid, res;
 | 
						int pid, res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pid = fork();
 | 
						pid = fork();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pid == 0) {
 | 
						if (pid == 0) {
 | 
				
			||||||
		char **arg;
 | 
							char buf[1024];
 | 
				
			||||||
		int n_args;
 | 
							char *const *p;
 | 
				
			||||||
 | 
							struct spa_strbuf s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Double fork to avoid zombies; we don't want to set SIGCHLD handler */
 | 
							/* Double fork to avoid zombies; we don't want to set SIGCHLD handler */
 | 
				
			||||||
		pid = fork();
 | 
							pid = fork();
 | 
				
			||||||
| 
						 | 
					@ -975,23 +977,16 @@ static int do_exec(struct pw_context *context, const char *path, const char *arg
 | 
				
			||||||
			exit(0);
 | 
								exit(0);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		arg = pw_strv_parse(args, strlen(args), INT_MAX, &n_args);
 | 
							spa_strbuf_init(&s, buf, sizeof(buf));
 | 
				
			||||||
		if (arg == NULL) {
 | 
							for (p = argv; *p; ++p)
 | 
				
			||||||
			pw_log_error("error parsing arguments: %m");
 | 
								spa_strbuf_append(&s, " '%s'", *p);
 | 
				
			||||||
			goto done;
 | 
					
 | 
				
			||||||
		}
 | 
							pw_log_info("exec%s", s.buffer);
 | 
				
			||||||
		arg = pw_strv_insert_at(arg, n_args, 0, path);
 | 
							res = execvp(argv[0], argv);
 | 
				
			||||||
		if (arg == NULL) {
 | 
					 | 
				
			||||||
			pw_log_error("error constructing arguments: %m");
 | 
					 | 
				
			||||||
			goto done;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		pw_log_info("exec %s '%s'", path, args);
 | 
					 | 
				
			||||||
		res = execvp(path, arg);
 | 
					 | 
				
			||||||
		pw_free_strv(arg);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (res == -1) {
 | 
							if (res == -1) {
 | 
				
			||||||
			res = -errno;
 | 
								res = -errno;
 | 
				
			||||||
			pw_log_error("execvp error '%s': %m", path);
 | 
								pw_log_error("execvp error '%s': %m", argv[0]);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
done:
 | 
					done:
 | 
				
			||||||
		exit(1);
 | 
							exit(1);
 | 
				
			||||||
| 
						 | 
					@ -1016,6 +1011,36 @@ done:
 | 
				
			||||||
 *   }
 | 
					 *   }
 | 
				
			||||||
 * ]
 | 
					 * ]
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char **make_exec_argv(const char *path, const char *value, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						char **argv = NULL;
 | 
				
			||||||
 | 
						int n_args;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (spa_json_is_container(value, len)) {
 | 
				
			||||||
 | 
							if (!spa_json_is_array(value, len)) {
 | 
				
			||||||
 | 
								errno = EINVAL;
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							argv = pw_strv_parse(value, len, INT_MAX, &n_args);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							spa_autofree char *s = calloc(1, len + 1);
 | 
				
			||||||
 | 
							if (!s)
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (spa_json_parse_stringn(value, len, s, len + 1) < 0) {
 | 
				
			||||||
 | 
								errno = EINVAL;
 | 
				
			||||||
 | 
								return NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							argv = pw_split_strv(s, " \t", INT_MAX, &n_args);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!argv)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return pw_strv_insert_at(argv, n_args, 0, path);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int parse_exec(void *user_data, const char *location,
 | 
					static int parse_exec(void *user_data, const char *location,
 | 
				
			||||||
		const char *section, const char *str, size_t len)
 | 
							const char *section, const char *str, size_t len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1034,7 +1059,9 @@ static int parse_exec(void *user_data, const char *location,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((r = spa_json_enter_object(&it[1], &it[2])) > 0) {
 | 
						while ((r = spa_json_enter_object(&it[1], &it[2])) > 0) {
 | 
				
			||||||
		char *path = NULL, *args = NULL;
 | 
							char *path = NULL;
 | 
				
			||||||
 | 
							const char *args_val = "[]";
 | 
				
			||||||
 | 
							int args_len = 2;
 | 
				
			||||||
		bool have_match = true;
 | 
							bool have_match = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) {
 | 
							while (spa_json_get_string(&it[2], key, sizeof(key)) > 0) {
 | 
				
			||||||
| 
						 | 
					@ -1053,13 +1080,13 @@ static int parse_exec(void *user_data, const char *location,
 | 
				
			||||||
			} else if (spa_streq(key, "args")) {
 | 
								} else if (spa_streq(key, "args")) {
 | 
				
			||||||
				if (spa_json_is_container(val, l))
 | 
									if (spa_json_is_container(val, l))
 | 
				
			||||||
					l = spa_json_container_len(&it[2], val, l);
 | 
										l = spa_json_container_len(&it[2], val, l);
 | 
				
			||||||
				args = (char*)val;
 | 
									args_val = val;
 | 
				
			||||||
				spa_json_parse_stringn(val, l, args, l+1);
 | 
									args_len = l;
 | 
				
			||||||
			} else if (spa_streq(key, "condition")) {
 | 
								} else if (spa_streq(key, "condition")) {
 | 
				
			||||||
				if (!spa_json_is_array(val, l)) {
 | 
									if (!spa_json_is_array(val, l)) {
 | 
				
			||||||
					pw_log_warn("expected array for condition in '%.*s'",
 | 
										pw_log_warn("expected array for condition in '%.*s'",
 | 
				
			||||||
							(int)len, str);
 | 
												(int)len, str);
 | 
				
			||||||
					break;
 | 
										goto next;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				spa_json_enter(&it[2], &it[3]);
 | 
									spa_json_enter(&it[2], &it[3]);
 | 
				
			||||||
				have_match = find_match(&it[3], &context->properties->dict, true);
 | 
									have_match = find_match(&it[3], &context->properties->dict, true);
 | 
				
			||||||
| 
						 | 
					@ -1072,11 +1099,23 @@ static int parse_exec(void *user_data, const char *location,
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (path != NULL) {
 | 
							if (path != NULL) {
 | 
				
			||||||
			res = do_exec(context, path, args);
 | 
								char **argv = make_exec_argv(path, args_val, args_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!argv) {
 | 
				
			||||||
 | 
									pw_log_warn("expected array or string for args in '%.*s'",
 | 
				
			||||||
 | 
											(int)len, str);
 | 
				
			||||||
 | 
									goto next;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								res = do_exec(context, argv);
 | 
				
			||||||
 | 
								pw_free_strv(argv);
 | 
				
			||||||
			if (res < 0)
 | 
								if (res < 0)
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			d->count++;
 | 
								d->count++;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						next:
 | 
				
			||||||
 | 
							continue;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (r < 0)
 | 
						if (r < 0)
 | 
				
			||||||
		pw_log_warn("malformed object array in '%.*s'", (int)len, str);
 | 
							pw_log_warn("malformed object array in '%.*s'", (int)len, str);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue