Skip to content

Commit

Permalink
Merge pull request #59 from viccie30/split_command_string
Browse files Browse the repository at this point in the history
Allow quoting to preserve spaces in the login option in config file
  • Loading branch information
Aetf authored Aug 5, 2022
2 parents a95c9ae + 51e41dd commit 20a2fc4
Show file tree
Hide file tree
Showing 8 changed files with 530 additions and 5 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
run: pip install meson ninja
- name: Install dependencies
run: |
sudo apt-get install -y libudev-dev libxkbcommon-dev libdrm-dev libgbm-dev libegl1-mesa-dev libgles-dev libpango1.0-dev libsystemd-dev
sudo apt-get install -y check libudev-dev libxkbcommon-dev libdrm-dev libgbm-dev libegl1-mesa-dev libgles-dev libpango1.0-dev libsystemd-dev
- name: Install libtsm
run: |
pip install cmake
Expand All @@ -38,7 +38,7 @@ jobs:
run: meson setup builddir/
- name: Create source distribution
# no unit tests yet
run: meson dist -C builddir/ --no-tests
run: meson dist -C builddir/
- name: Create release note
run: tools/extract_release_note.py NEWS ${{ github.workspace }}-release-note.txt
- name: Upload Artifact
Expand All @@ -55,4 +55,3 @@ jobs:
with:
files: builddir/meson-dist/*
body_path: ${{ github.workspace }}-release-note.txt

6 changes: 6 additions & 0 deletions docs/man/kmscon.1.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,12 @@
is parsed as regular option by kmscon.
(default: /bin/login -p)</para>

<para>If this option is specified in the configuration file, the
argument is split into words using the rules of the POSIX shell.
It is possible to include whitespace in arguments by enclosing
the argument in double or single quotes or by prepending it with
a backslash.</para>

<para>This example starts '/bin/bash -i' on each new terminal session:
./kmscon --login --debug --no-switchvt -- /bin/bash -i</para>
</listitem>
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ glesv2_deps = dependency('glesv2', disabler: true, required: require_glesv2)
pango_deps = dependency('pangoft2', disabler: true, required: get_option('font_pango'))
pixman_deps = dependency('pixman-1', disabler: true, required: get_option('renderer_pixman'))
xsltproc = find_program('xsltproc', native: true, disabler: true, required: get_option('docs'))
check_deps = dependency('check', disabler: true, required: get_option('tests'))

#
# Handle feature options
Expand Down
2 changes: 1 addition & 1 deletion src/kmscon_conf.c
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ static int file_login(struct conf_option *opt, bool on, const char *arg)
return -EFAULT;
}

ret = shl_split_string(arg, &t, &size, ' ', false);
ret = shl_split_command_string(arg, &t, &size);
if (ret) {
log_error("cannot split 'login' config-option argument");
return ret;
Expand Down
213 changes: 213 additions & 0 deletions src/shl_misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,219 @@ static inline int shl_split_string(const char *arg, char ***out,
return 0;
}

/* This parses \arg and splits the string into a new allocated array. The array
* is stored in \out and is NULL terminated. \out_num is the number of entries
* in the array. You can set it to NULL to not retrieve this value. */
static inline int shl_split_command_string(const char *arg, char ***out,
unsigned int *out_num)
{
unsigned int i;
unsigned int num, len, size, pos;
char **list, *off;
enum { UNQUOTED, DOUBLE_QUOTED, SINGLE_QUOTED } quote_status;
bool in_word;

if (!arg || !out)
return -EINVAL;

num = 0;
size = 0;
len = 0;
quote_status = UNQUOTED;
for (i = 0; arg[i]; ++i) {
switch (arg[i]) {
case ' ':
case '\t':
switch (quote_status) {
case UNQUOTED:
if (len > 0) {
++num;
size += len + 1;
len = 0;
}
break;
case DOUBLE_QUOTED:
case SINGLE_QUOTED:
++len;
break;
}
break;
case '"':
switch (quote_status) {
case UNQUOTED:
quote_status = DOUBLE_QUOTED;
break;
case DOUBLE_QUOTED:
quote_status = UNQUOTED;
break;
case SINGLE_QUOTED:
++len;
break;
}
break;
case '\'':
switch (quote_status) {
case UNQUOTED:
quote_status = SINGLE_QUOTED;
break;
case DOUBLE_QUOTED:
++len;
break;
case SINGLE_QUOTED:
quote_status = UNQUOTED;
break;
}
break;
case '\\':
switch (quote_status) {
case UNQUOTED:
if (!arg[i + 1])
return -EINVAL;
++i;
++len;
break;
case DOUBLE_QUOTED:
if (arg[i + 1] == '"' || arg[i + 1] == '\\')
++i;
++len;
break;
case SINGLE_QUOTED:
++len;
break;
}
break;
default:
++len;
break;
}
}

if (quote_status != UNQUOTED)
return -EINVAL;

if (len > 0) {
++num;
size += len + 1;
}

list = malloc(sizeof(char*) * (num + 1) + size);
if (!list)
return -ENOMEM;

off = (void*)(((char*)list) + (sizeof(char*) * (num + 1)));
len = 0;
pos = 0;
in_word = false;
for (i = 0; arg[i]; ++i) {
switch (arg[i]) {
case ' ':
case '\t':
switch (quote_status) {
case UNQUOTED:
if (in_word) {
in_word = false;
*off = '\0';
++off;
}
break;
case DOUBLE_QUOTED:
case SINGLE_QUOTED:
*off = arg[i];
if (!in_word) {
in_word = true;
list[pos++] = off;
}
++off;
break;
}
break;
case '"':
switch (quote_status) {
case UNQUOTED:
quote_status = DOUBLE_QUOTED;
break;
case DOUBLE_QUOTED:
quote_status = UNQUOTED;
break;
case SINGLE_QUOTED:
*off = arg[i];
if (!in_word) {
in_word = true;
list[pos++] = off;
}
++off;
break;
}
break;
case '\'':
switch (quote_status) {
case UNQUOTED:
quote_status = SINGLE_QUOTED;
break;
case DOUBLE_QUOTED:
*off = arg[i];
if (!in_word) {
in_word = true;
list[pos++] = off;
}
++off;
break;
case SINGLE_QUOTED:
quote_status = UNQUOTED;
break;
}
break;
case '\\':
switch (quote_status) {
case UNQUOTED:
++i;
*off = arg[i];
if (!in_word) {
in_word = true;
list[pos++] = off;
}
++off;
break;
case DOUBLE_QUOTED:
if (arg[i + 1] == '"' || arg[i + 1] == '\\')
++i;
*off = arg[i];
if (!in_word) {
in_word = true;
list[pos++] = off;
}
++off;
break;
case SINGLE_QUOTED:
*off = arg[i];
if (!in_word) {
in_word = true;
list[pos++] = off;
}
++off;
break;
}
break;
default:
*off = arg[i];
if (!in_word) {
in_word = true;
list[pos++] = off;
}
++off;
break;
}
}
if (in_word)
*off = '\0';
list[pos] = NULL;

*out = list;
if (out_num)
*out_num = num;
return 0;
}

static inline int shl_dup_array_size(char ***out, char **argv, size_t len)
{
char **t, *off;
Expand Down
9 changes: 8 additions & 1 deletion tests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,12 @@ foreach name, deps : {
exe = executable(test_name, f'@[email protected]',
dependencies: deps,
)
test(test_name, exe)
endforeach

test_shl = executable('test_shl', 'test_shl.c',
dependencies: [shl_deps, check_deps],
)
test('test_shl', test_shl,
protocol: 'tap',
env: {'CK_TAP_LOG_FILE_NAME': '-', 'CK_VERBOSITY': 'silent'},
)
Loading

0 comments on commit 20a2fc4

Please sign in to comment.