LINUX.ORG.RU

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

 , ,


2

5

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

  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_website.sh



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

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

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 ★★★★★
()

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

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

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

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

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

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

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

Хтонично.

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

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

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

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

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

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

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

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

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

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

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

P.S.

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

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

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

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

MKuznetsov ★★★★★
()
Ответ на: комментарий от 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)
Ответ на: комментарий от 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
()
Ответ на: комментарий от firkax

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

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

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

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

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

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

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

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

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

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

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

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

MKuznetsov ★★★★★
()