Im trying to make a “loadable” bash builtin that can be enabled using the enable command. This builtin will use lseek to allow changing the byte offset of a file descriptor.
The end goal here is being able to rewind a file descriptor by 1 byte and to do so extremely fast (say, less than 100 μs). For this particular application the time it would take to call an external binary to implement this is too long, but i think/hope that a loadable builtin will be sufficiently fast.
I am able to create the shared dynamically loaded library file and can load it with enable -f ./lseek lseek
, but when i try to use it I just get a segmentation fault (core dumped)
error.
The lseek.c
source code as well as the commands im using to compile it are shown in the script below. NOTE: i have very little knowledge of C…the lseek.c
source code is originally from chatgpt, and then I tried my best to modify it using the example loadables and this guide, and sorta just tweaked stuff until it compiled and loaded. The compile commands are based off of what make
runs to compile the other example loadables.
If anyone can see what the error is and tell me how to correct it Id much appreciate it. Thank you in advance.
OS is Fedora 40. Bash version is 5.2.x.
git clone https://git.savannah.gnu.org/git/bash.git
cd bash
./configure
cd ./examples/loadables
cat<<'EOF' >lseek.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include "command.h"
#include "builtins.h"
int
builtin_lseek (list)
WORD_LIST *list; {
// Check for the right number of arguments
if (list == NULL || list->word->word == NULL || list->next->word->word == NULL || list->next->next->word->word != NULL) {
fprintf(stderr, "Usage: lseek <fd> <offset>n");
return 1;
}
// Extract arguments from WORD_LIST
char *fd_str = list->word->word;
char *offset_str = list->next->word->word;
int fd = atoi(fd_str); // Convert the first argument to integer (file descriptor)
off_t offset = atoll(offset_str); // Convert the second argument to long long (offset)
if (fd < 0) {
fprintf(stderr, "Invalid file descriptor: %dn", fd);
return 1;
}
off_t new_offset = lseek(fd, offset, SEEK_CUR); // Use SEEK_CUR to move relative to current position
if (new_offset == (off_t) -1) {
perror("lseek");
return 1;
}
printf("File descriptor %d moved to offset %lldn", fd, (long long)new_offset);
return EXIT_SUCCESS;
}
char *lseek_doc[] =
{
"Change file descriptor offset",
"",
"Changes the byte offset of the file descriptor relative to the current byte offset",
"--> 1st input is file descriptor number (non-negative integer)",
"--> 2nd input is relative byte offset (non-zero integer)",
"",
"Specifying a positive byte offset will advance the file descriptor",
"Specifying a negative byte offset will rewind the file descriptor",
(char *)NULL
};
struct builtin lseek_struct = {
"lseek", /* command name */
builtin_lseek, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
lseek_doc, /* array of long documentation strings. */
"lseek <fd> <rel_offset>", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
EOF
gcc -fPIC -DHAVE_CONFIG_H -DSHELL -g -O2 -Wno-parentheses -Wno-format-security -I. -I.. -I../.. -I../../lib -I../../builtins -I. -I../../include -c -o lseek.o lseek.c
gcc -shared -Wl,-soname,lseek -I /usr/include/bash -o lseek lseek.o
enable -f ./lseek lseek
(
mapfile -t -n 11 -u $fd A
lseek $fd 1; read -r -u $fd B
printf '%sn' "${A[@]}"; echo; echo; echo $B
) {fd}<./builtin_lseek.c
Segmentation fault (core dumped)