Ну, раз внятного ответа до сих пор нет, поделюсь я)
И так, аналогичная ситуация, имеем 15 модемов, все определяются как близнецы братья, в udevadm info никаких различий нет, значит биндить будем по номеру ttyUSB с привязкой к IMEI.
Нам понадобится:
PHP
ATCom
SMS демон, в моем случае
SMS Server Tools 3
И так логика следующая: отваливается модем, демон после ошибки запускает "alarmhandler" (в моём случае он просто килит свой же процесс), cron проверяет запущен ли демон, если нет то запускает скрипт для бинда модемов и перезапуска смс демона.
Конфиг демона:
devices = #список девайсов
logfile = /var/log/sms/smsd.log
loglevel = 5
alarmlevel = 3
alarmhandler = /usr/local/bin/smserror.sh
failed = /var/spool/sms/failed
blacklist = /var/spool/sms/blacklist
report = /var/spool/sms/report
incoming = /var/spool/sms/incoming
stats = /var/log/sms/smsd_stats
[B0818760]
device = /dev/ttyModem1
incoming = yes
queues = B0818760
logfile = /var/log/sms/B0818760.log
loglevel = 5
#и т.д. все устройства
smserror.sh
#!/bin/sh
killall -9 smsd
checkSmsDaemon.sh - скрипт для проверки работы демона и бинда модемов, запускается кроном
#!/bin/sh
COUNT=`ps aux | grep smsd | grep -v grep | wc -l`
if [ $COUNT -lt 2 ];
then
#запускаем скрипт через flock, чтобы не создать "петлю" параллельным выполнением
flock -w0 /tmp/tp.lock /usr/local/bin/testPorts.sh
fi
testPorts.sh - вся магия происходит тут)
#!/bin/bash
dev=($(ls /dev | grep ttyUSB)) #массив имен устройств
obj="" #сюда будем складывать связки IMEI => порт
for i in ${dev[@]}; do
#запрос IMEI у модема, для моих Huawei e171 это ATI (пример ответа на скрине ниже)
RESP=$(/usr/local/bin/atcom --port /dev/$i ATI)
#парсим ответ с помощью php скрипта
imei=$(curl --connect-timeout 3 -s -d "data=$RESP" -X POST http://localhost/ajax/parseIMEI.php)
#проверяем ответ по длине строки
if [[ $(expr length $imei) -gt 5 ]];
then
#вывод в консоль, хоть для какой то визуализации)
echo $imei $i
#добавляем "связку" в массив
obj+=$imei:$i,
fi
done
#отправляем "объект" imei и портов в php скрипт для создания правил
rules=$(curl -s -d "data=$obj" -X POST http://localhost/ajax/createRule.php)
#записываем ответ в файл правила udevatm
echo -e $rules > /etc/udev/rules.d/02-modems_conformity.rules
#обновляем правила
sudo udevadm control --reload-rules
#биндим устройства
udevadm trigger
#запускаем смс демона
/etc/init.d/sms3 restart
RESP=$(/usr/local/bin/atcom --port /dev/$i ATI)
*PHP для парсинга я выбрал, т.к. у меня для смс сервиса написан собственный веб интерфейс и php уже установлен. Парсить можно чем угодно, хоть прямо в этом скрипте, но я не фанат работы со строками в bash.
parseIMEI.php
<?php
$data = $_POST['data'];
if (strpos($data, 'IMEI') !== false) {
echo substr($data, strpos($data, 'IMEI: ') + 6, 15);
} else {
echo 0;
}
createRule.php
<?php
$data = $_POST['data'];
$arr = array_slice(explode(',', $data), 0, -1);
$ports = [ //здесь IMEI привязывается к имени устройства
'3548070428.....' => 'ttyModem1',
'3548070428.....' => 'ttyModem2',
'3548070413.....' => 'ttyModem3',
'3548070428.....' => 'ttyModem4',
'3548070428.....' => 'ttyModem5',
'3548070455.....' => 'ttyModem6',
'3548070455.....' => 'ttyModem7',
'3548070455.....' => 'ttyModem8',
'3548070428.....' => 'ttyModem9',
'3548070428.....' => 'ttyModem10',
'8631150121.....' => 'ttyModem11',
'8631150125.....' => 'ttyModem12',
'8631150124.....' => 'ttyModem13',
'8614960137.....' => 'ttyModem14',
'8631150124.....' => 'ttyModem15',
];
$rule = '';
foreach ($arr as $v) {
$a = explode(':', $v);
$rule .= getRule($a[1], $ports[$a[0]]);
}
echo $rule;
function getRule($kerlen, $link) //создаю 2 строки, т.к. у меня модемы одной модели, но разных ревизий, и имеют разный idProduct
{
$str = 'SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="' . $kerlen . '", SYMLINK+="' . $link . '"\n';
$str .= 'SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="' . $kerlen . '", SYMLINK+="' . $link . '"\n';
return $str;
}
В результате работы php скрипта возвращается строка правила, для дальнейшей записи:
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB0", SYMLINK+="ttyModem2"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB0", SYMLINK+="ttyModem2"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB12", SYMLINK+="ttyModem11"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB12", SYMLINK+="ttyModem11"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB15", SYMLINK+="ttyModem3"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB15", SYMLINK+="ttyModem3"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB18", SYMLINK+="ttyModem4"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB18", SYMLINK+="ttyModem4"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB19", SYMLINK+="ttyModem8"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB19", SYMLINK+="ttyModem8"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB21", SYMLINK+="ttyModem10"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB21", SYMLINK+="ttyModem10"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB24", SYMLINK+="ttyModem9"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB24", SYMLINK+="ttyModem9"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB28", SYMLINK+="ttyModem5"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB28", SYMLINK+="ttyModem5"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB3", SYMLINK+="ttyModem7"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB3", SYMLINK+="ttyModem7"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB33", SYMLINK+="ttyModem6"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB33", SYMLINK+="ttyModem6"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB36", SYMLINK+="ttyModem14"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB36", SYMLINK+="ttyModem14"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB39", SYMLINK+="ttyModem13"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB39", SYMLINK+="ttyModem13"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB42", SYMLINK+="ttyModem15"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB42", SYMLINK+="ttyModem15"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB6", SYMLINK+="ttyModem12"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB6", SYMLINK+="ttyModem12"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1001", KERNEL=="ttyUSB9", SYMLINK+="ttyModem1"
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1506", KERNEL=="ttyUSB9", SYMLINK+="ttyModem1"
Результат запуска
testPorts.sh
Проверяем "бинды"
[root@localhost ~]# ls /dev/ | grep ttyModem
ttyModem1
ttyModem10
ttyModem11
ttyModem12
ttyModem13
ttyModem14
ttyModem15
ttyModem2
ttyModem3
ttyModem4
ttyModem5
ttyModem6
ttyModem7
ttyModem8
ttyModem9
PROFIT!
Благодарю за внимание, надеюсь кому-то поможет =)