Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow quoting to preserve spaces in the login option in config file #59

Merged
merged 2 commits into from
Aug 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
viccie30 marked this conversation as resolved.
Show resolved Hide resolved
- 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'@test_name@.c',
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