Як я можу обманути процес думати, що файл не існує?


31

У мене є програма, в якій зберігаються її настройки ~/.config/myprogramщо я використовую як інтерактивно, так і з системою пакетної черги. Під час інтерактивного запуску я хочу, щоб ця програма використовувала мої файли конфігурації (і це робить). Але при запуску в пакетному режимі файли конфігурації не потрібні, оскільки я вказую параметри командного рядка, які перезаписують усі відповідні налаштування. Крім того, доступ до файлів конфігурації по мережі збільшує час запуску програми на кілька секунд; якщо файлів не існує, програма запускається набагато швидше (оскільки кожне завдання займає лише хвилину, це має значний вплив на пропускну здатність пакетної роботи). Але оскільки я також інтерактивно використовую програму, я не хочу постійно переміщувати / видаляти свої конфігураційні файли. Залежно від того, коли заплановані мої пакетні завдання в кластері (на основі використання інших користувачів),

(Вбік: продуктивність мережевих файлів настільки повільна, ймовірно, це помилка, але я просто користувач кластеру, тому я можу лише обійти його, а не виправити.)

Я міг би створити версію програми, яка не читає файли конфігурації (або має параметр командного рядка не робити) для пакетного використання, але середовище побудови цієї програми погано сконструйована і її важко налаштувати. Я вважаю за краще використовувати двійкові файли, встановлені через менеджер пакунків моєї системи.

Як я можу підманути окремі екземпляри цієї програми, роблячи вигляд, що мої файли конфігурації не існують (без зміни програми)? Я сподіваюся на обгортку форми pretendfiledoesntexist ~/.config/myprogram -- myprogram --various-options..., але я відкритий для інших рішень.


2
Ви можете запустити його як користувач, який не має дозволу на читання файлу.
psimon

1
@psimon Оскільки я просто "користувач" кластеру, я не можу створити нового користувача, який би міг запускати свою пакетну роботу. Це розумна ідея, і якщо немає кращих пропозицій, я помиляю адміністратора кластера, щоб зробити це для мене.
Джефрі Босбум

Або встановіть скрипт, який спочатку перейменовує конфігураційний файл, запустить програму, а потім знову перейменує конфігураційний файл.
psimon

@psimon Я думаю, що я міг би бути більш зрозумілим: я можу використовувати програму в інтерактивному режимі і в пакетному режимі одночасно, залежно від того, коли мої пакетні завдання плануються в кластері.
Джеффрі Босбум

1
Так, якщо його динамічно пов’язано, можна використовувати LD_PRELOADгачок. Це простіше (ви можете реалізувати це через годину чи дві, якщо ви знаєте С), ніж альтернатива, яка є ptrace. Ви можете, ймовірно, використовувати fakechroot для цього (що я вважаю, LD_PRELOAD).
дероберт

Відповіді:


33

Ця програма, ймовірно, вирішує шлях до цього файлу $HOME/.config/myprogram. Отже, ви можете сказати, що ваш домашній каталог знаходиться в іншому місці, наприклад:

HOME=/nowhere your-program

Тепер, можливо, вашій програмі потрібен якийсь інший ресурс у вашому домашньому каталозі. Якщо ви знаєте, що вони є, ви можете підготувати підроблену програму для своєї програми з посиланнями на потрібний їй ресурс.

mkdir -p ~/myprogram-home/.config
ln -s ~/.Xauthority ~/myprogram-home/
...
HOME=~/myprogram-home myprogram

5
Ця відповідь вирішує мою проблему, тому я прийняв її, навіть якщо це не зовсім загальна відповідь на запитання у назві цього питання. Гак попереднього завантаження, як описано в іншій відповіді, є більш загальним (але також і більш зусильним) рішенням.
Джефрі Босбум

28

Якщо все інше не LD_PRELOADвдалося , напишіть бібліотеку обгортки, яку ви будете вводити, використовуючи так, щоб виклик open("/home/you/my-program/config.interactive")перехопився, але будь-який інший пройде через. Це працює для будь-якого типу програми, навіть сценарії оболонки, оскільки вона буде фільтрувати системні виклики.

extern int errno;

int open(const char *pathname, int flags)
{
  char *config_path = get_config_file_path();
  if (!strstr(pathname, config_path))
  {
    return get_real_open(pathname, flags);
  }
  else
  {
    errno = ENOENT;
    return -1;
  }
}

Примітка. Я не перевіряв цей код, і я не впевнений, що errnoдеталь працює.

Подивіться, як fakerootце відбувається для дзвінків як getuid(2)і stat(2).

В основному, лінкер прив’яже цей додаток до вашої бібліотеки, що перекриває openсимвол. Оскільки ви не можете використовувати дві різні функції, названі openу вашій власній бібліотеці, вам доведеться відокремити її у другій частині (наприклад get_real_open), яка в свою чергу буде посилатися на вихідний openдзвінок.

Оригінал: ./Application

Application -----> libc.so
            open()

Перехоплений: LD_PRELOAD=yourlib_wrap.so ./Application

Application -----> yourlib_wrap.so --------------> yourlib_impl.so -----> libc.so
            open()                 get_real_open()                 open()

Редагувати: Мабуть , є ldпрапор, який можна включити ( --wrap <symbol>), що дозволяє писати обгортки, не вдаючись до подвійного посилання:

/* yourlib.c */
#include <stdio.h>

int __real_open(const char *pathname, int flags)

int __wrap_open(const char *pathname, int flags)
{
  char *config_path = get_config_file_path();
  if (!strstr(pathname, config_path))
  {
    /* the undefined reference here will resolve to "open" at linking time */
    return __real_open(pathname, flags);
  }
  else
  {
    errno = ENOENT;
    return -1; 
  }
}

2

Відсуньте свій конфігураційний файл убік і напишіть обгортку сценарію оболонки для інтерактивного випадку використання, який копіює файл у звичайне місце призначення, запускає програму та видаляє її при виході.


Дивіться мою останню редакцію: я не контролюю планування пакетів, тому я можу використовувати програму інтерактивно та одночасно як частину пакетної роботи.
Джеффрі Босбум

1

Це повинно бути можливим для unionfs / aufs. Ви створюєте chrootсередовище для процесу. Ви використовуєте реальний каталог як шар лише для читання, а поверх нього ставите порожній. Потім ви змонтуєте том об'єднань у відповідному каталозі в chrootоточенні та видалите файл. Процес цього не побачить, але всі інші.


0

Перейменуйте конфігураційний файл у напр config.interactive. Створіть ще один порожній файл, який називається напр config.script.

Тепер створіть м'яке посилання під назвою config(або все, що додаток очікує як файл конфігурації) в залежності від реального конфігурації, яке вам потрібно, та запустіть свою програму.

ln -s config.interactive config

Не забудьте згодом налагодити своє посилання.


Дивіться мою останню редакцію: я не контролюю планування пакетів, тому я можу використовувати програму інтерактивно та одночасно як частину пакетної роботи. Ця відповідь по суті те саме, що переміщувати файли вручну або за допомогою сценарію.
Джефрі Босбум

1
До! Мені потрібно швидше думати і набирати текст. Це велика програма? Чи можна його перенести до хротону та бігти звідти інтерактивно? Все залежить від того, з якою програмою взаємодіє, я думаю. Це також може бути дуже стомлюючим завданням, щоб все, що йому потрібно, було також перетворено в хроту. (Я думаю, що я говорив сам із цього варіанту!)
garethTheRed

0

Якщо ви точно охарактеризували, як ваша програма використовує файл конфігурації, я її не помітив. Багато програм (наприклад, bashта vi) перевіряють файл конфігурації відразу після запуску; якщо файл існує, прочитайте його та закрийте. Ці програми більше ніколи не отримують доступу до цих файлів ініціалізації. Якщо ваша програма така, читайте далі.

Я знаю, що ви відхилили відповіді, які роблять файл конфігурації справді неіснуючим (перейменувавши його), але у мене є зморшка, яку я не бачив, як запропонував ніхто інший. Зробіть це, коли ви викликаєте програму в пакетному режимі:

DELAY_TIME=1
REALPATH="~/.config/myprogram"
HOLDPATH="${REALPATH}.hold"

mv "$REALPATH" "$HOLDPATH"
(sleep "$DELAY_TIME"; mv "$HOLDPATH" "$REALPATH")&
myprogram

Це переміщує файл конфігурації з шляху, але потім переміщує його на секунду назад, навіть якщо myprogramвін все ще працює. Це створює дуже коротке вікно часу, протягом якого файл недоступний - яка ймовірність того, що ви будете інтерактивно запускати програму під час цього вікна? (Навіть якщо ви це зробите, ви можете просто вийти та перезапустити, і конфігураційний файл, ймовірно, повернеться на місце.)

Це створює перегони умови; якщо програмі потрібно занадто багато часу, щоб обійти файл, він може отримати реальний файл. Якщо це трапляється досить часто, це проблема, просто збільште значення DELAY_TIME.


1
Що найгірше, що може піти не так? Я буквально бачив, що це відбувається. У виробництві.
Хенк Лангевельд

-1

Я як відповідь Stephane, але це буде обдурити будь-яку програму, вважаючи , будь-який файл є порожнім - (тому що його dentry тимчасово вказує на файл , який на самому справі є порожнім) :

cat <./test.txt
###OUTPUT###
notempty

mount --bind /dev/null ./test.txt
cat <./test.txt
###NO OUTPUT###

umount ./test.txt
cat <./test.txt
###OUTPUT###
notempty

Ви також можете:

mount --bind ./someotherconfig.conf ./unwanted.conf

Якби ти хотів.


Це по суті еквівалентно пару попередніх відповідей (за винятком, я вважаю, для цього потрібна привілейованість користувача). ОП відхилив ці інші відповіді, оскільки не хоче обманювати жоден процес - він хоче обдурити пакетне виклик програми, дозволяючи інтерактивному виклику нормально переглядати конфігураційний файл.
Скотт

@Scott - я не погоджуюся - будь-яка інша відповідь перед цим рекомендувала деякі зміни щодо mvфайлу, - які можуть мати інші наслідки, ніж впливати на його зубну систему, наприклад, фактично обрізання файлу чи інших тощо, і т.д. Все-таки я повинен, unshareщо mountя здогадуюсь ...
mikeserv
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.