This commit is contained in:
Alexander Zhirov 2023-12-25 00:06:56 +03:00
parent bb72f57776
commit cd5f9f7a12
10 changed files with 344 additions and 342 deletions

11
.vscode/settings.json vendored
View File

@ -30,10 +30,11 @@
"mpl-lib.h": "c",
"mpl-core.h": "c",
"mpl.h": "c",
"mpl-udev.h": "c"
"mpl-udev.h": "c",
"mpl-args.h": "c",
"*.in": "cpp",
"signal.h": "c",
"stdio.h": "c"
},
"cmake.configureOnOpen": false,
"editor.rulers": [
80
]
"cmake.configureOnOpen": false
}

View File

@ -1,6 +1,33 @@
cmake_minimum_required(VERSION 3.18.4)
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)
find_package(PkgConfig REQUIRED)

BIN
mportlink Executable file

Binary file not shown.

View File

@ -5,304 +5,108 @@
* Telegram @alexanderzhirov
*/
#include "mpl-core.h"
#include <sys/stat.h>
#include <sys/file.h>
#include "mpl-core.h"
#include <unistd.h>
#define LOCKFILE "/run/lock/mportlink.lock"
#define DEV_PATH "/dev/"
#define DONGLE_PATH (DEV_PATH "dongle/")
static void mpl_create_dongle_dir()
static int mpl_create_dongle_dir()
{
struct stat st;
if (stat(DONGLE_PATH, &st) == 0) {
if (!S_ISDIR(st.st_mode)) {
MPLOG(LOG_WARNING, "%s exists and is not a directory",
DONGLE_PATH);
exit(EXIT_FAILURE);
if (stat(DONGLE_PATH, &st) == 0)
{
if (!S_ISDIR(st.st_mode))
{
MPLOG(LOG_WARNING, "%s exists and is not a directory", DONGLE_PATH);
return 1;
}
} else if (mkdir(DONGLE_PATH,
S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1) {
}
else if (mkdir(DONGLE_PATH, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == -1)
{
MPLOG(LOG_ERR, "unable to create a directory %s", DONGLE_PATH);
exit(EXIT_FAILURE);
return 1;
}
return 0;
}
int mpl_init()
void static mpl_free(MPL *mpl)
{
openlog(MPL, LOG_PID, LOG_SYSLOG);
int lock_fd = open(LOCKFILE, O_CREAT | O_RDWR, 0644);
if (lock_fd < 0) {
MPLOG(LOG_ERR, "Unable to create a lockfile");
exit(EXIT_FAILURE);
}
int rc = flock(lock_fd, LOCK_EX | LOCK_NB);
if (rc || errno == EWOULDBLOCK) {
MPLOG(LOG_ERR, "Only one instance of %s is allowed", MPL);
exit(EXIT_FAILURE);
}
mpl_create_dongle_dir();
MPLOG(LOG_NOTICE, "Starting the %s daemon", MPL);
return lock_fd;
if (mpl)
free(mpl);
}
void mpl_stop(const int lock_fd)
MPL *mpl_init(MPL_PARAMETERS *parameters)
{
flock(lock_fd, LOCK_UN);
MPL *mpl = (MPL *)calloc(1, sizeof(MPL));
MPLOG(LOG_NOTICE, "Stopping the %s daemon", 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);
flock(mpl->fd, LOCK_UN);
mpl_free(mpl);
if (mpl->cancellable.exit)
MPLOG(LOG_NOTICE, "stopping the %s daemon", MPL_NAME);
else
MPLOG(LOG_NOTICE, "successful completion of the process %d", getpid());
closelog();
}
MPL_UDEV *mpl_new()
void mpl_loop(MPL *mpl)
{
MPL_UDEV *mpl_udev = (MPL_UDEV *)calloc(1, sizeof(MPL_UDEV));
if (mpl->parameters.check_device)
mpl_udev_check_devices(&mpl->udev);
if (mpl_udev == NULL) {
MPLOG(LOG_ERR, "Error getting the udev structure");
exit(EXIT_FAILURE);
}
return mpl_udev;
mpl_udev_loop(&mpl->udev, &mpl->cancellable);
}
void mpl_loop(MPL_UDEV *mpl_udev)
{
}
// typedef struct
// {
// const gchar *manufacturer;
// const gchar *model;
// const gchar *imei;
// const gchar *device_identifier;
// MMModemPortInfo *ports;
// guint n_ports;
// } MPLmodem;
// 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);
// }

View File

@ -9,11 +9,23 @@
#define MPL_CORE_H_
#include "mpl-lib.h"
#include "mpl-udev.h"
int mpl_init();
void mpl_stop(const int lock_fd);
void mpl_loop(MPL_UDEV *mpl_udev);
typedef struct
{
int check_device;
} MPL_PARAMETERS;
MPL_UDEV *mpl_new();
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

View File

@ -15,24 +15,20 @@
#include <string.h>
#include <syslog.h>
#define MPL "mportlink"
#define MPL_NAME "mportlink"
#define MPLOG(PRIORITY, fmt, ...) do { \
char buf[256]; \
snprintf(buf, sizeof(buf), fmt __VA_OPT__(,) __VA_ARGS__); \
PRIORITY < LOG_WARNING ? \
syslog(PRIORITY, "%s(): %s (%s)", __func__, buf, \
strerror(errno)) : \
PRIORITY < LOG_WARNING && errno ? \
syslog(PRIORITY, "%s(): %s (%s)", __func__, buf, strerror(errno)) : \
syslog(PRIORITY, "%s(): %s", __func__, buf); \
} while(0)
typedef struct _MPL_UDEV MPL_UDEV;
struct _MPL_UDEV
typedef struct
{
struct udev *udev;
struct udev_monitor *monitor;
int udev_fd;
};
int signal;
int exit;
} MPL_CANCELLABLE;
#endif

View File

@ -5,48 +5,54 @@
* Telegram @alexanderzhirov
*/
#include "mpl-lib.h"
#include "mpl-udev.h"
#include <libudev.h>
void mpl_udev_init(MPL_UDEV *mpl_udev)
#include <unistd.h>
#include <sys/wait.h>
int mpl_udev_init(MPL_UDEV *udev)
{
mpl_udev->udev = udev_new();
if (mpl_udev->udev == NULL) {
MPLOG(LOG_ERR, "Error creating udev context");
exit(EXIT_FAILURE);
udev->context = udev_new();
if (udev->context == NULL)
{
MPLOG(LOG_ERR, "error creating udev context");
return 1;
}
mpl_udev->monitor = udev_monitor_new_from_netlink(mpl_udev->udev, "udev");
if (mpl_udev->monitor == NULL) {
MPLOG(LOG_ERR, "Error creating udev monitor");
udev_unref(mpl_udev->udev);
exit(EXIT_FAILURE);
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(mpl_udev->monitor,
"usb", NULL);
udev_monitor_enable_receiving(mpl_udev->monitor);
udev_monitor_filter_add_match_subsystem_devtype(udev->monitor, "usb", NULL);
udev_monitor_enable_receiving(udev->monitor);
mpl_udev->udev_fd = udev_monitor_get_fd(mpl_udev->monitor);
if (mpl_udev->udev_fd < 0) {
MPLOG(LOG_ERR, "Error creating udev monitor descriptor");
udev_unref(mpl_udev->udev);
exit(EXIT_FAILURE);
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;
}
void mpl_udev_check_devices(MPL_UDEV *mpl_udev)
int mpl_udev_check_devices(MPL_UDEV *udev)
{
struct udev_device *dev;
struct udev_enumerate *enumerate;
struct udev_list_entry *devices, *dev_list_entry;
enumerate = udev_enumerate_new(mpl_udev->udev);
enumerate = udev_enumerate_new(udev->context);
if (enumerate == NULL) {
MPLOG(LOG_ERR, "Error creating udev enumerate");
exit(EXIT_FAILURE);
if (enumerate == NULL)
{
MPLOG(LOG_ERR, "error creating udev enumerate");
return 1;
}
udev_enumerate_add_match_subsystem(enumerate, "usb");
@ -54,25 +60,26 @@ void mpl_udev_check_devices(MPL_UDEV *mpl_udev)
devices = udev_enumerate_get_list_entry(enumerate);
if (devices == NULL) {
MPLOG(LOG_ERR, "Error get udev devices");
exit(EXIT_FAILURE);
if (devices == NULL)
{
MPLOG(LOG_ERR, "error get udev devices");
return 1;
}
udev_list_entry_foreach(dev_list_entry, devices) {
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(mpl_udev->udev, syspath);
dev = udev_device_new_from_syspath(udev->context, syspath);
const char *devtype = udev_device_get_devtype(dev);
if (!(strcmp(devtype, "usb_interface") == 0))
continue;
const char *driver = udev_device_get_driver(dev);
if (!(strcmp(driver, "option") == 0))
continue;
const char *sysattr_value = udev_device_get_sysattr_value(dev,
"bInterfaceNumber");
const char *sysattr_value = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
printf("Номер порта: %s\n", sysattr_value);
// int num = atoi(sysattr_value);
@ -85,10 +92,98 @@ void mpl_udev_check_devices(MPL_UDEV *mpl_udev)
}
udev_enumerate_unref(enumerate);
return 0;
}
mpl_udev_free(MPL_UDEV *mpl_udev)
void mpl_udev_free(MPL_UDEV *udev)
{
udev_monitor_unref(mpl_udev->monitor);
udev_unref(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)
{
const char *path_to_device = NULL;
int port_number = -1;
int status = -1;
pid_t pid = -1;
while (1)
{
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)
{
const char *action = udev_device_get_property_value(dev, "ACTION");
if (!(strcmp(action, "bind") == 0))
{
udev_device_unref(dev);
continue;
}
const char *devtype = udev_device_get_devtype(dev);
if (!(strcmp(devtype, "usb_interface") == 0))
{
udev_device_unref(dev);
continue;
}
const char *driver = udev_device_get_driver(dev);
if (!(strcmp(driver, "option") == 0))
{
udev_device_unref(dev);
continue;
}
const char *sysattr_value = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
if (sysattr_value == NULL)
{
udev_device_unref(dev);
continue;
}
port_number = atoi(sysattr_value);
path_to_device = udev_device_get_syspath(dev);
pid = fork();
if (pid == 0)
{
udev_device_unref(dev);
break;
}
else
wait(&status);
udev_device_unref(dev);
}
}
mpl_udev_free(udev);
if (cancellable->exit)
return;
sleep(5);
printf("exit");
}

View File

@ -5,7 +5,22 @@
* Telegram @alexanderzhirov
*/
#ifndef MPL_UDEV_H_
#define MPL_UDEV_H_
#include <libudev.h>
#include "mpl-lib.h"
void mpl_udev_init(MPL_UDEV *mpl_udev);
void mpl_udev_check_devices(MPL_UDEV *mpl_udev);
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

View File

@ -5,25 +5,74 @@
* Telegram @alexanderzhirov
*/
#include <getopt.h>
#include "mpl.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 main loop (%d)", signum);
MPLOG(LOG_WARNING, "cancelling the mportlink loop (%d)", signum);
mpl->cancellable.signal = signum;
mpl->cancellable.exit = 1;
}
int main()
int main(int argc, char *argv[])
{
int lock_fd = mpl_init();
int c;
MPL_UDEV *mpl = mpl_new();
mpl_udev_init(mpl);
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(&parameters);
signal(SIGINT, signals_handler);
signal(SIGHUP, signals_handler);
signal(SIGINT, signals_handler);
signal(SIGTERM, signals_handler);
mpl_stop(lock_fd);
mpl_loop(mpl);
return EXIT_SUCCESS;
mpl_stop(mpl);
return 0;
}

View File

@ -8,8 +8,11 @@
#ifndef MPL_H_
#define MPL_H_
#ifndef VERSION
#define VERSION "unrelease"
#endif
#include "mpl-lib.h"
#include "mpl-core.h"
#include "mpl-udev.h"
#endif