mirror of
https://github.com/apache/nuttx-apps.git
synced 2026-08-02 12:49:03 +00:00
Fix argument parsing in init_parse_arguments() to properly handle multiple quoted arguments like 'echo "arg1" "arg2"' by skipping quote characters after processing them. Signed-off-by: fangpeina <fangpeina@xiaomi.com>
308 lines
6.6 KiB
C
308 lines
6.6 KiB
C
/****************************************************************************
|
|
* apps/system/nxinit/parser.c
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
* Included Files
|
|
****************************************************************************/
|
|
|
|
#include <ctype.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
#include "init.h"
|
|
#include "parser.h"
|
|
|
|
/****************************************************************************
|
|
* Public Functions
|
|
****************************************************************************/
|
|
|
|
int init_parse_arguments(FAR char *buf, bool dup, int argc, FAR char **argv)
|
|
{
|
|
bool quote = false;
|
|
bool new = true;
|
|
int i = 0;
|
|
|
|
for (; ; )
|
|
{
|
|
while (isblank(*buf))
|
|
{
|
|
if (!quote)
|
|
{
|
|
*buf = '\0';
|
|
new = true;
|
|
}
|
|
|
|
buf++;
|
|
}
|
|
|
|
if (*buf == '-' && *(buf + 1) == '-')
|
|
{
|
|
argv[i++] = buf;
|
|
if (i >= argc || *(buf += 2) == '\0')
|
|
{
|
|
break;
|
|
}
|
|
|
|
while (isblank(*buf))
|
|
{
|
|
*buf++ = '\0';
|
|
}
|
|
|
|
argv[i++] = buf;
|
|
break;
|
|
}
|
|
|
|
if (*buf == '\"')
|
|
{
|
|
*buf = '\0';
|
|
if (quote)
|
|
{
|
|
quote = false;
|
|
buf++;
|
|
}
|
|
else
|
|
{
|
|
quote = true;
|
|
new = true;
|
|
buf++;
|
|
}
|
|
}
|
|
|
|
if (*buf == '\0')
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (new)
|
|
{
|
|
argv[i++] = buf;
|
|
if (i >= argc)
|
|
{
|
|
break;
|
|
}
|
|
|
|
new = false;
|
|
}
|
|
|
|
buf++;
|
|
}
|
|
|
|
if (dup && i > 0)
|
|
{
|
|
argc = i;
|
|
for (i = 0; i < argc; i++)
|
|
{
|
|
argv[i] = strdup(argv[i]);
|
|
if (!argv[i])
|
|
{
|
|
while (i-- > 0)
|
|
{
|
|
free(argv[i]);
|
|
}
|
|
|
|
return -errno;
|
|
}
|
|
}
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
int init_parse_config_file(FAR const struct parser_s *parser,
|
|
FAR const char *file)
|
|
{
|
|
char buf[CONFIG_SYSTEM_NXINIT_RC_LINE_MAX];
|
|
FAR const struct parser_s *cur = NULL;
|
|
bool create = false;
|
|
FAR char *nl;
|
|
size_t n = 0;
|
|
int ret = 0;
|
|
int fd;
|
|
#ifdef CONFIG_SYSTEM_NXINIT_DEBUG
|
|
int line = 0;
|
|
#endif
|
|
|
|
init_debug("Parsing %s", file);
|
|
|
|
fd = open(file, O_RDONLY | O_CLOEXEC);
|
|
if (fd < 0)
|
|
{
|
|
init_err("Opening %s %d", file, errno);
|
|
return -errno;
|
|
}
|
|
|
|
for (; ; )
|
|
{
|
|
ssize_t r = read(fd, &buf[n], sizeof(buf) - n);
|
|
if (r < 0)
|
|
{
|
|
if (errno == EINTR)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
ret = -errno;
|
|
goto out;
|
|
}
|
|
else if (r == 0)
|
|
{
|
|
if (n == 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
buf[n++] = '\n';
|
|
}
|
|
|
|
n += r;
|
|
while ((nl = memchr(buf, '\n', n)))
|
|
{
|
|
*(nl++) = '\0';
|
|
n -= nl - buf;
|
|
init_debug("Line %3d: '%s'", ++line, buf);
|
|
if (*buf == '\0')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
/* Skip empty lines and lines containing only whitespace */
|
|
|
|
for (ret = 0; buf[ret] && isblank(buf[ret]); ret++);
|
|
|
|
if (buf[ret] == '\0')
|
|
{
|
|
memmove(buf, nl, n);
|
|
continue;
|
|
}
|
|
|
|
for (ret = 0; parser[ret].key; ret++)
|
|
{
|
|
if (!strncmp(parser[ret].key, buf, strlen(parser[ret].key)))
|
|
{
|
|
create = true;
|
|
cur = &parser[ret];
|
|
init_debug("New section (%s)", parser[ret].key);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (cur == NULL)
|
|
{
|
|
ret = -EINVAL;
|
|
goto out;
|
|
}
|
|
|
|
ret = cur->parse(cur, create, buf);
|
|
create = false;
|
|
if (ret < 0)
|
|
{
|
|
goto out;
|
|
}
|
|
|
|
memmove(buf, nl, n);
|
|
}
|
|
|
|
if (n == sizeof(buf))
|
|
{
|
|
ret = -E2BIG;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
for (n = 0; parser[n].key; n++)
|
|
{
|
|
if (parser[n].check)
|
|
{
|
|
ret = parser[n].check(&parser[n]);
|
|
if (ret < 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
out:
|
|
close(fd);
|
|
if (ret < 0)
|
|
{
|
|
init_err("Parse %s %d", file, ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int init_parse_configs(FAR const struct parser_s *parser,
|
|
FAR const char *path)
|
|
{
|
|
FAR struct dirent *entry;
|
|
char file[PATH_MAX];
|
|
struct stat sb;
|
|
FAR DIR *dir;
|
|
int ret = 0;
|
|
size_t i;
|
|
|
|
if (stat(path, &sb) < 0)
|
|
{
|
|
init_err("Stat %s", path);
|
|
return -errno;
|
|
}
|
|
|
|
if (S_ISDIR(sb.st_mode))
|
|
{
|
|
dir = opendir(path);
|
|
if (dir == NULL)
|
|
{
|
|
init_err("Opening directory %s", path);
|
|
return -errno;
|
|
}
|
|
|
|
while ((entry = readdir(dir)) != NULL)
|
|
{
|
|
if (DIRENT_ISFILE(entry->d_type))
|
|
{
|
|
i = strlen(entry->d_name);
|
|
if (i >= 3 && !strcmp(entry->d_name + i - 3, ".rc"))
|
|
{
|
|
snprintf(file, sizeof(file), "%s/%s", path, entry->d_name);
|
|
ret = init_parse_config_file(parser, file);
|
|
if (ret < 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
closedir(dir);
|
|
}
|
|
else if (S_ISREG(sb.st_mode))
|
|
{
|
|
ret = init_parse_config_file(parser, path);
|
|
}
|
|
|
|
return ret;
|
|
}
|