LINUX.ORG.RU

Звуковое уведомление о сети. C.

 , ,


1

4

По следам своей старой темы (Голосовое оповещение о поче (скрипт)) решил доработать скрипт. Суть все та же: Если теряем связь с ресурсом, то запускаем программу, которая:

  1. Единожды звуком (через beep) уведомляет о том, что сети нет.
  2. Продолжает работать в фоне, с интервалом (однократно) отправляя ping на ресурс.
  3. Если ресурс доступен, уведомляет звуком и завершает работу. Параметр 1 в аргументы задает бесконечный мониторинг ресурса. Уведомлять будет только при изменении состояния.

Видео для улучшения понимания того, как работает скрипт: https://youtu.be/jVtt_ol9S4g?si=Ztz2ki6YpBl2sR-M

Удобно поставить на cron при старте. Компилируется так:

gcc test_ip.c -o  test_ip.o

Первая версия (удалена).

Отредактированный вариант (перемещён на git): https://gitflic.ru/project/dcc0/test_ip_finite_machine/blob/?file=test_ip_Christmas.c&branch=test_ip.c

https://github.com/dcc0/finite_machine_test_ip/blob/main/test_ip_Christmas.c

Вариант bash с Curl для тестирования сайта: https://github.com/dcc0/finite_machine_test_ip/blob/main/test_web_new.sh



Последнее исправление: AnonymUser (всего исправлений: 35)

Вас не смущает ничего в следующих строчках?

char ip[100]="ping -c 1 ";

sprintf(ip, "%s%s", ip, argv[1]);

if(system(ip)==0)

P.S. Рекомендую отформатировать код перед вставкой хотя бы clang-format каким.

P.S.S. Можно для С и С++ использовать цветовую разметку - указав язык после трех одинарных кавычек - подробности тут Markdown

necromant ★★
()
Ответ на: комментарий от necromant

Что argv[1] указатель?! Или что источник ip в sprintf отновременно и «приемник»? Если так, то, конечно, можно подправить. Но для бытовых целей корретно работает. Как еще склеить две строки в C?! Вернее, строку и указатель… :) Тогда мне только это в голову пришло. Может, вообще без этого можно. Я только такой способо нашел в свое время.

И ip не int… безусловно.

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 3)
Ответ на: комментарий от necromant
if(system(ip)==0)

В условии вроде смысл 0 эквив. false. Во всяком случае работает. Я, конечно, не отрицаю, что мог недодумать что-то. Или просто знаний где-то не хватило. Если результат работы функции system 0 или что в общем-то трактуется как false, то… Но в общем работает как ожидается. Или я что-то недопонял.

Но sprintf я подправил.

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 3)

Блин, ну что мешает по-человечески - запускать программу по заранее предопределенному пути или переданную в параметре? К чему этот дурацкий хардкод? А если завтра я не захочу звук, а захочу отправлять сигнал в dbus? А этот сигнал будут слушать разные программы и что-то делать

cobold ★★★★★
()
Ответ на: комментарий от cobold

Ничего не понял. Это довольно бытовая штука. Смысл такой: если тебе надо отойти от компа и вернуться, когда будет сигнал о доступности. Когда сигнал будет программа остановится.
Но есть выбор, если надо крутить бесконечно.

Она и запускается с параметром.

Если надо, сделай, как тебе нужно.

AnonymUser
() автор топика

Что мешает делать тоже самое штатными средствами? зачем нужен какой-то ресурс и сложный код на сишке в придачу? Оно еще и по крону запускается. Этой теме срочно нужен тег «я познаю мир».

Clockwork ★★★★★
()
Последнее исправление: Clockwork (всего исправлений: 1)
Ответ на: комментарий от Clockwork

Можно не по крону. Можно руками. Как хочешь.

И важно: понимают ли читающие условие задачи?!

Штатных средств нет. Я не знаю во всяком случае.

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 1)
Ответ на: комментарий от firkax

Конструкция sprintf(str, «%s...», str, ...) рабочая, хоть и некрасивая.

эта конструкция - двойной хит ! мало того что длина строку не контроллируется, и в параметрах непосредственно argv[1]. Можно прямо из командной строки поломать стек. Так ещё результат потом неэкраннированно уходит в system(). Просто прекрасно ..

как-то так вот

./a.out "127.0.0.1&&rm -rf /"

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

А, ну это то конечно да, в коде много разных проблем. Я подумал что там претензия к тому что первый и третий аргументы совпадают почему-то.

firkax ★★★★★
()

я невооруженным пьяным глазом нашел как минимум две дыры в твоем говнокоде, при этом я не программист и не сишник.

зачем тут вообще си, если вызывается внешний башскрипт, еще и захардкоженный?
возьми питон, или там луа, перл, шелл, на худой конец.

«не можешь срать — не мучай жопу».

ann_eesti
()
Ответ на: комментарий от AnonymUser

С точки зрения безопасной работы программы желательно snprintf использовать. Для ip 100 байт выделили, а если с argv[1] прилезет больше ста байт?

Вызов system напряг тем, что почти напрямую ему передаётся argv[1] без проверки корректности. Понятно, что для себя так пойдет, но вы код опубликовали, соответственно желательно соблюдать хорошие практики защитного программирования - никогда не доверять входным параметрам.

necromant ★★
()
Последнее исправление: necromant (всего исправлений: 1)

Хтонично.

Его мутный взгляд упал на результаты вчерашнего кулинарного эксперимента. Овощной суп на дрожжах — что за БЛЕСТЯЩАЯ идея! Из тех, что кажутся блестящими исключительно часа в два ночи, после того как хорошенько наберешься.

Когда он вспомнил другие порождения столь же насыщенных ночей, его передернуло. Один раз это были спагетти с горчицей. Жареный горох тоже оставил массу незабываемых впечатлений. А однажды ему показалось, что нет ничего лучше, чем съесть муку с дрожжами и запить теплой водичкой. Тогда у него как раз кончился хлеб. В конце концов, желудок ведь все равно расщепляет продукты на составляющие? В такие моменты все кажется чрезвычайно разумным. В полночной кулинарии присутствует своя неоспоримая логика. Просто эта логика не дневная.

leave ★★★★★
()
Ответ на: комментарий от AnonymUser

Причём тут main в конце? Я не про положение функции а про бардак внутри неё.

firkax ★★★★★
()
Ответ на: комментарий от anonymous

Нет, объявлять переменные в Си надо после открывающей фигурной скобки, желательно той что в начале функции, и до любого императивного кода. Несмотря на то, что современные компиляторы позволяют устраивать помойку и объявлять переменные где попало, делать так не следует. А если ты страдаешь от того, что начало функции слишком далеко от места использования переменной - наверно надо поделить эту функцию на несколько более коротких.

firkax ★★★★★
()
Ответ на: комментарий от firkax

Если я объявляю переменную и сразу присваиваю argv[X] ей, а только потом проверяю, то как-то странно получается. Тут обсуждали: https://www.opennet.ru/openforum/vsluhforumID9/10121.html#13

Если следовать этому правилу фигурной скобки (с argv), то получается:

  1. Сначала объявить
  2. Проверить argv
  3. Затем присловить argv переменной
AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 2)

ЛОР-овцам не нравится. Переделывай.

anonymous
()
Ответ на: комментарий от blex

Очень много всего вскрылось в одном топе :) И технического, и не технического. Каждый, наверное, о себе что-то узнал.

Тоже не задумывался над таким хаком.

НГ творит чудеса. :)

P.S.

AnonymUser
() автор топика
Ответ на: комментарий от AnonymUser

Для минимальной защиты приходит в голову только проверить количество пробелов.

просто не используй вызов system(). Если уж вызывать внешнюю программу, то есть семейка execXX() https://man7.org/linux/man-pages/man3/exec.3.html

заодно и sprintf станет ненужен

MKuznetsov ★★★★★
()

Возьми shell, не страдай. Анонимус в первом комментарии все правильно написал.

gaylord
()
Ответ на: комментарий от firkax

Несмотря на то, что современные компиляторы позволяют устраивать помойку и объявлять переменные где попало, делать так не следует

Ты в прошлом треде так и не смог обосновать, почему в начале не помойка, а по месту использования – помойка. Потому что так-то конечно же наоборот – помойка из кучи переменных в начале функции ничего не добавляет в плане читаемости.

gaylord
()
Ответ на: комментарий от gaylord

Помойка не от количества а от того что алгоритм перемешан с объявлениями. Начало функции можно целиком пропустить и смотреть туда тогда когда надо, а алгоритм, не замусоренный всякими int, char и прочими типами, выглядит намного лучше. Ну и ещё - если у тебя в начале функции прямо «куча» переменных - надо подумать о разделении её (функции) на более маленькие. Если начало функции оказывается слишком далеко от конца - тоже.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 2)
Ответ на: комментарий от firkax

Помойка не от количества а от того что алгоритм перемешан с объявлениями. Начало функции можно целиком пропустить и смотреть туда тогда когда надо, а алгоритм, не замусоренный всякими int, char и прочими импам, выглядит намного лучше. Ну и ещё - если у тебя в начале функции прямо «куча» переменных - надо подумать о разделении её на более маленькие.

Эм… Ну вот давай сравним.

Объявления в начале:

static void bleh(void)
{
	struct foobar *f;
	struct bar *b;
	int i, ret;

	f = foobar_new();
	if (!f)
		errx(1, "cannot create f");

	b = bar_new();
	if (!b)
		errx(1, "cannot create b");

	for (i = 0; i < b->nr_somethings; ++i) {
		ret = f->ops->do(&b->somethings[i]);
		if (ret)
			errx(1, "cannot do something: %d", ret);
	}

	foobar_free(f);
	bar_free(b);
}

Объявления где надо:

static void bleh(void)
{
	struct foobar *f = foobar_new();
	if (!f)
		errx(1, "cannot create f");

	struct bar *b = bar_new();
	if (!b)
		errx(1, "cannot create b");

	for (int i = 0; i < b->nr_somethings; ++i) {
		int ret = f->ops->do(&b->somethings[i]);
		if (ret)
			errx(1, "cannot do something: %d", ret);
	}

	foobar_free(f);
	bar_free(b);
}

Мне первое нравится больше исключительно в силу синдрома утенка, но это чистая вкусовщина. Читаемость кода не изменилась.

В C23 появился auto и теперь все ваще хорошо:

static void bleh(void)
{
	auto f = foobar_new();
	if (!f)
		errx(1, "cannot create f");

	auto b = bar_new();
	if (!b)
		errx(1, "cannot create b");

	for (auto i = 0; i < b->nr_somethings; ++i) {
		auto ret = f->ops->do(&b->somethings[i]);
		if (ret)
			errx(1, "cannot do something: %d", ret);
	}

	foobar_free(f);
	bar_free(b);
}
gaylord
()
Последнее исправление: gaylord (всего исправлений: 1)
Ответ на: комментарий от firkax

Я тоже так подумал, но сначала час ковырялся. Потом заглянул в ман :)

Но выполение доп. кода я убрал.

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 1)
Ответ на: комментарий от gaylord

Если брать только этот кусок сферически в вакууме, то читаемость и правда не сильно изменилась - он и так и так максимально простой. Но когда такого кода тысячи и десятки тысяч строк, это утомляет. Собственно, конкретно программа автора может быть оформлена как угодно, хоть без форматирования вообще - она и так и так простая, но лучше сразу привыкать к хорошему оформлению.

А ещё в первом присваивание можно засунуть внутрь if():

static void bleh(void)
{
	struct foobar *f;
	struct bar *b;
	int i, ret;

	if (!(f = foobar_new()))
		errx(1, "cannot create f");

	if (!(b = bar_new()))
		errx(1, "cannot create b");

	for (i = 0; i < b->nr_somethings; ++i)
		if (ret = f->ops->do(&b->somethings[i]))
			errx(1, "cannot do something: %d", ret);

	foobar_free(f);
	bar_free(b);
}
И в таком виде читаемость уже заметно лучше: каждый условный оператор сразу показывает, какое выражение мы проверяем, не надо возвращаться глазами на строчку вверх после того как видишь if. И в целом: теперь весь код по сути влезает в 3 хорошо различимых и тривиальных строчки (если убрать переносы строк после for() и if()) + 2 строчки с чисткой, а в оригинале он выглядел как алгоритм.

В C23 появился auto и теперь все ваще хорошо:

Я бы не сказал. Теперь, чтобы узнать, какого типа переменные f и b, придётся искать прототипы нужных функций, которые в общем случае (если человек видит этот код в первый раз, например) неизвестно где. Хотя конкретно у тебя эти функции выглядят как конструкторы динамических структур и тип скорее всего можно угадать, но в общем случае это не так. А ещё может так случиться, что тип возврата какой-то функции поменяют вместе с семантикой её использования вообще, рассчитывая на то, что в местах, где он используется, код сломается, компилятор выдаст ошибку и всё можно будет поправить, но из-за auto этого не случится и в коде появится баг.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 3)
Ответ на: комментарий от firkax

Редакторы бывают разные. IDE скорее показывает, а просто редактор скорее нет.

Мой просто редактор (neovim) показывает. Я могу себе представить кодовые базы, где такое скорее вредит, чем помогает, но средний проект на C, где все нужное для LSP генерится meson/cmake, это вообще не касается.

gaylord
()
Последнее исправление: gaylord (всего исправлений: 1)

это элементарщина, в любой книге по с++ в первых главах пишут что надо объявлять только перед употреблением для уменьшения области видимости поэтому и в for отдельная переменная i прямо в цикле

anonymous
()
Ответ на: комментарий от AnonymUser

execl вроде ничего не возвращает, судя по ману.

если exec хоть что-то вернул (вообще вернулся), то это ошибка :-)

MKuznetsov ★★★★★
()
Ответ на: комментарий от firkax

придётся искать прототипы нужных функций

В IDE это делается одним хоткеем.

но из-за auto этого не случится и в коде появится баг

Просто сишка — слаботипизированный язык. Ей пора на покой. А за попытку на ней начинать писать новый софт нужно обкалывать транквилизаторами.

ox55ff ★★★★★
()
Ответ на: комментарий от firkax

в таком виде читаемость уже заметно лучше

в этом виде читаемость никакая и сообщения про ошибки ни о чём. И ещё память утекает.

вы возможно тайно завидуете лисперам, что любите вложенность скобок и не контролируете память

о том что foobar_new() не вышел, надо было верещать в самом foobar_new - там и причину можно назвать.

объявления временных i ret не нужны (вредны) в начале - они не формируют контекст. Человек будет читать код, разбирая алгоритм - нахрен ему i,ret?

функция что-то делает с foo *f, bar *b и ещё с чем-то..вот они детально и описываются в начале;

какой коммент потенциально можно дать переменной i..«впердолено чтобы внизу использовать как счётчик цикла»? если цикл поменяется на while - функцию в двух местах патчить ??

MKuznetsov ★★★★★
()
Ответ на: комментарий от MKuznetsov

Согласен с тем, что ret можно убрать. Может быть, нужно.

  for (int i = 0; i != max_len; i++) {

Так в итоге: так лучше, чем объявлять int i после фигурной скобки?!

AnonymUser
() автор топика
Ответ на: комментарий от ox55ff

Я сделал на C то что хотел сделать. Можно отправлять, конечно. Но вряд ли, мне так кажется. То, что хорошо стандартизировано, вряд ли совсем уснёт.

AnonymUser
() автор топика

Пустая строка (два раза Enter) начинает новый абзац. Знак '>' в начале абзаца выделяет абзац курсивом цитирования.
Внимание: прочитайте описание разметки Markdown.
Используйте Ctrl-Enter для размещения комментария