• Как привязать usb модем через udev symlink?

    tomat17
    @tomat17
    Ну, раз внятного ответа до сих пор нет, поделюсь я)

    И так, аналогичная ситуация, имеем 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)
    63241178a7185875682521.jpeg

    *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
    63241404c8417218133339.jpeg
    Проверяем "бинды"
    [root@localhost ~]# ls /dev/ | grep ttyModem
    ttyModem1
    ttyModem10
    ttyModem11
    ttyModem12
    ttyModem13
    ttyModem14
    ttyModem15
    ttyModem2
    ttyModem3
    ttyModem4
    ttyModem5
    ttyModem6
    ttyModem7
    ttyModem8
    ttyModem9


    PROFIT!

    Благодарю за внимание, надеюсь кому-то поможет =)
    Ответ написан
    1 комментарий