Compare commits
No commits in common. "dev" and "master" have entirely different histories.
|
@ -19,29 +19,7 @@
|
||||||
"cstdint": "c",
|
"cstdint": "c",
|
||||||
"fcntl.h": "c",
|
"fcntl.h": "c",
|
||||||
"file.h": "c",
|
"file.h": "c",
|
||||||
"dir.h": "c",
|
"dir.h": "c"
|
||||||
"mportlink-core.h": "c",
|
|
||||||
"mportlink.h": "c",
|
|
||||||
"mportlink-lib.h": "c",
|
|
||||||
"errno.h": "c",
|
|
||||||
"stdlib.h": "c",
|
|
||||||
"string.h": "c",
|
|
||||||
"libudev.h": "c",
|
|
||||||
"mpl-lib.h": "c",
|
|
||||||
"mpl-core.h": "c",
|
|
||||||
"mpl.h": "c",
|
|
||||||
"mpl-udev.h": "c",
|
|
||||||
"mpl-args.h": "c",
|
|
||||||
"*.in": "cpp",
|
|
||||||
"signal.h": "c",
|
|
||||||
"stdio.h": "c",
|
|
||||||
"getopt.h": "c",
|
|
||||||
"mpl-common.h": "c",
|
|
||||||
"cerrno": "c",
|
|
||||||
"string": "c",
|
|
||||||
"string_view": "c",
|
|
||||||
"regex.h": "c",
|
|
||||||
"dirent.h": "c"
|
|
||||||
},
|
},
|
||||||
"cmake.configureOnOpen": false
|
"cmake.configureOnOpen": false
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
"-fdiagnostics-color=always",
|
"-fdiagnostics-color=always",
|
||||||
"-g",
|
"-g",
|
||||||
"*.c",
|
"*.c",
|
||||||
"`pkg-config", "--libs", "udev`",
|
"`pkg-config", "--libs", "--cflags", "mm-glib`",
|
||||||
"-o",
|
"-o",
|
||||||
"${workspaceFolder}/bin/mportlink"
|
"${workspaceFolder}/bin/mportlink"
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## [Unreleased]
|
## [0.2.0](https://github.com/AlexanderZhirov/MPortLink/compare/0.1.0...v0.2.0)
|
||||||
### Changed
|
|
||||||
- The code is rewritten from scratch, based on `udev`
|
|
||||||
|
|
||||||
## [0.2.0](https://github.com/AlexanderZhirov/MPortLink/compare/0.1.0...0.2.0)
|
|
||||||
### Changed
|
### Changed
|
||||||
- Creation of links to ports has been moved to the directory `/dev/dongle`
|
- Creation of links to ports has been moved to the directory `/dev/dongle`
|
||||||
|
|
||||||
|
|
|
@ -1,42 +1,15 @@
|
||||||
cmake_minimum_required(VERSION 3.18.4)
|
cmake_minimum_required(VERSION 3.18.4)
|
||||||
project(mportlink)
|
project(mportlink)
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Os")
|
|
||||||
|
|
||||||
set(VERSION_MAJOR 0)
|
|
||||||
set(VERSION_MINOR 1)
|
|
||||||
set(VERSION_PATCH 0)
|
|
||||||
string(TIMESTAMP CURRENT_YEAR "%y" UTC)
|
|
||||||
string(TIMESTAMP DAY_OF_YEAR "%j" UTC)
|
|
||||||
|
|
||||||
string(CONCAT BASEVERSION "${VERSION_MAJOR}" "." "${VERSION_MINOR}" "." "${VERSION_PATCH}")
|
|
||||||
string(CONCAT BUILDVERSION "${BASEVERSION}" "." "${CURRENT_YEAR}" "${DAY_OF_YEAR}")
|
|
||||||
|
|
||||||
execute_process(
|
|
||||||
COMMAND git describe HEAD
|
|
||||||
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
|
|
||||||
OUTPUT_VARIABLE GIT_VERSION
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
ERROR_QUIET
|
|
||||||
)
|
|
||||||
|
|
||||||
if(GIT_SHORT_HASH STREQUAL "")
|
|
||||||
set(VERSION "${BUILDVERSION}")
|
|
||||||
else()
|
|
||||||
set(VERSION "${GIT_VERSION}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_definitions(-DVERSION="${VERSION}")
|
|
||||||
|
|
||||||
file(GLOB_RECURSE SRC_FILES_LIST src/*.c)
|
file(GLOB_RECURSE SRC_FILES_LIST src/*.c)
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
|
|
||||||
pkg_search_module(UDEV REQUIRED libudev)
|
pkg_search_module(MM REQUIRED mm-glib)
|
||||||
|
|
||||||
include_directories(${UDEV_INCLUDE_DIRS})
|
include_directories(${MM_INCLUDE_DIRS})
|
||||||
link_directories(${UDEV_LIBRARY_DIRS})
|
link_directories(${MM_LIBRARY_DIRS})
|
||||||
add_definitions(${UDEV_CFLAGS_OTHER})
|
add_definitions(${MM_CFLAGS_OTHER})
|
||||||
|
|
||||||
add_executable(${PROJECT_NAME} ${SRC_FILES_LIST})
|
add_executable(${PROJECT_NAME} ${SRC_FILES_LIST})
|
||||||
target_link_libraries(${PROJECT_NAME} ${UDEV_LIBRARIES})
|
target_link_libraries(${PROJECT_NAME} ${MM_LIBRARIES})
|
||||||
|
|
32
README.md
32
README.md
|
@ -1,24 +1,42 @@
|
||||||
# MPortLink
|
# MPortLink
|
||||||
|
|
||||||
[![license](https://img.shields.io/github/license/AlexanderZhirov/mportlink.svg?sort=semver&style=for-the-badge&color=green)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.html)
|
|
||||||
[![main](https://img.shields.io/badge/dynamic/json.svg?label=git.zhirov.kz&style=for-the-badge&url=https://git.zhirov.kz/api/v1/repos/alexander/MPortLink/tags&query=$[0].name&color=violet&logo=C)](https://git.zhirov.kz/alexander/MPortLink)
|
|
||||||
[![githab](https://img.shields.io/github/v/tag/AlexanderZhirov/mportlink.svg?sort=semver&style=for-the-badge&color=blue&label=github&logo=C)](https://github.com/AlexanderZhirov/mportlink)
|
|
||||||
[![linux](https://img.shields.io/badge/Linux-FCC624?style=for-the-badge&logo=linux&logoColor=black)](https://www.linux.org/)
|
|
||||||
|
|
||||||
**MPortLink** (*modem port link*) is designed to track connected USB modems and create permanent symbolic links to ports.
|
**MPortLink** (*modem port link*) is designed to track connected USB modems and create permanent symbolic links to ports.
|
||||||
|
|
||||||
MPortLink was developed for direct use of several USB modems when connected to Asterisk telephony, the ports of which were randomly determined by the operating system. The utility allows you to create permanent symbolic links to devices, regardless of the order in which the ports of the USB modem device were defined.
|
MPortLink was developed for direct use of several USB modems when connected to Asterisk telephony, the ports of which were randomly determined by the operating system. The utility allows you to create permanent symbolic links to devices, regardless of the order in which the ports of the USB modem device were defined.
|
||||||
|
|
||||||
|
Based on [ModemManager](https://gitlab.freedesktop.org/mobile-broadband/ModemManager).
|
||||||
|
|
||||||
|
## Dependency
|
||||||
|
|
||||||
|
The installed `modemmanager` is required for use.
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
Just need to run the script `build.sh `and `mportlink` will be built in the `build` project directory.
|
`libmm-glib` library is required for the build. It is called differently in different distributions, for example: `libmm-glib-dev` or `libmm-glib-devel`.
|
||||||
|
|
||||||
|
After installing the dependencies, you just need to run the script `build.sh `and `mportlink` will be built in the `build` project directory.
|
||||||
|
|
||||||
### Manually
|
### Manually
|
||||||
|
|
||||||
```
|
```
|
||||||
gcc -Werror -Wall -Os src/*.c `pkg-config --libs libudev` -o mportlink
|
gcc -Werror -Wall -Os src/*.c `pkg-config --libs --cflags mm-glib` -o mportlink
|
||||||
```
|
```
|
||||||
|
|
||||||
## Using
|
## Using
|
||||||
|
|
||||||
Superuser rights are required to work. Start the daemon and connect your USB modem. In `journalctl` you will see his work. Links to the ports of the connected modem will be created in the `/dev/dongle` directory.
|
Superuser rights are required to work. Start the daemon and connect your USB modem. In `journalctl` you will see his work. Links to the ports of the connected modem will be created in the `/dev/dongle` directory.
|
||||||
|
|
||||||
|
```
|
||||||
|
Dec 21 13:51:02 solus mportlink[17764]: main: starting the mportlink daemon
|
||||||
|
Dec 21 13:51:26 solus mportlink[17764]: mpl_symlink_ports, dst_path: the symbolic link has been successfully created [/dev/dongle/358**********26-0 -> /dev/ttyUSB0]
|
||||||
|
Dec 21 13:51:26 solus mportlink[17764]: mpl_symlink_ports, dst_path: the symbolic link has been successfully created [/dev/dongle/358**********26-1 -> /dev/ttyUSB1]
|
||||||
|
Dec 21 13:51:41 solus mportlink[17764]: mpl_unlink_ports, dst_path: link was successfully deleted [/dev/dongle/358**********26-0]
|
||||||
|
Dec 21 13:51:41 solus mportlink[17764]: mpl_unlink_ports, dst_path: link was successfully deleted [/dev/dongle/358**********26-1]
|
||||||
|
Dec 21 13:51:48 solus mportlink[17764]: signals_handler: cancelling the operation...
|
||||||
|
Dec 21 13:51:48 solus mportlink[17764]: signals_handler: cancelling the main loop...
|
||||||
|
Dec 21 13:51:48 solus mportlink[17764]: main: stopping the mportlink daemon
|
||||||
|
```
|
||||||
|
|
||||||
|
## To-Do
|
||||||
|
|
||||||
|
Currently, the utility is linked to the ModemManager server, through which the connected modems are identified. It is planned to disconnect from this server, as there is a problem with the capture of the device and the unavailability of using Asterisk.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[Unit]
|
[Unit]
|
||||||
Description=Modem Port Link
|
Description=Modem Port Link
|
||||||
After=
|
After=ModemManager.service
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
ExecStart=/usr/bin/mportlink
|
ExecStart=/usr/bin/mportlink
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
#include "mportlink.h"
|
||||||
|
|
||||||
|
MMManager *mmcli_get_manager_finish(GAsyncResult *res)
|
||||||
|
{
|
||||||
|
return g_task_propagate_pointer(G_TASK(res), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void manager_new_ready(GDBusConnection *connection, GAsyncResult *res, GTask *task)
|
||||||
|
{
|
||||||
|
MMManager *manager;
|
||||||
|
gchar *name_owner;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
manager = mm_manager_new_finish(res, &error);
|
||||||
|
if (!manager)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "manager_new_ready, manager: couldn't create manager: %s\n", error ? error->message : "unknown error");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
name_owner = g_dbus_object_manager_client_get_name_owner(G_DBUS_OBJECT_MANAGER_CLIENT(manager));
|
||||||
|
if (!name_owner)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "manager_new_ready, name_owner: couldn't find the ModemManager process in the bus");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(name_owner);
|
||||||
|
|
||||||
|
g_task_return_pointer(task, manager, g_object_unref);
|
||||||
|
g_object_unref(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mmcli_get_manager(GDBusConnection *connection, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
|
||||||
|
{
|
||||||
|
GTask *task;
|
||||||
|
|
||||||
|
task = g_task_new(connection, cancellable, callback, user_data);
|
||||||
|
|
||||||
|
mm_manager_new(connection, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START, cancellable, (GAsyncReadyCallback)manager_new_ready, task);
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#include <libmm-glib.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
MMManager *manager;
|
||||||
|
GCancellable *cancellable;
|
||||||
|
} Context;
|
||||||
|
|
||||||
|
MMManager *mmcli_get_manager_finish(GAsyncResult *res);
|
||||||
|
void mmcli_get_manager(GDBusConnection *connection, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
|
111
src/mpl-common.c
111
src/mpl-common.c
|
@ -1,111 +0,0 @@
|
||||||
/*
|
|
||||||
* mpl-common.c
|
|
||||||
*
|
|
||||||
* by Alexander Zhirov (alexander@zhirov.kz)
|
|
||||||
* Telegram @alexanderzhirov
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "mpl-common.h"
|
|
||||||
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/file.h>
|
|
||||||
|
|
||||||
#define LOCKFILE "/run/lock/mportlink.lock"
|
|
||||||
|
|
||||||
static int mpl_create_dongle_dir()
|
|
||||||
{
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
if (stat(MPL_DONGLE_PATH, &st) == 0)
|
|
||||||
{
|
|
||||||
if (!S_ISDIR(st.st_mode))
|
|
||||||
{
|
|
||||||
MPLOG(LOG_WARNING, "%s exists and is not a directory", MPL_DONGLE_PATH);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (mkdir(MPL_DONGLE_PATH, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1)
|
|
||||||
{
|
|
||||||
MPLOG(LOG_ERR, "unable to create a directory %s", MPL_DONGLE_PATH);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void static mpl_free(MPL *mpl)
|
|
||||||
{
|
|
||||||
if (mpl)
|
|
||||||
free(mpl);
|
|
||||||
}
|
|
||||||
|
|
||||||
MPL *mpl_init(MPL_PARAMETERS *parameters)
|
|
||||||
{
|
|
||||||
MPL *mpl = (MPL *)calloc(1, sizeof(MPL));
|
|
||||||
|
|
||||||
if (!mpl)
|
|
||||||
{
|
|
||||||
MPLOG(LOG_ERR, "error getting the MPL structure");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
mpl->parameters.check_device = parameters->check_device;
|
|
||||||
mpl->cancellable.signal = 0;
|
|
||||||
mpl->cancellable.exit = 0;
|
|
||||||
|
|
||||||
mpl->fd = open(LOCKFILE, O_CREAT | O_RDWR, 0644);
|
|
||||||
if (mpl->fd < 0)
|
|
||||||
{
|
|
||||||
MPLOG(LOG_ERR, "unable to create a lockfile");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int rc = flock(mpl->fd, LOCK_EX | LOCK_NB);
|
|
||||||
if (rc || errno == EWOULDBLOCK)
|
|
||||||
{
|
|
||||||
MPLOG(LOG_ERR, "only one instance of %s is allowed", MPL_NAME);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mpl_create_dongle_dir())
|
|
||||||
{
|
|
||||||
MPLOG(LOG_ERR, "%s will be stopped", MPL_NAME);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mpl_udev_init(&mpl->udev))
|
|
||||||
{
|
|
||||||
MPLOG(LOG_ERR, "%s will be stopped", MPL_NAME);
|
|
||||||
mpl_free(mpl);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
MPLOG(LOG_NOTICE, "starting the %s daemon", MPL_NAME);
|
|
||||||
|
|
||||||
return mpl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mpl_stop(MPL *mpl)
|
|
||||||
{
|
|
||||||
mpl_udev_free(&mpl->udev);
|
|
||||||
|
|
||||||
if (mpl->cancellable.exit)
|
|
||||||
{
|
|
||||||
flock(mpl->fd, LOCK_UN);
|
|
||||||
MPLOG(LOG_NOTICE, "stopping the %s daemon", MPL_NAME);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
MPLOG(LOG_NOTICE, "successful completion of the process %d", getpid());
|
|
||||||
|
|
||||||
mpl_free(mpl);
|
|
||||||
|
|
||||||
closelog();
|
|
||||||
}
|
|
||||||
|
|
||||||
void mpl_loop(MPL *mpl)
|
|
||||||
{
|
|
||||||
if (mpl->parameters.check_device)
|
|
||||||
mpl_udev_check_devices(&mpl->udev);
|
|
||||||
|
|
||||||
mpl_udev_loop(&mpl->udev, &mpl->cancellable);
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
/*
|
|
||||||
* mpl-common.h
|
|
||||||
*
|
|
||||||
* by Alexander Zhirov (alexander@zhirov.kz)
|
|
||||||
* Telegram @alexanderzhirov
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MPL_COMMON_H_
|
|
||||||
#define MPL_COMMON_H_
|
|
||||||
|
|
||||||
#include "mpl-lib.h"
|
|
||||||
#include "mpl-udev.h"
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int check_device;
|
|
||||||
} MPL_PARAMETERS;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
MPL_PARAMETERS parameters;
|
|
||||||
MPL_CANCELLABLE cancellable;
|
|
||||||
MPL_UDEV udev;
|
|
||||||
} MPL;
|
|
||||||
|
|
||||||
MPL *mpl_init(MPL_PARAMETERS *parameters);
|
|
||||||
void mpl_stop(MPL *mpl);
|
|
||||||
void mpl_loop(MPL *mpl);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,87 +0,0 @@
|
||||||
/*
|
|
||||||
* mpl-core.c
|
|
||||||
*
|
|
||||||
* by Alexander Zhirov (alexander@zhirov.kz)
|
|
||||||
* Telegram @alexanderzhirov
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "mpl-lib.h"
|
|
||||||
#include "mpl-core.h"
|
|
||||||
|
|
||||||
#include <regex.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
int device_path(const MPL_MODEM *modem)
|
|
||||||
{
|
|
||||||
DIR *dir;
|
|
||||||
struct dirent *ent;
|
|
||||||
regex_t regex;
|
|
||||||
const char *pattern = "^ttyUSB[0-9]*$";
|
|
||||||
|
|
||||||
int ret = regcomp(®ex, pattern, REG_EXTENDED);
|
|
||||||
if (ret != 0)
|
|
||||||
{
|
|
||||||
printf("Failed to compile regular expression\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
dir = opendir(modem->path);
|
|
||||||
if (dir == NULL)
|
|
||||||
{
|
|
||||||
printf("Failed to open directory: %s\n", modem->path);
|
|
||||||
regfree(®ex);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((ent = readdir(dir)) != NULL)
|
|
||||||
{
|
|
||||||
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = regexec(®ex, ent->d_name, 0, NULL, 0);
|
|
||||||
|
|
||||||
if (ret == 0)
|
|
||||||
{
|
|
||||||
printf("Found a file matching the pattern: %s\n", ent->d_name);
|
|
||||||
|
|
||||||
char *path = (char *)calloc(strlen(MPL_DEV_PATH) + strlen(ent->d_name) + 1, sizeof(char));
|
|
||||||
strcpy(path, MPL_DEV_PATH);
|
|
||||||
strcat(path, ent->d_name);
|
|
||||||
|
|
||||||
int fd = open(path, O_RDWR);
|
|
||||||
if (fd < 0)
|
|
||||||
{
|
|
||||||
printf("Не удалось открыть USB устройство.\n");
|
|
||||||
free(path);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *tty = ttyname(fd);
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
if (tty != NULL)
|
|
||||||
{
|
|
||||||
printf("%s устройство tty: %s\n", modem->action ? "Добавлено" : "Удалено", tty);
|
|
||||||
|
|
||||||
// if (!num)
|
|
||||||
// print_imei(tty);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
printf("Устройство tty не найдено\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (ret != REG_NOMATCH)
|
|
||||||
{
|
|
||||||
printf("Failed to apply regular expression\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
regfree(®ex);
|
|
||||||
closedir(dir);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
/*
|
|
||||||
* mpl-core.h
|
|
||||||
*
|
|
||||||
* by Alexander Zhirov (alexander@zhirov.kz)
|
|
||||||
* Telegram @alexanderzhirov
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MPL_CORE_H_
|
|
||||||
#define MPL_CORE_H_
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int port;
|
|
||||||
char *path;
|
|
||||||
int action;
|
|
||||||
} MPL_MODEM;
|
|
||||||
|
|
||||||
int device_path(const MPL_MODEM *modem);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,25 +0,0 @@
|
||||||
/*
|
|
||||||
* mpl-lib.c
|
|
||||||
*
|
|
||||||
* by Alexander Zhirov (alexander@zhirov.kz)
|
|
||||||
* Telegram @alexanderzhirov
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "mpl-lib.h"
|
|
||||||
|
|
||||||
char *mpl_get_copy_string(const char *str)
|
|
||||||
{
|
|
||||||
int size = strlen(str);
|
|
||||||
char *copy = (char *)calloc(size + 1, sizeof(char));
|
|
||||||
|
|
||||||
if (!copy)
|
|
||||||
{
|
|
||||||
MPLOG(LOG_ERR, "error getting the string");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
strcpy(copy, str);
|
|
||||||
copy[size] = '\0';
|
|
||||||
|
|
||||||
return copy;
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
/*
|
|
||||||
* mpl-lib.h
|
|
||||||
*
|
|
||||||
* by Alexander Zhirov (alexander@zhirov.kz)
|
|
||||||
* Telegram @alexanderzhirov
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MPL_LIB_H_
|
|
||||||
#define MPL_LIB_H_
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#define MPL_NAME "mportlink"
|
|
||||||
#define MPL_DEV_PATH "/dev/"
|
|
||||||
#define MPL_DONGLE_PATH (MPL_DEV_PATH "dongle/")
|
|
||||||
|
|
||||||
#define MPLOG(PRIORITY, fmt, ...) do { \
|
|
||||||
char buf[256]; \
|
|
||||||
snprintf(buf, sizeof(buf), fmt __VA_OPT__(,) __VA_ARGS__); \
|
|
||||||
PRIORITY < LOG_WARNING && errno ? \
|
|
||||||
syslog(PRIORITY, "%s(): %s (%s)", __func__, buf, strerror(errno)) : \
|
|
||||||
syslog(PRIORITY, "%s(): %s", __func__, buf); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
int signal;
|
|
||||||
int exit;
|
|
||||||
} MPL_CANCELLABLE;
|
|
||||||
|
|
||||||
char *mpl_get_copy_string(const char *str);
|
|
||||||
|
|
||||||
#endif
|
|
259
src/mpl-udev.c
259
src/mpl-udev.c
|
@ -1,259 +0,0 @@
|
||||||
/*
|
|
||||||
* mpl-udev.c
|
|
||||||
*
|
|
||||||
* by Alexander Zhirov (alexander@zhirov.kz)
|
|
||||||
* Telegram @alexanderzhirov
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "mpl-udev.h"
|
|
||||||
#include "mpl-core.h"
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
void test(struct udev_device *dev)
|
|
||||||
{
|
|
||||||
const char *action = udev_device_get_action(dev);
|
|
||||||
// printf("action: %s\n", action);
|
|
||||||
// const char *devpath = udev_device_get_devpath(dev);
|
|
||||||
// printf("devpath: %s\n", devpath);
|
|
||||||
|
|
||||||
// const char *subsystem = udev_device_get_subsystem(dev);
|
|
||||||
// printf("subsystem: %s\n", subsystem);
|
|
||||||
|
|
||||||
const char *devtype = udev_device_get_devtype(dev);
|
|
||||||
// printf("devtype: %s\n", devtype);
|
|
||||||
|
|
||||||
const char *driver = udev_device_get_driver(dev);
|
|
||||||
// printf("driver: %s\n", driver);
|
|
||||||
|
|
||||||
// const char *sysattr_value = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
|
|
||||||
// printf("Номер порта: %s\n", sysattr_value);
|
|
||||||
|
|
||||||
const char *syspath = udev_device_get_syspath(dev);
|
|
||||||
// printf("syspath: %s\n", syspath);
|
|
||||||
|
|
||||||
// const char *sysname = udev_device_get_sysname(dev);
|
|
||||||
// printf("sysname: %s\n", sysname);
|
|
||||||
|
|
||||||
// const char *sysnum = udev_device_get_sysnum(dev);
|
|
||||||
// printf("sysnum: %s\n", sysnum);
|
|
||||||
|
|
||||||
const char *devnode = udev_device_get_devnode(dev);
|
|
||||||
// printf("devnode: %s\n", devnode);
|
|
||||||
|
|
||||||
// int is_initialized = udev_device_get_is_initialized(dev);
|
|
||||||
// printf("is_initialized: %d\n", is_initialized);
|
|
||||||
|
|
||||||
printf("action: %s\tdevtype: %s\tdriver: %s\tsyspath: %s\tdevnode: %s\n", action, devtype, driver, syspath, devnode);
|
|
||||||
}
|
|
||||||
|
|
||||||
int mpl_udev_init(MPL_UDEV *udev)
|
|
||||||
{
|
|
||||||
udev->context = udev_new();
|
|
||||||
if (udev->context == NULL)
|
|
||||||
{
|
|
||||||
MPLOG(LOG_ERR, "error creating udev context");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
udev->monitor = udev_monitor_new_from_netlink(udev->context, "udev");
|
|
||||||
if (udev->monitor == NULL)
|
|
||||||
{
|
|
||||||
MPLOG(LOG_ERR, "error creating udev monitor");
|
|
||||||
mpl_udev_free(udev);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
udev_monitor_filter_add_match_subsystem_devtype(udev->monitor, "usb", NULL);
|
|
||||||
udev_monitor_enable_receiving(udev->monitor);
|
|
||||||
|
|
||||||
udev->fd = udev_monitor_get_fd(udev->monitor);
|
|
||||||
if (udev->fd < 0)
|
|
||||||
{
|
|
||||||
MPLOG(LOG_ERR, "error creating udev monitor descriptor");
|
|
||||||
mpl_udev_free(udev);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// action: bind devtype: usb_interface driver: option syspath: /sys/devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3.3/3-3.3:1.1
|
|
||||||
// action: unbind devtype: usb_interface driver: (null) syspath: /sys/devices/pci0000:00/0000:00:14.0/usb3/3-3/3-3.3/3-3.3:1.1
|
|
||||||
|
|
||||||
static int mpl_device_is_interface(struct udev_device *dev)
|
|
||||||
{
|
|
||||||
return strcmp(udev_device_get_devtype(dev), "usb_interface") == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mpl_device_is_modem(struct udev_device *dev)
|
|
||||||
{
|
|
||||||
const char *driver = udev_device_get_driver(dev);
|
|
||||||
const char *sysattr = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
|
|
||||||
|
|
||||||
if (!driver || !sysattr)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return mpl_device_is_interface(dev) && strcmp(driver, "option") == 0 && sysattr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mpl_connect_modem(struct udev_device *dev)
|
|
||||||
{
|
|
||||||
const char *action = udev_device_get_property_value(dev, "ACTION");
|
|
||||||
|
|
||||||
return strcmp(action, "bind") == 0 && mpl_device_is_modem(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int mpl_disconnect_modem(struct udev_device *dev)
|
|
||||||
{
|
|
||||||
const char *action = udev_device_get_property_value(dev, "ACTION");
|
|
||||||
|
|
||||||
return strcmp(action, "unbind") == 0 && mpl_device_is_interface(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static MPL_MODEM *mpl_get_modem_info(struct udev_device *dev)
|
|
||||||
{
|
|
||||||
MPL_MODEM *modem = (MPL_MODEM *)calloc(1, sizeof(MPL_MODEM));
|
|
||||||
|
|
||||||
if (modem == NULL)
|
|
||||||
{
|
|
||||||
MPLOG(LOG_ERR, "error creating modem");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
modem->port = atoi(udev_device_get_sysattr_value(dev, "bInterfaceNumber"));
|
|
||||||
modem->path = mpl_get_copy_string(udev_device_get_syspath(dev));
|
|
||||||
modem->action = strcmp(udev_device_get_property_value(dev, "ACTION"), "bind") == 0;
|
|
||||||
|
|
||||||
return modem;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mpl_free_modem(MPL_MODEM *modem)
|
|
||||||
{
|
|
||||||
if (modem->path)
|
|
||||||
free(modem->path);
|
|
||||||
free(modem);
|
|
||||||
}
|
|
||||||
|
|
||||||
int mpl_udev_check_devices(MPL_UDEV *udev)
|
|
||||||
{
|
|
||||||
struct udev_device *dev;
|
|
||||||
struct udev_enumerate *enumerate;
|
|
||||||
struct udev_list_entry *devices, *dev_list_entry;
|
|
||||||
|
|
||||||
MPL_MODEM *modem = NULL;
|
|
||||||
|
|
||||||
enumerate = udev_enumerate_new(udev->context);
|
|
||||||
|
|
||||||
if (enumerate == NULL)
|
|
||||||
{
|
|
||||||
MPLOG(LOG_ERR, "error creating udev enumerate");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
udev_enumerate_add_match_subsystem(enumerate, "usb");
|
|
||||||
udev_enumerate_scan_devices(enumerate);
|
|
||||||
|
|
||||||
devices = udev_enumerate_get_list_entry(enumerate);
|
|
||||||
|
|
||||||
if (devices == NULL)
|
|
||||||
{
|
|
||||||
MPLOG(LOG_ERR, "error get udev devices");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
udev_list_entry_foreach(dev_list_entry, devices)
|
|
||||||
{
|
|
||||||
const char *syspath = udev_list_entry_get_name(dev_list_entry);
|
|
||||||
dev = udev_device_new_from_syspath(udev->context, syspath);
|
|
||||||
|
|
||||||
if (!mpl_device_is_modem(dev))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
modem = mpl_get_modem_info(dev);
|
|
||||||
|
|
||||||
device_path(modem);
|
|
||||||
|
|
||||||
mpl_free_modem(modem);
|
|
||||||
udev_device_unref(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
udev_enumerate_unref(enumerate);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void mpl_udev_free(MPL_UDEV *udev)
|
|
||||||
{
|
|
||||||
if (udev->monitor)
|
|
||||||
{
|
|
||||||
udev_monitor_unref(udev->monitor);
|
|
||||||
udev->monitor = NULL;
|
|
||||||
}
|
|
||||||
if (udev->context)
|
|
||||||
{
|
|
||||||
udev_unref(udev->context);
|
|
||||||
udev->context = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void mpl_udev_loop(MPL_UDEV *udev, MPL_CANCELLABLE *cancellable)
|
|
||||||
{
|
|
||||||
MPL_MODEM *modem = NULL;
|
|
||||||
int status = -1;
|
|
||||||
pid_t pid = -1;
|
|
||||||
|
|
||||||
int stop = 0;
|
|
||||||
|
|
||||||
while (!stop)
|
|
||||||
{
|
|
||||||
fd_set fds;
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(udev->fd, &fds);
|
|
||||||
|
|
||||||
if (select(udev->fd + 1, &fds, NULL, NULL, NULL) <= 0)
|
|
||||||
{
|
|
||||||
if (cancellable->exit)
|
|
||||||
return;
|
|
||||||
|
|
||||||
MPLOG(LOG_ERR, "file selection error");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct udev_device *dev = udev_monitor_receive_device(udev->monitor);
|
|
||||||
if (dev)
|
|
||||||
{
|
|
||||||
// test(dev);
|
|
||||||
|
|
||||||
if (mpl_connect_modem(dev))
|
|
||||||
{
|
|
||||||
modem = mpl_get_modem_info(dev);
|
|
||||||
|
|
||||||
pid = fork();
|
|
||||||
if (pid == 0)
|
|
||||||
{
|
|
||||||
stop = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
wait(&status);
|
|
||||||
}
|
|
||||||
else if (mpl_disconnect_modem(dev))
|
|
||||||
{
|
|
||||||
// unmount ports
|
|
||||||
}
|
|
||||||
|
|
||||||
udev_device_unref(dev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mpl_udev_free(udev);
|
|
||||||
|
|
||||||
if (cancellable->exit)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// printf("path: %s\t port: %d\t action: %d\n", modem->path, modem->port, modem->action);
|
|
||||||
|
|
||||||
device_path(modem);
|
|
||||||
mpl_free_modem(modem);
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* mpl-udev.h
|
|
||||||
*
|
|
||||||
* by Alexander Zhirov (alexander@zhirov.kz)
|
|
||||||
* Telegram @alexanderzhirov
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MPL_UDEV_H_
|
|
||||||
#define MPL_UDEV_H_
|
|
||||||
|
|
||||||
#include <libudev.h>
|
|
||||||
#include "mpl-lib.h"
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
struct udev *context;
|
|
||||||
struct udev_monitor *monitor;
|
|
||||||
int fd;
|
|
||||||
} MPL_UDEV;
|
|
||||||
|
|
||||||
int mpl_udev_init(MPL_UDEV *udev);
|
|
||||||
void mpl_udev_free(MPL_UDEV *udev);
|
|
||||||
int mpl_udev_check_devices(MPL_UDEV *udev);
|
|
||||||
void mpl_udev_loop(MPL_UDEV *udev, MPL_CANCELLABLE *cancellable);
|
|
||||||
|
|
||||||
#endif
|
|
77
src/mpl.c
77
src/mpl.c
|
@ -1,77 +0,0 @@
|
||||||
/*
|
|
||||||
* mpl.c
|
|
||||||
*
|
|
||||||
* by Alexander Zhirov (alexander@zhirov.kz)
|
|
||||||
* Telegram @alexanderzhirov
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "mpl.h"
|
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
static MPL *mpl;
|
|
||||||
|
|
||||||
const char *const short_options = "hcv";
|
|
||||||
|
|
||||||
const struct option long_options[] = {
|
|
||||||
{"help", 0, NULL, 'h'},
|
|
||||||
{"check-devices", 0, NULL, 'c'},
|
|
||||||
{"version", 0, NULL, 'v'},
|
|
||||||
{NULL, 0, NULL, 0}};
|
|
||||||
|
|
||||||
[[noreturn]] void static print_usage_and_exit(int code)
|
|
||||||
{
|
|
||||||
printf("Usage: %s [OPTION]...\n\n", MPL_NAME);
|
|
||||||
puts(" -c, --check-devices checking connected devices at startup");
|
|
||||||
puts(" -h, --help display this help text and exit");
|
|
||||||
puts(" -v, --version display version information and exit\n");
|
|
||||||
exit(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[noreturn]] void static print_version_and_exit()
|
|
||||||
{
|
|
||||||
printf("%s version %s\n", MPL_NAME, VERSION);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void signals_handler(int signum)
|
|
||||||
{
|
|
||||||
MPLOG(LOG_WARNING, "cancelling the mportlink loop (%d)", signum);
|
|
||||||
mpl->cancellable.signal = signum;
|
|
||||||
mpl->cancellable.exit = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
|
|
||||||
MPL_PARAMETERS parameters =
|
|
||||||
{
|
|
||||||
.check_device = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, short_options, long_options, NULL)) != -1)
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case 'c':
|
|
||||||
parameters.check_device = 1;
|
|
||||||
break;
|
|
||||||
case 'v':
|
|
||||||
print_version_and_exit();
|
|
||||||
case 'h':
|
|
||||||
print_usage_and_exit(0);
|
|
||||||
case '?':
|
|
||||||
print_usage_and_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
mpl = mpl_init(¶meters);
|
|
||||||
|
|
||||||
signal(SIGHUP, signals_handler);
|
|
||||||
signal(SIGINT, signals_handler);
|
|
||||||
signal(SIGTERM, signals_handler);
|
|
||||||
|
|
||||||
mpl_loop(mpl);
|
|
||||||
|
|
||||||
mpl_stop(mpl);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
17
src/mpl.h
17
src/mpl.h
|
@ -1,17 +0,0 @@
|
||||||
/*
|
|
||||||
* mpl.h
|
|
||||||
*
|
|
||||||
* by Alexander Zhirov (alexander@zhirov.kz)
|
|
||||||
* Telegram @alexanderzhirov
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MPL_H_
|
|
||||||
#define MPL_H_
|
|
||||||
|
|
||||||
#ifndef VERSION
|
|
||||||
#define VERSION "unrelease"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "mpl-common.h"
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -0,0 +1,253 @@
|
||||||
|
#include "mportlink.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#define DEV_PATH "/dev/"
|
||||||
|
#define DONGLE_PATH "/dev/dongle/"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
const gchar *manufacturer;
|
||||||
|
const gchar *model;
|
||||||
|
const gchar *imei;
|
||||||
|
const gchar *device_identifier;
|
||||||
|
MMModemPortInfo *ports;
|
||||||
|
guint n_ports;
|
||||||
|
} MPLmodem;
|
||||||
|
|
||||||
|
void mpl_create_dongle_dir()
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (stat(DONGLE_PATH, &st) == 0)
|
||||||
|
{
|
||||||
|
if (!S_ISDIR(st.st_mode))
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "mpl_create_dongle_dir: %s exists and is not a directory", DONGLE_PATH);
|
||||||
|
raise(SIGINT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mkdir(DONGLE_PATH, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "mpl_create_dongle_dir: unable to create a directory %s", DONGLE_PATH);
|
||||||
|
raise(SIGINT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MPLmodem *mpl_get_new_modem()
|
||||||
|
{
|
||||||
|
MPLmodem *modem = (MPLmodem *)calloc(1, sizeof(MPLmodem));
|
||||||
|
|
||||||
|
if (modem == NULL)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "mpl_get_new_modem, modem: memory allocation error");
|
||||||
|
raise(SIGINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
return modem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mpl_free_modem(MPLmodem *modem)
|
||||||
|
{
|
||||||
|
if (modem->n_ports && modem->ports)
|
||||||
|
mm_modem_port_info_array_free(modem->ports, modem->n_ports);
|
||||||
|
free(modem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mpl_print_modem_info(MPLmodem *modem, bool connected)
|
||||||
|
{
|
||||||
|
gchar *status;
|
||||||
|
status = connected ? "Connected" : "Disconnected";
|
||||||
|
|
||||||
|
g_print("%s %s %s (%s)\n", status, modem->manufacturer, modem->model, modem->device_identifier);
|
||||||
|
g_print("`-- Count ports: %d\n", modem->n_ports);
|
||||||
|
|
||||||
|
for (guint i = 0; i < modem->n_ports; i++)
|
||||||
|
{
|
||||||
|
if (i + 1 < modem->n_ports)
|
||||||
|
{
|
||||||
|
g_print(" |-- Port %d:\n", i);
|
||||||
|
g_print(" | |-- Name: %s\n", modem->ports[i].name);
|
||||||
|
g_print(" | `-- Link: %s-%d\n", modem->imei, i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_print(" `-- Port %d:\n", i);
|
||||||
|
g_print(" |-- Name: %s\n", modem->ports[i].name);
|
||||||
|
g_print(" `-- Link: %s-%d\n", modem->imei, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MPLmodem *mpl_get_new_modem_info(MMObject *obj)
|
||||||
|
{
|
||||||
|
MPLmodem *mpl_modem = NULL;
|
||||||
|
MMModem *mm_modem = mm_object_get_modem(obj);
|
||||||
|
|
||||||
|
if (mm_modem == NULL)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "mpl_get_new_modem_info, mm_modem: modem does not implement the interface");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
mpl_modem = mpl_get_new_modem();
|
||||||
|
|
||||||
|
mpl_modem->manufacturer = mm_modem_get_manufacturer(mm_modem);
|
||||||
|
mpl_modem->model = mm_modem_get_model(mm_modem);
|
||||||
|
mpl_modem->imei = mm_modem_get_equipment_identifier(mm_modem);
|
||||||
|
mpl_modem->device_identifier = mm_modem_get_device_identifier(mm_modem);
|
||||||
|
|
||||||
|
gboolean success = mm_modem_get_ports(mm_modem, &mpl_modem->ports, &mpl_modem->n_ports);
|
||||||
|
|
||||||
|
g_object_unref(mm_modem);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
return mpl_modem;
|
||||||
|
else
|
||||||
|
syslog(LOG_WARNING, "mpl_get_new_modem_info, success: error receiving modem ports");
|
||||||
|
|
||||||
|
mpl_free_modem(mpl_modem);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *mpl_get_dst_path(guint index, const gchar *imei)
|
||||||
|
{
|
||||||
|
char *dst_path = NULL;
|
||||||
|
|
||||||
|
guint size_id = snprintf(NULL, 0, "-%d", index);
|
||||||
|
char *id = (char *)calloc(size_id + 1, sizeof(char));
|
||||||
|
|
||||||
|
if (id == NULL)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "mpl_get_dst_path, id: memory allocation error");
|
||||||
|
raise(SIGINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(id, "-%d", index);
|
||||||
|
|
||||||
|
guint dst_path_size = strlen(DONGLE_PATH) + strlen(imei) + size_id;
|
||||||
|
dst_path = (char *)calloc(dst_path_size + 1, sizeof(char));
|
||||||
|
|
||||||
|
if (dst_path == NULL)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "mpl_get_dst_path, dst_path: memory allocation error");
|
||||||
|
raise(SIGINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(dst_path, DONGLE_PATH);
|
||||||
|
strcat(dst_path, imei);
|
||||||
|
strcat(dst_path, id);
|
||||||
|
|
||||||
|
free(id);
|
||||||
|
|
||||||
|
return dst_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *mpl_get_src_path(const gchar *port_name)
|
||||||
|
{
|
||||||
|
char *src_path = NULL;
|
||||||
|
|
||||||
|
guint src_path_size = strlen(DEV_PATH) + strlen(port_name);
|
||||||
|
src_path = (char *)calloc(src_path_size + 1, sizeof(char));
|
||||||
|
|
||||||
|
if (src_path == NULL)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "mpl_get_src_path, src_path: memory allocation error");
|
||||||
|
raise(SIGINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(src_path, DEV_PATH);
|
||||||
|
strcat(src_path, port_name);
|
||||||
|
|
||||||
|
return src_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mpl_symlink_ports(MPLmodem *modem)
|
||||||
|
{
|
||||||
|
for (guint i = 0; i < modem->n_ports; i++)
|
||||||
|
{
|
||||||
|
char *src_path = mpl_get_src_path(modem->ports[i].name);
|
||||||
|
char *dst_path = mpl_get_dst_path(i, modem->imei);
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (access(src_path, F_OK) == -1)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "mpl_symlink_ports, src_path: device file is not available [%s]", src_path);
|
||||||
|
free(src_path);
|
||||||
|
free(dst_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lstat(dst_path, &st) == 0)
|
||||||
|
{
|
||||||
|
syslog(LOG_WARNING, "mpl_symlink_ports, dst_path: a symbolic link to the device already exists [%s]", dst_path);
|
||||||
|
if (unlink(dst_path) == -1)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "mpl_symlink_ports, dst_path: link could not be deleted [%s]", dst_path);
|
||||||
|
free(src_path);
|
||||||
|
free(dst_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symlink(src_path, dst_path) == 0)
|
||||||
|
syslog(LOG_NOTICE, "mpl_symlink_ports, dst_path: the symbolic link has been successfully created [%s -> %s]", dst_path, src_path);
|
||||||
|
else
|
||||||
|
syslog(LOG_ERR, "mpl_symlink_ports, dst_path: error creating a symbolic link [%s -> %s]", dst_path, src_path);
|
||||||
|
|
||||||
|
free(src_path);
|
||||||
|
free(dst_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mpl_unlink_ports(MPLmodem *modem)
|
||||||
|
{
|
||||||
|
for (guint i = 0; i < modem->n_ports; i++)
|
||||||
|
{
|
||||||
|
char *dst_path = mpl_get_dst_path(i, modem->imei);
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (lstat(dst_path, &st) == -1)
|
||||||
|
{
|
||||||
|
syslog(LOG_WARNING, "mpl_unlink_ports, dst_path: a symbolic link to the device not exists [%s]", dst_path);
|
||||||
|
free(dst_path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unlink(dst_path) == 0)
|
||||||
|
syslog(LOG_NOTICE, "mpl_unlink_ports, dst_path: link was successfully deleted [%s]", dst_path);
|
||||||
|
else
|
||||||
|
syslog(LOG_ERR, "mpl_unlink_ports, dst_path: link could not be deleted [%s]", dst_path);
|
||||||
|
|
||||||
|
free(dst_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mpl_device_added(MMManager *manager, MMObject *obj)
|
||||||
|
{
|
||||||
|
MPLmodem *modem = mpl_get_new_modem_info(obj);
|
||||||
|
|
||||||
|
if (modem == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// mpl_print_modem_info(modem, true);
|
||||||
|
mpl_symlink_ports(modem);
|
||||||
|
|
||||||
|
mpl_free_modem(modem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mpl_device_removed(MMManager *manager, MMObject *obj)
|
||||||
|
{
|
||||||
|
MPLmodem *modem = mpl_get_new_modem_info(obj);
|
||||||
|
|
||||||
|
if (modem == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// mpl_print_modem_info(modem, false);
|
||||||
|
mpl_unlink_ports(modem);
|
||||||
|
|
||||||
|
mpl_free_modem(modem);
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
#include "mportlink.h"
|
||||||
|
#include <sys/file.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#define LOCKFILE "/run/lock/mportlink.lock"
|
||||||
|
#define MPL "mportlink"
|
||||||
|
|
||||||
|
static Context *ctx;
|
||||||
|
static GCancellable *cancellable;
|
||||||
|
static GMainLoop *loop;
|
||||||
|
|
||||||
|
static void signals_handler(int signum)
|
||||||
|
{
|
||||||
|
if (cancellable)
|
||||||
|
{
|
||||||
|
if (!g_cancellable_is_cancelled(cancellable))
|
||||||
|
{
|
||||||
|
syslog(LOG_WARNING, "signals_handler: cancelling the operation...");
|
||||||
|
g_cancellable_cancel(cancellable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loop && g_main_loop_is_running(loop))
|
||||||
|
{
|
||||||
|
syslog(LOG_WARNING, "signals_handler: cancelling the main loop...");
|
||||||
|
g_main_loop_quit(loop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_manager_ready(GObject *source, GAsyncResult *result, gpointer none)
|
||||||
|
{
|
||||||
|
ctx->manager = mmcli_get_manager_finish(result);
|
||||||
|
|
||||||
|
g_signal_connect(ctx->manager, "object-added", G_CALLBACK(mpl_device_added), NULL);
|
||||||
|
g_signal_connect(ctx->manager, "object-removed", G_CALLBACK(mpl_device_removed), NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
openlog(MPL, LOG_PID, LOG_SYSLOG);
|
||||||
|
|
||||||
|
int lock_fd = open(LOCKFILE, O_CREAT | O_RDWR, 0666);
|
||||||
|
int rc = flock(lock_fd, LOCK_EX | LOCK_NB);
|
||||||
|
|
||||||
|
if (rc || errno == EWOULDBLOCK)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "main: only one instance of %s is allowed", MPL);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
syslog(LOG_NOTICE, "main: starting the %s daemon", MPL);
|
||||||
|
|
||||||
|
mpl_create_dongle_dir();
|
||||||
|
|
||||||
|
GError *error = NULL;
|
||||||
|
GDBusConnection *connection = NULL;
|
||||||
|
|
||||||
|
signal(SIGINT, signals_handler);
|
||||||
|
signal(SIGHUP, signals_handler);
|
||||||
|
signal(SIGTERM, signals_handler);
|
||||||
|
|
||||||
|
connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
|
||||||
|
if (!connection)
|
||||||
|
{
|
||||||
|
syslog(LOG_ERR, "main, connection: couldn't get bus: %s", error->message);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
cancellable = g_cancellable_new();
|
||||||
|
loop = g_main_loop_new(NULL, FALSE);
|
||||||
|
|
||||||
|
ctx = g_new0(Context, 1);
|
||||||
|
if (cancellable)
|
||||||
|
ctx->cancellable = g_object_ref(cancellable);
|
||||||
|
|
||||||
|
mmcli_get_manager(connection, cancellable, (GAsyncReadyCallback)get_manager_ready, NULL);
|
||||||
|
g_main_loop_run(loop);
|
||||||
|
|
||||||
|
if (cancellable)
|
||||||
|
g_object_unref(cancellable);
|
||||||
|
g_main_loop_unref(loop);
|
||||||
|
g_object_unref(connection);
|
||||||
|
|
||||||
|
flock(lock_fd, LOCK_UN);
|
||||||
|
|
||||||
|
syslog(LOG_NOTICE, "main: stopping the %s daemon", MPL);
|
||||||
|
closelog();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
#include "mm.h"
|
||||||
|
|
||||||
|
void mpl_create_dongle_dir();
|
||||||
|
void mpl_device_added(MMManager *manager, MMObject *obj);
|
||||||
|
void mpl_device_removed(MMManager *manager, MMObject *obj);
|
Reference in New Issue