mirror of https://github.com/nirenjan/libx52.git
Add notify API
This change adds a notification API to libx52dcomm. It also pulls in the logic to join multiple arguments into a single buffer for later use.update-lkm
parent
88159d4fc5
commit
619d516ccc
|
@ -12,11 +12,14 @@ x52d_SOURCES = \
|
|||
daemon/x52d_config_dump.c \
|
||||
daemon/x52d_config.c \
|
||||
daemon/x52d_device.c \
|
||||
daemon/x52d_client.c \
|
||||
daemon/x52d_clock.c \
|
||||
daemon/x52d_mouse.c \
|
||||
daemon/x52d_notify.c \
|
||||
daemon/x52d_led.c \
|
||||
daemon/x52d_command.c \
|
||||
daemon/x52d_comm_internal.c
|
||||
daemon/x52d_comm_internal.c \
|
||||
daemon/x52d_comm_client.c
|
||||
|
||||
x52d_CFLAGS = \
|
||||
-I $(top_srcdir) \
|
||||
|
@ -83,6 +86,7 @@ EXTRA_DIST += \
|
|||
daemon/daemon.dox \
|
||||
daemon/protocol.dox \
|
||||
daemon/x52d.service.in \
|
||||
daemon/x52d_client.h \
|
||||
daemon/x52d_clock.h \
|
||||
daemon/x52d_config.def \
|
||||
daemon/x52d_config.h \
|
||||
|
@ -90,6 +94,7 @@ EXTRA_DIST += \
|
|||
daemon/x52d_device.h \
|
||||
daemon/x52d_io.h \
|
||||
daemon/x52d_mouse.h \
|
||||
daemon/x52d_notify.h \
|
||||
daemon/x52d_command.h \
|
||||
daemon/x52dcomm.h \
|
||||
daemon/x52dcomm-internal.h \
|
||||
|
|
|
@ -46,6 +46,7 @@ string "quit", or terminates input by using Ctrl+D.
|
|||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "x52d_const.h"
|
||||
#include "x52dcomm.h"
|
||||
|
@ -65,19 +66,13 @@ static int send_command(int sock_fd, int argc, char **argv)
|
|||
int rc;
|
||||
char buffer[1024];
|
||||
int buflen;
|
||||
int i;
|
||||
|
||||
memset(buffer, 0, sizeof(buffer));
|
||||
buflen = 0;
|
||||
for (i = 0; i < argc; i++) {
|
||||
int arglen = strlen(argv[i]) + 1;
|
||||
if ((size_t)(buflen + arglen) >= sizeof(buffer)) {
|
||||
buflen = x52d_format_command(argc, (const char **)argv, buffer, sizeof(buffer));
|
||||
if (buflen < 0) {
|
||||
if (errno == E2BIG) {
|
||||
fprintf(stderr, _("Argument length too long\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&buffer[buflen], argv[i], arglen);
|
||||
buflen += arglen;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = x52d_send_command(sock_fd, buffer, buflen, sizeof(buffer));
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver - Client handling
|
||||
*
|
||||
* Copyright (C) 2022 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pinelog.h"
|
||||
#include "x52d_client.h"
|
||||
#include "x52dcomm-internal.h"
|
||||
|
||||
void x52d_client_init(int client_fd[X52D_MAX_CLIENTS])
|
||||
{
|
||||
for (int i = 0; i < X52D_MAX_CLIENTS; i++) {
|
||||
client_fd[i] = INVALID_CLIENT;
|
||||
}
|
||||
}
|
||||
|
||||
bool x52d_client_register(int client_fd[X52D_MAX_CLIENTS], int sock_fd)
|
||||
{
|
||||
int fd;
|
||||
int i;
|
||||
|
||||
fd = accept(sock_fd, NULL, NULL);
|
||||
if (fd < 0) {
|
||||
PINELOG_ERROR(_("Error accepting client connection on socket fd %d: %s"),
|
||||
sock_fd, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x52d_set_socket_nonblocking(fd) < 0) {
|
||||
PINELOG_ERROR(_("Error marking client fd %d as nonblocking: %s"),
|
||||
fd, strerror(errno));
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i = 0; i < X52D_MAX_CLIENTS; i++) {
|
||||
if (client_fd[i] == INVALID_CLIENT) {
|
||||
PINELOG_TRACE("Accepted client %d on socket %d, slot %d", fd, sock_fd, i);
|
||||
client_fd[i] = fd;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, we've looped through the entirity of client_fd, but
|
||||
* have not registered an empty slot. We need to close the socket and
|
||||
* tell the caller that we haven't been able to register the client.
|
||||
*/
|
||||
PINELOG_TRACE("Maximum connections reached, closing socket %d", fd);
|
||||
error:
|
||||
close(fd);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool x52d_client_deregister(int client_fd[X52D_MAX_CLIENTS], int fd)
|
||||
{
|
||||
bool deregistered = false;
|
||||
|
||||
for (int i = 0; i < X52D_MAX_CLIENTS; i++) {
|
||||
if (client_fd[i] == fd) {
|
||||
client_fd[i] = INVALID_CLIENT;
|
||||
deregistered = true;
|
||||
close(fd);
|
||||
|
||||
PINELOG_TRACE("Disconnected client %d from socket", fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return deregistered;
|
||||
}
|
||||
|
||||
bool x52d_client_error(int client_fd[X52D_MAX_CLIENTS], int fd)
|
||||
{
|
||||
int error;
|
||||
socklen_t errlen = sizeof(error);
|
||||
|
||||
getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen);
|
||||
PINELOG_ERROR(_("Error when polling socket: FD %d, error %d, len %lu"),
|
||||
fd, error, (unsigned long int)errlen);
|
||||
return x52d_client_deregister(client_fd, fd);
|
||||
}
|
||||
|
||||
int x52d_client_poll(int client_fd[X52D_MAX_CLIENTS], struct pollfd pfd[MAX_CONN], int listen_fd)
|
||||
{
|
||||
int pfd_count;
|
||||
int rc;
|
||||
|
||||
memset(pfd, 0, sizeof(*pfd) * MAX_CONN);
|
||||
|
||||
pfd_count = 1;
|
||||
pfd[0].fd = listen_fd;
|
||||
pfd[0].events = POLLIN | POLLERR;
|
||||
for (int i = 0; i < X52D_MAX_CLIENTS; i++) {
|
||||
if (client_fd[i] != INVALID_CLIENT) {
|
||||
pfd[pfd_count].fd = client_fd[i];
|
||||
pfd[pfd_count].events = POLLIN | POLLERR | POLLHUP;
|
||||
pfd_count++;
|
||||
}
|
||||
}
|
||||
|
||||
PINELOG_TRACE("Polling %d file descriptors", pfd_count);
|
||||
|
||||
retry_poll:
|
||||
rc = poll(pfd, pfd_count, -1);
|
||||
if (rc < 0) {
|
||||
if (errno == EINTR) {
|
||||
goto retry_poll;
|
||||
}
|
||||
PINELOG_ERROR(_("Error %d when polling %d descriptors: %s"),
|
||||
errno, pfd_count, strerror(errno));
|
||||
} else if (rc == 0) {
|
||||
PINELOG_INFO(_("Timed out when polling"));
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void x52d_client_handle(int client_fd[X52D_MAX_CLIENTS], struct pollfd *pfd, int listen_fd, x52d_poll_handler handler)
|
||||
{
|
||||
for (int i = 0; i < MAX_CONN; i++) {
|
||||
if (pfd[i].revents & POLLHUP) {
|
||||
/* Remote hungup */
|
||||
x52d_client_deregister(client_fd, pfd[i].fd);
|
||||
} else if (pfd[i].revents & POLLERR) {
|
||||
/* Error reading from the socket */
|
||||
x52d_client_error(client_fd, pfd[i].fd);
|
||||
} else if (pfd[i].revents & POLLIN) {
|
||||
if (pfd[i].fd == listen_fd) {
|
||||
x52d_client_register(client_fd, listen_fd);
|
||||
} else {
|
||||
if (handler != NULL) {
|
||||
handler(pfd[i].fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver - Client handling
|
||||
*
|
||||
* Copyright (C) 2022 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#ifndef X52D_CLIENT_H
|
||||
#define X52D_CLIENT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "x52d_const.h"
|
||||
|
||||
#define MAX_CONN (X52D_MAX_CLIENTS + 1)
|
||||
|
||||
#define INVALID_CLIENT -1
|
||||
|
||||
typedef void (*x52d_poll_handler)(int);
|
||||
|
||||
void x52d_client_init(int client_fd[X52D_MAX_CLIENTS]);
|
||||
bool x52d_client_register(int client_fd[X52D_MAX_CLIENTS], int sock_fd);
|
||||
bool x52d_client_deregister(int client_fd[X52D_MAX_CLIENTS], int fd);
|
||||
bool x52d_client_error(int client_fd[X52D_MAX_CLIENTS], int fd);
|
||||
int x52d_client_poll(int client_fd[X52D_MAX_CLIENTS], struct pollfd pfd[MAX_CONN], int listen_fd);
|
||||
void x52d_client_handle(int client_fd[X52D_MAX_CLIENTS], struct pollfd *pfd, int listen_fd, x52d_poll_handler handler);
|
||||
|
||||
#endif //!defined X52D_CLIENT_H
|
|
@ -18,19 +18,11 @@
|
|||
#include "x52dcomm.h"
|
||||
#include "x52dcomm-internal.h"
|
||||
|
||||
int x52d_dial_command(const char *sock_path)
|
||||
static int _setup_socket(struct sockaddr_un *remote, int len)
|
||||
{
|
||||
int sock;
|
||||
int len;
|
||||
struct sockaddr_un remote;
|
||||
int saved_errno;
|
||||
|
||||
len = x52d_setup_command_sock(sock_path, &remote);
|
||||
if (len < 0) {
|
||||
/* Error when setting up sockaddr */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create a socket */
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock == -1) {
|
||||
|
@ -39,7 +31,7 @@ int x52d_dial_command(const char *sock_path)
|
|||
}
|
||||
|
||||
/* Connect to the socket */
|
||||
if (connect(sock, (struct sockaddr *)&remote, (socklen_t)len) == -1) {
|
||||
if (connect(sock, (struct sockaddr *)remote, (socklen_t)len) == -1) {
|
||||
/* Failure connecting to the socket. Cleanup */
|
||||
saved_errno = errno;
|
||||
/* close may modify errno, so we save it prior to the call */
|
||||
|
@ -51,6 +43,60 @@ int x52d_dial_command(const char *sock_path)
|
|||
return sock;
|
||||
}
|
||||
|
||||
int x52d_dial_command(const char *sock_path)
|
||||
{
|
||||
int len;
|
||||
struct sockaddr_un remote;
|
||||
|
||||
len = x52d_setup_command_sock(sock_path, &remote);
|
||||
if (len < 0) {
|
||||
/* Error when setting up sockaddr */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _setup_socket(&remote, len);
|
||||
}
|
||||
|
||||
int x52d_dial_notify(const char *sock_path)
|
||||
{
|
||||
int len;
|
||||
struct sockaddr_un remote;
|
||||
|
||||
len = x52d_setup_notify_sock(sock_path, &remote);
|
||||
if (len < 0) {
|
||||
/* Error when setting up sockaddr */
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _setup_socket(&remote, len);
|
||||
}
|
||||
|
||||
int x52d_format_command(int argc, const char **argv, char *buffer, size_t buflen)
|
||||
{
|
||||
int msglen;
|
||||
int i;
|
||||
|
||||
if (argc == 0 || argv == NULL || buffer == NULL || buflen < X52D_BUFSZ) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(buffer, 0, buflen);
|
||||
msglen = 0;
|
||||
for (i = 0; i < argc; i++) {
|
||||
int arglen = strlen(argv[i]) + 1;
|
||||
if ((size_t)(msglen + arglen) >= buflen) {
|
||||
errno = E2BIG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(&buffer[msglen], argv[i], arglen);
|
||||
msglen += arglen;
|
||||
}
|
||||
|
||||
return msglen;
|
||||
}
|
||||
|
||||
int x52d_send_command(int sock_fd, char *buffer, size_t bufin, size_t bufout)
|
||||
{
|
||||
int rc;
|
||||
|
@ -94,3 +140,38 @@ int x52d_send_command(int sock_fd, char *buffer, size_t bufin, size_t bufout)
|
|||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int x52d_recv_notification(int sock_fd, x52d_notify_callback_fn callback)
|
||||
{
|
||||
int rc;
|
||||
char buffer[X52D_BUFSZ];
|
||||
int argc;
|
||||
char *argv[X52D_BUFSZ];
|
||||
|
||||
if (callback == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Wait till we get a response */
|
||||
for (;;) {
|
||||
rc = recv(sock_fd, buffer, sizeof(buffer), 0);
|
||||
if (rc < 0) {
|
||||
// Error
|
||||
if (errno == EINTR) {
|
||||
// System call interrupted due to signal. Try again
|
||||
continue;
|
||||
} else {
|
||||
// Failed. Return early
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Split into individual arguments */
|
||||
x52d_split_args(&argc, argv, buffer, rc);
|
||||
|
||||
return callback(argc, argv);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "x52dcomm-internal.h"
|
||||
#include "x52d_const.h"
|
||||
|
@ -23,7 +25,16 @@ const char * x52d_command_sock_path(const char *sock_path)
|
|||
return sock_path;
|
||||
}
|
||||
|
||||
int x52d_setup_command_sock(const char *sock_path, struct sockaddr_un *remote)
|
||||
const char * x52d_notify_sock_path(const char *sock_path)
|
||||
{
|
||||
if (sock_path == NULL) {
|
||||
sock_path = X52D_SOCK_NOTIFY;
|
||||
}
|
||||
|
||||
return sock_path;
|
||||
}
|
||||
|
||||
static int _setup_sockaddr(struct sockaddr_un *remote, const char *sock_path)
|
||||
{
|
||||
int len;
|
||||
if (remote == NULL) {
|
||||
|
@ -31,8 +42,6 @@ int x52d_setup_command_sock(const char *sock_path, struct sockaddr_un *remote)
|
|||
return -1;
|
||||
}
|
||||
|
||||
sock_path = x52d_command_sock_path(sock_path);
|
||||
|
||||
len = strlen(sock_path);
|
||||
if ((size_t)len >= sizeof(remote->sun_path)) {
|
||||
/* Socket path will not fit inside sun_path */
|
||||
|
@ -49,3 +58,54 @@ int x52d_setup_command_sock(const char *sock_path, struct sockaddr_un *remote)
|
|||
|
||||
return len;
|
||||
}
|
||||
|
||||
int x52d_setup_command_sock(const char *sock_path, struct sockaddr_un *remote)
|
||||
{
|
||||
return _setup_sockaddr(remote, x52d_command_sock_path(sock_path));
|
||||
}
|
||||
|
||||
int x52d_setup_notify_sock(const char *sock_path, struct sockaddr_un *remote)
|
||||
{
|
||||
return _setup_sockaddr(remote, x52d_notify_sock_path(sock_path));
|
||||
}
|
||||
|
||||
int x52d_set_socket_nonblocking(int sock_fd)
|
||||
{
|
||||
int flags;
|
||||
|
||||
/* Mark the socket as non-blocking */
|
||||
flags = fcntl(sock_fd, F_GETFL);
|
||||
if (flags < 0) {
|
||||
goto sock_failure;
|
||||
}
|
||||
if (fcntl(sock_fd, F_SETFL, flags | O_NONBLOCK) < 0) {
|
||||
goto sock_failure;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
sock_failure:
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void x52d_split_args(int *argc, char **argv, char *buffer, int buflen)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (i < buflen) {
|
||||
if (buffer[i]) {
|
||||
argv[*argc] = buffer + i;
|
||||
(*argc)++;
|
||||
for (; i < buflen && buffer[i]; i++);
|
||||
// At this point, buffer[i] = '\0'
|
||||
// Skip to the next character.
|
||||
i++;
|
||||
} else {
|
||||
// We should never reach here, unless we have two NULs in a row
|
||||
argv[*argc] = buffer + i;
|
||||
(*argc)++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,104 +24,15 @@
|
|||
#include "x52d_const.h"
|
||||
#include "x52d_command.h"
|
||||
#include "x52d_config.h"
|
||||
#include "x52d_client.h"
|
||||
#include "x52dcomm-internal.h"
|
||||
|
||||
#define MAX_CONN (X52D_MAX_CLIENTS + 1)
|
||||
|
||||
#define INVALID_CLIENT -1
|
||||
|
||||
static int client_fd[X52D_MAX_CLIENTS];
|
||||
static int active_clients;
|
||||
|
||||
static pthread_t command_thr;
|
||||
static int command_sock_fd;
|
||||
static const char *command_sock;
|
||||
|
||||
static void register_client(int sock_fd)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (active_clients >= X52D_MAX_CLIENTS) {
|
||||
/* Ignore the incoming connection */
|
||||
return;
|
||||
}
|
||||
|
||||
fd = accept(sock_fd, NULL, NULL);
|
||||
if (fd < 0) {
|
||||
PINELOG_ERROR(_("Error accepting client connection on command socket: %s"),
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
PINELOG_TRACE("Accepted client %d on command socket", fd);
|
||||
|
||||
for (int i = 0; i < X52D_MAX_CLIENTS; i++) {
|
||||
if (client_fd[i] == INVALID_CLIENT) {
|
||||
client_fd[i] = fd;
|
||||
active_clients++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void deregister_client(int fd)
|
||||
{
|
||||
for (int i = 0; i < X52D_MAX_CLIENTS; i++) {
|
||||
if (client_fd[i] == fd) {
|
||||
client_fd[i] = INVALID_CLIENT;
|
||||
active_clients--;
|
||||
close(fd);
|
||||
|
||||
PINELOG_TRACE("Disconnected client %d from command socket", fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void client_error(int fd)
|
||||
{
|
||||
int error;
|
||||
socklen_t errlen = sizeof(error);
|
||||
|
||||
getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen);
|
||||
PINELOG_ERROR(_("Error when polling command socket: FD %d, error %d, len %lu"),
|
||||
fd, error, (unsigned long int)errlen);
|
||||
deregister_client(fd);
|
||||
}
|
||||
|
||||
static int poll_clients(int sock_fd, struct pollfd *pfd)
|
||||
{
|
||||
int pfd_count;
|
||||
int rc;
|
||||
|
||||
memset(pfd, 0, sizeof(*pfd) * MAX_CONN);
|
||||
|
||||
pfd_count = 1;
|
||||
pfd[0].fd = sock_fd;
|
||||
pfd[0].events = POLLIN | POLLERR;
|
||||
for (int i = 0; i < X52D_MAX_CLIENTS; i++) {
|
||||
if (client_fd[i] != INVALID_CLIENT) {
|
||||
pfd[pfd_count].fd = client_fd[i];
|
||||
pfd[pfd_count].events = POLLIN | POLLERR | POLLHUP;
|
||||
pfd_count++;
|
||||
}
|
||||
}
|
||||
|
||||
PINELOG_TRACE("Polling %d file descriptors", pfd_count);
|
||||
rc = poll(pfd, pfd_count, -1);
|
||||
if (rc < 0) {
|
||||
if (errno != EINTR) {
|
||||
PINELOG_ERROR(_("Error when polling for command: %s"), strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
} else if (rc == 0) {
|
||||
PINELOG_INFO(_("Timed out when polling for command"));
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined __has_attribute
|
||||
# if __has_attribute(format)
|
||||
__attribute((format(printf, 4, 5)))
|
||||
|
@ -131,7 +42,7 @@ static void response_formatted(char *buffer, int *buflen, const char *type,
|
|||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char response[1024];
|
||||
char response[X52D_BUFSZ];
|
||||
int resplen;
|
||||
int typelen;
|
||||
|
||||
|
@ -152,7 +63,7 @@ static void response_formatted(char *buffer, int *buflen, const char *type,
|
|||
static void response_strings(char *buffer, int *buflen, const char *type, int count, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char response[1024];
|
||||
char response[X52D_BUFSZ];
|
||||
int resplen;
|
||||
int arglen;
|
||||
int i;
|
||||
|
@ -351,6 +262,7 @@ static void cmd_logging(char *buffer, int *buflen, int argc, char **argv)
|
|||
[X52D_MOD_LED] = "led",
|
||||
[X52D_MOD_MOUSE] = "mouse",
|
||||
[X52D_MOD_COMMAND] = "command",
|
||||
[X52D_MOD_CLIENT] = "client",
|
||||
};
|
||||
|
||||
// This corresponds to the levels in pinelog
|
||||
|
@ -430,24 +342,9 @@ static void cmd_logging(char *buffer, int *buflen, int argc, char **argv)
|
|||
static void command_parser(char *buffer, int *buflen)
|
||||
{
|
||||
int argc = 0;
|
||||
char *argv[1024] = { 0 };
|
||||
int i = 0;
|
||||
char *argv[X52D_BUFSZ] = { 0 };
|
||||
|
||||
while (i < *buflen) {
|
||||
if (buffer[i]) {
|
||||
argv[argc] = buffer + i;
|
||||
argc++;
|
||||
for (; i < *buflen && buffer[i]; i++);
|
||||
// At this point, buffer[i] = '\0'
|
||||
// Skip to the next character.
|
||||
i++;
|
||||
} else {
|
||||
// We should never reach here, unless we have two NULs in a row
|
||||
argv[argc] = buffer + i;
|
||||
argc++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
x52d_split_args(&argc, argv, buffer, *buflen);
|
||||
|
||||
MATCH(0, "config") {
|
||||
cmd_config(buffer, buflen, argc, argv);
|
||||
|
@ -458,50 +355,41 @@ static void command_parser(char *buffer, int *buflen)
|
|||
}
|
||||
}
|
||||
|
||||
static void client_handler(int fd)
|
||||
{
|
||||
char buffer[X52D_BUFSZ] = { 0 };
|
||||
int sent;
|
||||
int rc;
|
||||
|
||||
rc = recv(fd, buffer, sizeof(buffer), 0);
|
||||
if (rc < 0) {
|
||||
PINELOG_ERROR(_("Error reading from client %d: %s"),
|
||||
fd, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse and handle command.
|
||||
command_parser(buffer, &rc);
|
||||
|
||||
PINELOG_TRACE("Sending %d bytes in response '%s'", rc, buffer);
|
||||
sent = send(fd, buffer, rc, 0);
|
||||
if (sent != rc) {
|
||||
PINELOG_ERROR(_("Short write to client %d; expected %d bytes, wrote %d bytes"),
|
||||
fd, rc, sent);
|
||||
}
|
||||
}
|
||||
|
||||
int x52d_command_loop(int sock_fd)
|
||||
{
|
||||
struct pollfd pfd[MAX_CONN];
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
rc = poll_clients(sock_fd, pfd);
|
||||
rc = x52d_client_poll(client_fd, pfd, sock_fd);
|
||||
if (rc <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_CONN; i++) {
|
||||
if (pfd[i].revents & POLLHUP) {
|
||||
/* Remote hungup */
|
||||
deregister_client(pfd[i].fd);
|
||||
} else if (pfd[i].revents & POLLERR) {
|
||||
/* Error reading from the socket */
|
||||
client_error(pfd[i].fd);
|
||||
} else if (pfd[i].revents & POLLIN) {
|
||||
if (pfd[i].fd == sock_fd) {
|
||||
register_client(sock_fd);
|
||||
} else {
|
||||
char buffer[1024] = { 0 };
|
||||
int sent;
|
||||
|
||||
rc = recv(pfd[i].fd, buffer, sizeof(buffer), 0);
|
||||
if (rc < 0) {
|
||||
PINELOG_ERROR(_("Error reading from client %d: %s"),
|
||||
pfd[i].fd, strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse and handle command.
|
||||
command_parser(buffer, &rc);
|
||||
|
||||
PINELOG_TRACE("Sending %d bytes in response '%s'", rc, buffer);
|
||||
sent = send(pfd[i].fd, buffer, rc, 0);
|
||||
if (sent != rc) {
|
||||
PINELOG_ERROR(_("Short write to client %d; expected %d bytes, wrote %d bytes"),
|
||||
pfd[i].fd, rc, sent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
x52d_client_handle(client_fd, pfd, sock_fd, client_handler);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -525,11 +413,7 @@ int x52d_command_init(const char *sock_path)
|
|||
struct sockaddr_un local;
|
||||
int flags;
|
||||
|
||||
for (int i = 0; i < X52D_MAX_CLIENTS; i++) {
|
||||
client_fd[i] = INVALID_CLIENT;
|
||||
}
|
||||
|
||||
active_clients = 0;
|
||||
x52d_client_init(client_fd);
|
||||
|
||||
command_sock = sock_path;
|
||||
command_sock_fd = -1;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#define X52D_PID_FILE RUNDIR "/" X52D_APP_NAME ".pid"
|
||||
|
||||
#define X52D_SOCK_COMMAND RUNDIR "/" X52D_APP_NAME ".cmd"
|
||||
#define X52D_SOCK_NOTIFY RUNDIR "/" X52D_APP_NAME ".notify"
|
||||
|
||||
#include "gettext.h"
|
||||
#define N_(x) gettext_noop(x)
|
||||
|
@ -33,6 +34,8 @@ enum {
|
|||
X52D_MOD_LED,
|
||||
X52D_MOD_MOUSE,
|
||||
X52D_MOD_COMMAND,
|
||||
X52D_MOD_CLIENT,
|
||||
X52D_MOD_NOTIFY,
|
||||
|
||||
X52D_MOD_MAX
|
||||
};
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "x52d_io.h"
|
||||
#include "x52d_mouse.h"
|
||||
#include "x52d_command.h"
|
||||
#include "x52d_notify.h"
|
||||
#include "x52dcomm-internal.h"
|
||||
#include "x52dcomm.h"
|
||||
#include "pinelog.h"
|
||||
|
@ -90,7 +91,8 @@ static void usage(int exit_code)
|
|||
_("Usage: %s [-f] [-v] [-q]\n"
|
||||
"\t[-l log-file] [-o override]\n"
|
||||
"\t[-c config-file] [-p pid-file]\n"
|
||||
"\t[-s command-socket-path]\n"),
|
||||
"\t[-s command-socket-path]\n"
|
||||
"\t[-b notify-socket-path]\n"),
|
||||
X52D_APP_NAME);
|
||||
exit(exit_code);
|
||||
}
|
||||
|
@ -205,6 +207,7 @@ int main(int argc, char **argv)
|
|||
char *conf_file = NULL;
|
||||
const char *pid_file = NULL;
|
||||
const char *command_sock = NULL;
|
||||
const char *notify_sock = NULL;
|
||||
int opt;
|
||||
int rc;
|
||||
sigset_t sigblockset;
|
||||
|
@ -231,8 +234,9 @@ int main(int argc, char **argv)
|
|||
* -l path to log file
|
||||
* -p path to PID file (only used if running in background)
|
||||
* -s path to command socket
|
||||
* -b path to notify socket
|
||||
*/
|
||||
while ((opt = getopt(argc, argv, "fvql:o:c:p:s:h")) != -1) {
|
||||
while ((opt = getopt(argc, argv, "fvql:o:c:p:s:b:h")) != -1) {
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
foreground = true;
|
||||
|
@ -277,6 +281,10 @@ int main(int argc, char **argv)
|
|||
command_sock = optarg;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
notify_sock = optarg;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage(EXIT_SUCCESS);
|
||||
break;
|
||||
|
@ -314,6 +322,7 @@ int main(int argc, char **argv)
|
|||
if (x52d_command_init(command_sock) < 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
x52d_notify_init(notify_sock);
|
||||
#if defined(HAVE_EVDEV)
|
||||
x52d_io_init();
|
||||
x52d_mouse_evdev_init();
|
||||
|
@ -355,6 +364,7 @@ cleanup:
|
|||
x52d_clock_exit();
|
||||
x52d_dev_exit();
|
||||
x52d_command_exit();
|
||||
x52d_notify_exit();
|
||||
#if defined(HAVE_EVDEV)
|
||||
x52d_mouse_evdev_exit();
|
||||
x52d_io_exit();
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver - Notification manager
|
||||
*
|
||||
* Copyright (C) 2022 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define PINELOG_MODULE X52D_MOD_NOTIFY
|
||||
#include "pinelog.h"
|
||||
#include "x52d_const.h"
|
||||
#include "x52d_notify.h"
|
||||
#include "x52d_client.h"
|
||||
#include "x52dcomm.h"
|
||||
#include "x52dcomm-internal.h"
|
||||
|
||||
static pthread_t notify_thr;
|
||||
static pthread_t notify_listen;
|
||||
static pthread_mutex_t notify_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static int notify_pipe[2];
|
||||
static int notify_sock;
|
||||
|
||||
static int client_fd[X52D_MAX_CLIENTS];
|
||||
|
||||
/* Bind and listen to the notify socket */
|
||||
static int listen_notify(const char *notify_sock_path)
|
||||
{
|
||||
int sock_fd;
|
||||
int len;
|
||||
struct sockaddr_un local;
|
||||
|
||||
len = x52d_setup_notify_sock(notify_sock_path, &local);
|
||||
if (len < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock_fd < 0) {
|
||||
/* Failure creating the socket. Abort early */
|
||||
PINELOG_ERROR(_("Error creating notification socket: %s"), strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (x52d_set_socket_nonblocking(sock_fd) < 0) {
|
||||
PINELOG_ERROR(_("Error marking notification socket as nonblocking: %s"), strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Cleanup any existing socket */
|
||||
unlink(local.sun_path);
|
||||
if (bind(sock_fd, (struct sockaddr *)&local, (socklen_t)len) < 0) {
|
||||
/* Failure binding socket */
|
||||
PINELOG_ERROR(_("Error binding to notification socket: %s"), strerror(errno));
|
||||
goto listen_failure;
|
||||
}
|
||||
|
||||
if (listen(sock_fd, X52D_MAX_CLIENTS) < 0) {
|
||||
PINELOG_ERROR(_("Error listening on notification socket: %s"), strerror(errno));
|
||||
goto listen_failure;
|
||||
}
|
||||
|
||||
return sock_fd;
|
||||
|
||||
listen_failure:
|
||||
unlink(local.sun_path);
|
||||
close(sock_fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void * x52_notify_thr(void * param)
|
||||
{
|
||||
char buffer[X52D_BUFSZ];
|
||||
uint16_t bufsiz;
|
||||
int rc;
|
||||
|
||||
for (;;) {
|
||||
read_pipe_size:
|
||||
rc = read(notify_pipe[0], &bufsiz, sizeof(bufsiz));
|
||||
if (rc < 0) {
|
||||
if (errno == EINTR) {
|
||||
goto read_pipe_size;
|
||||
} else {
|
||||
PINELOG_ERROR(_("Error %d reading from pipe: %s"),
|
||||
errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
// Error condition, try again
|
||||
continue;
|
||||
}
|
||||
|
||||
read_pipe_data:
|
||||
rc = read(notify_pipe[0], buffer, bufsiz);
|
||||
if (rc < 0) {
|
||||
if (errno == EINTR) {
|
||||
goto read_pipe_data;
|
||||
} else {
|
||||
PINELOG_ERROR(_("Error %d reading from pipe: %s"),
|
||||
errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < X52D_MAX_CLIENTS; i++) {
|
||||
// Broadcast to every connected client
|
||||
if (client_fd[i] != INVALID_CLIENT) {
|
||||
write_client_notification:
|
||||
rc = write(client_fd[i], buffer, bufsiz);
|
||||
if (rc < 0 && errno == EINTR) {
|
||||
goto write_client_notification;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void x52d_notify_send(int argc, const char **argv)
|
||||
{
|
||||
char buffer[X52D_BUFSZ + sizeof(uint16_t)];
|
||||
uint16_t bufsiz;
|
||||
uint16_t written;
|
||||
int rc;
|
||||
|
||||
bufsiz = (uint16_t)x52d_format_command(argc, argv, buffer + sizeof(uint16_t), X52D_BUFSZ);
|
||||
memcpy(buffer, &bufsiz, sizeof(bufsiz));
|
||||
|
||||
pthread_mutex_lock(¬ify_mutex);
|
||||
written = 0;
|
||||
while (written < bufsiz) {
|
||||
rc = write(notify_pipe[1], buffer + written, bufsiz - written);
|
||||
if (rc < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
PINELOG_ERROR(_("Error %d writing notification pipe: %s"),
|
||||
errno, strerror(errno));
|
||||
} else {
|
||||
written += rc;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(¬ify_mutex);
|
||||
}
|
||||
|
||||
static void client_handler(int fd)
|
||||
{
|
||||
char buffer[X52D_BUFSZ] = { 0 };
|
||||
int rc;
|
||||
|
||||
rc = recv(fd, buffer, sizeof(buffer), 0);
|
||||
PINELOG_TRACE("Received and discarded %d bytes from notification client %d", rc, fd);
|
||||
}
|
||||
|
||||
static void * x52_notify_loop(void * param)
|
||||
{
|
||||
struct pollfd pfd[MAX_CONN];
|
||||
int rc;
|
||||
|
||||
for (;;) {
|
||||
rc = x52d_client_poll(client_fd, pfd, notify_sock);
|
||||
if (rc <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
x52d_client_handle(client_fd, pfd, notify_sock, client_handler);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void x52d_notify_init(const char *notify_sock_path)
|
||||
{
|
||||
int rc;
|
||||
|
||||
PINELOG_TRACE("Initializing notification manager");
|
||||
x52d_client_init(client_fd);
|
||||
|
||||
PINELOG_TRACE("Creating notifications pipe");
|
||||
rc = pipe(notify_pipe);
|
||||
if (rc != 0) {
|
||||
PINELOG_FATAL(_("Error %d creating notification pipe: %s"),
|
||||
errno, strerror(errno));
|
||||
}
|
||||
|
||||
PINELOG_TRACE("Opening notification listener socket");
|
||||
notify_sock = listen_notify(notify_sock_path);
|
||||
|
||||
rc = pthread_create(¬ify_thr, NULL, x52_notify_thr, NULL);
|
||||
if (rc != 0) {
|
||||
PINELOG_FATAL(_("Error %d initializing notify thread: %s"),
|
||||
rc, strerror(rc));
|
||||
}
|
||||
|
||||
rc = pthread_create(¬ify_listen, NULL, x52_notify_loop, NULL);
|
||||
if (rc != 0) {
|
||||
PINELOG_FATAL(_("Error %d initializing notify listener: %s"),
|
||||
rc, strerror(rc));
|
||||
}
|
||||
}
|
||||
|
||||
void x52d_notify_exit(void)
|
||||
{
|
||||
close(notify_pipe[0]);
|
||||
close(notify_pipe[1]);
|
||||
close(notify_sock);
|
||||
|
||||
pthread_cancel(notify_thr);
|
||||
pthread_cancel(notify_listen);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver - Notification manager
|
||||
*
|
||||
* Copyright (C) 2022 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#ifndef X52D_NOTIFY_H
|
||||
#define X52D_NOTIFY_H
|
||||
|
||||
void x52d_notify_init(const char *notify_sock_path);
|
||||
void x52d_notify_exit(void);
|
||||
void x52d_notify_send(int argc, const char **argv);
|
||||
|
||||
#endif // !defined X52D_NOTIFY_H
|
||||
|
|
@ -13,7 +13,13 @@
|
|||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#define X52D_BUFSZ 1024
|
||||
|
||||
const char *x52d_command_sock_path(const char *sock_path);
|
||||
int x52d_setup_command_sock(const char *sock_path, struct sockaddr_un *remote);
|
||||
const char *x52d_notify_sock_path(const char *sock_path);
|
||||
int x52d_setup_notify_sock(const char *sock_path, struct sockaddr_un *remote);
|
||||
int x52d_set_socket_nonblocking(int sock_fd);
|
||||
void x52d_split_args(int *argc, char **argv, char *buffer, int buflen);
|
||||
|
||||
#endif // !defined X52DCOMM_INTERNAL_H
|
||||
|
|
|
@ -35,7 +35,7 @@ extern "C" {
|
|||
*/
|
||||
|
||||
/**
|
||||
* @brief Open a connection to the daemon.
|
||||
* @brief Open a connection to the daemon command socket.
|
||||
*
|
||||
* This method opens a socket connection to the daemon command socket. This
|
||||
* socket allows the client to issue commands and retrieve data. The \p sock_path
|
||||
|
@ -54,6 +54,46 @@ extern "C" {
|
|||
*/
|
||||
int x52d_dial_command(const char *sock_path);
|
||||
|
||||
/**
|
||||
* @brief Open a connection to the daemon notify socket.
|
||||
*
|
||||
* This method opens a socket connection to the daemon notify socket. This
|
||||
* socket allows the client to receive notifications from the daemon. Thej
|
||||
* \p sock_path parameter may be NULL, in which case, it will use the default
|
||||
* socket path.
|
||||
*
|
||||
* The client will need to use the returned descriptor to communicate with the
|
||||
* daemon using \ref x52d_recv_notification. Once finished, the client may use
|
||||
* the \c close(2) method to close the file descriptor.
|
||||
*
|
||||
* @param[in] sock_path Path to the daemon command socket.
|
||||
*
|
||||
* @returns Non-negative socket file descriptor on success.
|
||||
* @returns -1 on failure, and set \c errno accordingly.
|
||||
*
|
||||
* @exception E2BIG returned if the passed socket path is too big
|
||||
*/
|
||||
int x52d_dial_notify(const char *sock_path);
|
||||
|
||||
/**
|
||||
* @brief Format a series of command strings into a buffer
|
||||
*
|
||||
* The client sends the command and parameters as a series of NUL terminated
|
||||
* strings. This function concatenates the commands into a single buffer that
|
||||
* can be passed to \ref x52d_send_command.
|
||||
*
|
||||
* \p buffer should be at least 1024 bytes long.
|
||||
*
|
||||
* @param[in] argc Number of arguments to fit in the buffer
|
||||
* @param[in] argv Pointer to an array of arguments.
|
||||
* @param[out] buffer Buffer to store the formatted command
|
||||
* @param[in] buflen Length of the buffer
|
||||
*
|
||||
* @returns number of bytes in the formatted command
|
||||
* @returns -1 on an error condition, and \c errno is set accordingly.
|
||||
*/
|
||||
int x52d_format_command(int argc, const char **argv, char *buffer, size_t buflen);
|
||||
|
||||
/**
|
||||
* @brief Send a command to the daemon and retrieve the response.
|
||||
*
|
||||
|
@ -83,6 +123,32 @@ int x52d_dial_command(const char *sock_path);
|
|||
*/
|
||||
int x52d_send_command(int sock_fd, char *buffer, size_t bufin, size_t bufout);
|
||||
|
||||
/**
|
||||
* @brief Notification callback function type
|
||||
*/
|
||||
typedef int (* x52d_notify_callback_fn)(int argc, char **argv);
|
||||
|
||||
/**
|
||||
* @brief Receive a notification from the daemon
|
||||
*
|
||||
* This function blocks until it receives a notification from the daemon. Once
|
||||
* it receives a notification successfully, it will call the callback function
|
||||
* with the arguments as string pointers. It will return the return value of
|
||||
* the callback function, if it was called.
|
||||
*
|
||||
* This is a blocking function and will not return until either a notification
|
||||
* is received from the server, or an exception condition occurs.
|
||||
*
|
||||
* @param[in] sock_fd Socket descriptor returned from
|
||||
* \ref x52d_dial_notify
|
||||
*
|
||||
* @param[in] callback Pointer to the callback function
|
||||
*
|
||||
* @returns return code of the callback function on success
|
||||
* @returns -1 on an error condition, and \c errno is set accordingly.
|
||||
*/
|
||||
int x52d_recv_notification(int sock_fd, x52d_notify_callback_fn callback);
|
||||
|
||||
/** @} */
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -665,51 +665,51 @@ msgstr ""
|
|||
msgid "Timed out when polling for command"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_command.c:488
|
||||
#: daemon/x52d_command.c:473
|
||||
#, c-format
|
||||
msgid "Error reading from client %d: %s"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_command.c:499
|
||||
#: daemon/x52d_command.c:484
|
||||
#, c-format
|
||||
msgid "Short write to client %d; expected %d bytes, wrote %d bytes"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_command.c:513
|
||||
#: daemon/x52d_command.c:498
|
||||
#, c-format
|
||||
msgid "Error %d during command loop: %s"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_command.c:545
|
||||
#: daemon/x52d_command.c:530
|
||||
#, c-format
|
||||
msgid "Error creating command socket: %s"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_command.c:552
|
||||
#: daemon/x52d_command.c:537
|
||||
#, c-format
|
||||
msgid "Error getting command socket flags: %s"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_command.c:556
|
||||
#: daemon/x52d_command.c:541
|
||||
#, c-format
|
||||
msgid "Error setting command socket flags: %s"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_command.c:564
|
||||
#: daemon/x52d_command.c:549
|
||||
#, c-format
|
||||
msgid "Error binding to command socket: %s"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_command.c:569
|
||||
#: daemon/x52d_command.c:554
|
||||
#, c-format
|
||||
msgid "Error listening on command socket: %s"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_command.c:579
|
||||
#: daemon/x52d_command.c:564
|
||||
msgid "Starting command processing thread"
|
||||
msgstr ""
|
||||
|
||||
#: daemon/x52d_command.c:597
|
||||
#: daemon/x52d_command.c:582
|
||||
msgid "Shutting down command processing thread"
|
||||
msgstr ""
|
||||
|
||||
|
|
20
po/xx_PL.po
20
po/xx_PL.po
|
@ -716,52 +716,52 @@ msgstr "Erroray enwhay ollingpay orfay ommandcay: %s"
|
|||
msgid "Timed out when polling for command"
|
||||
msgstr "Imedtay outay enwhay ollingpay orfay ommandcay"
|
||||
|
||||
#: daemon/x52d_command.c:488
|
||||
#: daemon/x52d_command.c:473
|
||||
#, c-format
|
||||
msgid "Error reading from client %d: %s"
|
||||
msgstr "Erroray eadingray omfray ientclay %d: %s"
|
||||
|
||||
#: daemon/x52d_command.c:499
|
||||
#: daemon/x52d_command.c:484
|
||||
#, c-format
|
||||
msgid "Short write to client %d; expected %d bytes, wrote %d bytes"
|
||||
msgstr ""
|
||||
"Ortshay itewray otay ientclay %d; expecteday %d ytesbay, otewray %d ytesbay"
|
||||
|
||||
#: daemon/x52d_command.c:513
|
||||
#: daemon/x52d_command.c:498
|
||||
#, c-format
|
||||
msgid "Error %d during command loop: %s"
|
||||
msgstr "Erroray %d uringday ommandcay ooplay: %s"
|
||||
|
||||
#: daemon/x52d_command.c:545
|
||||
#: daemon/x52d_command.c:530
|
||||
#, c-format
|
||||
msgid "Error creating command socket: %s"
|
||||
msgstr "Erroray eatingcray ommandcay ocketsay: %s"
|
||||
|
||||
#: daemon/x52d_command.c:552
|
||||
#: daemon/x52d_command.c:537
|
||||
#, c-format
|
||||
msgid "Error getting command socket flags: %s"
|
||||
msgstr "Erroray ettinggay ommandcay ocketsay agsflay: %s"
|
||||
|
||||
#: daemon/x52d_command.c:556
|
||||
#: daemon/x52d_command.c:541
|
||||
#, c-format
|
||||
msgid "Error setting command socket flags: %s"
|
||||
msgstr "Erroray ettingsay ommandcay ocketsay agsflay: %s"
|
||||
|
||||
#: daemon/x52d_command.c:564
|
||||
#: daemon/x52d_command.c:549
|
||||
#, c-format
|
||||
msgid "Error binding to command socket: %s"
|
||||
msgstr "Erroray indingbay otay ommandcay ocketsay: %s"
|
||||
|
||||
#: daemon/x52d_command.c:569
|
||||
#: daemon/x52d_command.c:554
|
||||
#, c-format
|
||||
msgid "Error listening on command socket: %s"
|
||||
msgstr "Erroray isteninglay onay ommandcay ocketsay: %s"
|
||||
|
||||
#: daemon/x52d_command.c:579
|
||||
#: daemon/x52d_command.c:564
|
||||
msgid "Starting command processing thread"
|
||||
msgstr "Artingstay ommandcay ocessingpray eadthray"
|
||||
|
||||
#: daemon/x52d_command.c:597
|
||||
#: daemon/x52d_command.c:582
|
||||
msgid "Shutting down command processing thread"
|
||||
msgstr "Uttingshay ownday ommandcay ocessingpray eadthray"
|
||||
|
||||
|
|
Loading…
Reference in New Issue