typedef void (make_request_fn) (struct request_queue *q, struct bio *bio);
Это не объявление функции. Это определение типа функции. Позже в том же файле include/linux/blkdev.h, строка 299, такое же имя получает поле в структуре
request_queue
.А в файле drivers/md/bcache/request.c, в строке 1140, этому полю присвоена функция
flash_dev_make_request
, что заставляет вас думать, что вы вызываете функциюmake_request_fn()
, но на самом деле вы вызываетеflash_dev_make_request()
.Это действительно базовый способ обеспечения инкапсуляции и полиморфизма и действительно базовая модель ООП в C.
Мне удалось добиться почти того, что я изначально хотел, используя пространства имен монтирования . (В моем первоначальном решении также использовался unionfs , но, как оказалось, он вообще не нужен ). Он используется для привязки -mount /bin/bash
к /bin/sh
для ограниченного набора процессов. Краткая процедура установки новой оболочки, где sh
— это bash
, описана ниже.
Сначала мы запускаем новую оболочку с изолированным пространством имен монтирования:
sudo unshare -m sudo -u user /bin/bash
А потом в новой оболочке привязываем -крепление /bin/bash
к/bin/sh
:
sudo mount --bind /bin/bash /bin/sh
Вот именно!
Посмотрим, что у нас в этой оболочке:
user@ubuntu:~$ /bin/sh --version
GNU bash, version...
user@ubuntu:~$ diff -s /bin/sh /bin/bash
Files /bin/sh and /bin/bash are identical
Но при работе в другой оболочке:
user@ubuntu:~$ /bin/sh --version
/bin/sh: 0: Illegal option --
user@ubuntu:~$ diff -s /bin/sh /bin/bash
Binary files /bin/sh and /bin/bash differ
user@ubuntu:~$ diff -s /bin/sh /bin/dash
Files /bin/sh and /bin/dash are identical
Скрипты, содержащие не -расширения POSIX, должны иметь соответствующий правильный заголовок #!
, в вашем случае:
#!/bin/bash
поэтому я не вижу возможности редактировать все некорректные скрипты.
Кстати, :если вы действительно уверены, вы можете создать временную ссылку на bash и переименовать ее:
cd /bin
ln -s bash nsh
mv nsh sh
Так как mv
работает атомарно, это гарантирует, что всегда будет рабочий/bin/sh
В результате сценарии и другие оболочки, работающие в настоящее время, пока вы выполняете переименование, продолжат работать, и после переименования будет вызываться bash вместо dash.
Однако, если ваша система работает таким образом, что позволяет редактировать сценарии, я предпочитаю редактировать только сценарии.
Если вы замените /bin/sh
ссылкой на bash
, не забудьте исправить это, чтобы после завершения /bin/sh
снова стал ссылкой на dash
.
Если рассматриваемые сценарии являются частью двоичного пакета, не забудьте отправить отчет об ошибке по этой проблеме своему восходящему потоку.
Вы можете легко исправить их, не ломайте свою систему!
find. -name '*.sh' -type f -exec sed -i '1s|^#! */bin/sh|#!/bin/bash|' {} +
Я полагаю, что пространства имен монтирования или что-то в этом роде можно использовать, чтобы у разных процессов/пользователей было разное представление о том, что /bin/sh
такое.
Но это звучит по-хакерски, а также может считаться «внесением постоянных изменений в систему». Вероятно, было бы проще просто исправить одну строку -. Сделайте это исправление частью вашего процесса обновления и опубликуйте отчет об ошибке и исправление о неправильном хеш-банге вверх по течению.
С GNU sed
что-то подобное должно делать, чтобы исправить их:
sed -i -e '1s,^#! */bin/sh,#!/bin/bash,' /all/the/scripts/*
Если/bin/sh
-> /bin/dash
является динамически подключаемым исполняемым файлом в вашей системе, как в моей (, вы можете проверить это с помощью файла (1 )), вы можете использовать для этого хак LD_PRELOAD
.
Это работает следующим образом :Небольшая динамическая библиотека, загруженная LD_PRELOAD
, переопределяет функцию glibc __libc_start_main
(, которая вызывает функцию main()
исполняемого файла ), и если argv[0] == /bin/sh
, то она /bin/bash
exec вместо этого с теми же аргументами (, за исключениемargv[0]
); в противном случае он обращается к исходному __libc_start_main
, как будто ничего не произошло.
$ cat sh_is_bash.c
#define _GNU_SOURCE /* for RTLD_NEXT */
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <err.h>
int __libc_start_main(
int (*main)(int,char**,char**), int ac, char **av,
int (*init)(int,char**,char**), void (*fini)(void),
void (*rtld_fini)(void), void *stack_end)
{
typeof(__libc_start_main) *real_lsm;
if(ac > 0 && !strcmp(av[0], "/bin/sh")){
av[0] = "/bin/bash";
execv(av[0], av);
err(1, "execv %s", av[0]);
}else if(real_lsm = dlsym(RTLD_NEXT, "__libc_start_main"))
return real_lsm(main, ac, av, init, fini, rtld_fini, stack_end);
else
errx(1, "BUG: dlsym: %s", dlerror());
}
$ cc -fPIC -shared -Wall -W -Wno-parentheses sh_is_bash.c -o sh_is_bash.so -ldl
$ LD_PRELOAD=`pwd`/sh_is_bash.so program...
Любой скрипт с шебангом #! /bin/sh
будет выполняться с /bin/bash
вместо /bin/sh
, если переменная окружения LD_PRELOAD
содержит абсолютный путь к sh_is_bash.so
.
Это уродливо, но не требует серьезных изменений ни в вашей системе, ни в скриптах, легко развертывается и управляется, и для этого не нужны никакие специальные привилегии.