Ваша динамическая библиотека всегда может читать /proc/self/cmdline
, чтобы узнать, какие параметры командной строки используются для выполнения текущего исполняемого файла. example.c
:
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
static char **get_argv(int *const argcptr)
{
char **argv;
char *data = NULL;
size_t size = 0; /* Allocated to data */
size_t used = 0;
size_t argc, i;
ssize_t bytes;
int fd;
if (argcptr)
*argcptr = 0;
do {
fd = open("/proc/self/cmdline", O_RDONLY | O_NOCTTY);
} while (fd == -1 && errno == EINTR);
if (fd == -1)
return NULL;
while (1) {
if (used >= size) {
char *old_data = data;
size = (used | 4095) + 4096;
data = realloc(data, size + 1);
if (data == NULL) {
free(old_data);
close(fd);
errno = ENOMEM;
return NULL;
}
}
do {
bytes = read(fd, data + used, size - used);
} while (bytes == (ssize_t)-1 && errno == EINTR);
if (bytes < (ssize_t)0) {
free(data);
close(fd);
errno = EIO;
return NULL;
} else
if (bytes == (ssize_t)0)
break;
else
used += bytes;
}
if (close(fd)) {
free(data);
errno = EIO;
return NULL;
}
/* Let's be safe and overallocate one pointer here. */
argc = 1;
for (i = 0; i < used; i++)
if (data[i] == '\0')
argc++;
/* Reallocate to accommodate both pointers and data. */
argv = realloc(data, (argc + 1) * sizeof (char *) + used + 1);
if (argv == NULL) {
free(data);
errno = ENOMEM;
return NULL;
}
data = (char *)(argv + argc + 1);
memmove(data, argv, used);
/* In case the input lacked a trailing NUL byte. */
data[used] = '\0';
/* Assign the pointers. */
argv[0] = data;
argc = 0;
for (i = 0; i < used; i++)
if (data[i] == '\0')
argv[++argc] = data + i + 1;
/* Final pointer points to past data. Make it end the array. */
argv[argc] = NULL;
if (argcptr)
*argcptr = (int)argc;
return argv;
}
/* Example standard error functions, that avoid the use of stdio.h.
*/
static void wrerr(const char *p)
{
if (p != NULL) {
const char *const q = p + strlen(p);
ssize_t n;
while (p < q) {
n = write(STDERR_FILENO, p, (size_t)(q - p));
if (n > (ssize_t)0)
p += n;
else
if (n != (ssize_t)-1)
return;
else
if (errno != EINTR)
return;
}
}
}
static void wrerrint(const int i)
{
char buffer[32];
char *p = buffer + sizeof buffer;
unsigned int u;
if (i < 0)
u = (unsigned int)(-i);
else
u = (unsigned int)i;
*(--p) = '\0';
do {
*(--p) = '0' + (u % 10U);
u /= 10U;
} while (u > 0U);
if (i < 0)
*(--p) = '-';
wrerr(p);
}
static void init(void) __attribute__((constructor));
static void init(void)
{
int argc, i, saved_errno;
char **argv;
saved_errno = errno;
argv = get_argv(&argc);
if (argv == NULL) {
const char *const errmsg = strerror(errno);
wrerr("libexample.so: get_argv() failed: ");
wrerr(errmsg);
wrerr(".\n");
errno = saved_errno;
return;
}
for (i = 0; i < argc; i++) {
wrerr("libexample.so: argv[");
wrerrint((int)i);
wrerr("] = '");
wrerr(argv[i]);
wrerr("'\n");
}
free(argv);
errno = saved_errno;
return;
}
Вкомпилировать использованием, например,
gcc -Wall -fPIC -shared example.c -ldl -Wl,-soname,libexample.so -o libexample.so
и испытания с использованием, например,
LD_PRELOAD=./libexample.so /bin/echo foo bar baz baaz
(Обратите внимание, что простой echo
является оболочкой встроенный, и вы должны выполнить еще один двоичный файл, как /bin/echo
загрузить библиотеку преднагрузки.)
Однако наиболее динамические библиотеки принимают аргументы в переменных среды вместо ; например, YOURLIB_MEM
для подсказки размера памяти или YOURLIB_DEBUG
для включения подробного вывода отладки во время выполнения.
(Мой пример кода не использует stdio.h выход, потому что не все бинарные файлы использовать, особенно если написано в каком-то другом языке. Вместо этого, wrerr()
и wrerrint()
маленькие глупые вспомогательные функции, которые используют низкоуровневые unistd.h I/O для прямой записи в стандартную ошибку, это всегда работает и вызывает минимальные побочные эффекты во время выполнения.)
Вопросы?
Это, конечно, предполагает, что '/ proc' установлен, что не всегда так. –
@ JonathonReinhart: Правда. Однако вы не можете предположить, что программа будет работать без '/ proc', установленного в Linux в любом случае. Вы теряете немного функциональности без '/ proc', включая некоторые функции glibc, такие как [' fexecve() '] (http://man7.org/linux/man-pages/man3/fexecve.3.html) и такие утилиты, как 'pidof', перестают работать. Это не так важно, хотя: как я уже сказал, * «большинство динамических библиотек [должны] принимать аргументы в переменных среды» *, и это никак не зависит от '/ proc'. –