Skip to content

Commit

Permalink
Merge pull request #1113 from Mathewnd/master
Browse files Browse the repository at this point in the history
options/posix: implement {get,set,end}usershell
  • Loading branch information
no92 committed Aug 29, 2024
2 parents 67e11fa + 6e89642 commit 4dc6701
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 6 deletions.
52 changes: 46 additions & 6 deletions options/posix/generic/unistd-stubs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1137,19 +1137,59 @@ int access(const char *path, int mode) {
return 0;
}

namespace {
FILE *user_shell_global_file; // Used by setusershell/getusershell/endusershell.

bool user_shell_open_global_file() {
if(!user_shell_global_file) {
user_shell_global_file = fopen("/etc/shells", "r");
if(!user_shell_global_file) {
// if the file cannot be opened, we need to pretend one exists with
// these shells:
static char shells[] = "/bin/sh\n/bin/csh\n";

user_shell_global_file = fmemopen(shells, strlen(shells), "r");
if(user_shell_global_file == nullptr)
return false;
}
}

return true;
}

void user_shell_close_global_file() {
if(user_shell_global_file) {
fclose(user_shell_global_file);
user_shell_global_file = nullptr;
}
}
}

char *getusershell(void) {
__ensure(!"Not implemented");
__builtin_unreachable();
static char shell[PATH_MAX];
if(!user_shell_open_global_file())
return nullptr;

if (fgets(shell, PATH_MAX, user_shell_global_file)){
shell[strcspn(shell, "\n")] = '\0';
return shell;
}

if(ferror(user_shell_global_file))
errno = EIO;

return nullptr;
}

void setusershell(void) {
__ensure(!"Not implemented");
__builtin_unreachable();
if(!user_shell_open_global_file())
return;

rewind(user_shell_global_file);
}

void endusershell(void) {
__ensure(!"Not implemented");
__builtin_unreachable();
user_shell_close_global_file();
}

int isatty(int fd) {
Expand Down
1 change: 1 addition & 0 deletions tests/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ all_test_cases = [
'posix/strdupa',
'posix/mkstemp',
'posix/waitid',
'posix/usershell',
'glibc/getopt',
'glibc/ffsl-ffsll',
'glibc/error_message_count',
Expand Down
63 changes: 63 additions & 0 deletions tests/posix/usershell.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>

static void testfor(const char *expected, char *shell, int *count) {
if (strcmp(shell, expected) == 0)
*count += 1;
}

#define BUFFER_SIZE (1024 * 512)

int main(void) {
setusershell();

FILE *f = fopen("/etc/shells", "r");
if (f == NULL) {
/* /etc/shells file is unreadable, test for the existance of /bin/sh and /bin/csh */
char *shell = getusershell();
int csh = 0;
int sh = 0;

testfor("/bin/sh", shell, &sh);
testfor("/bin/csh", shell, &csh);

shell = getusershell();
assert(shell);

testfor("/bin/sh", shell, &sh);
testfor("/bin/csh", shell, &csh);

assert(sh == 1 && csh == 1);
assert(getusershell() == NULL);
} else {
/* /etc/shells is there, read the whole file into a buffer and change all '\n's to '\0'. */
char buffer[BUFFER_SIZE + 1];
int nbytes = fread(buffer, 1, BUFFER_SIZE, f);
buffer[nbytes] = '\0';

for (int i = 0; i < nbytes; ++i) {
if (buffer[i] == '\n')
buffer[i] = '\0';
}

/* loop through each shell and make sure the result is right */
char *shell = buffer;
while (shell < &buffer[nbytes]) {
char *usershell = getusershell();
while (usershell && *usershell == '#')
usershell = getusershell();

while (*shell == '#')
shell += strlen(shell) + 1;

assert(strcmp(shell, usershell) == 0);
shell += strlen(shell) + 1;
}
}

endusershell();

return 0;
}

0 comments on commit 4dc6701

Please sign in to comment.