mirror of https://github.com/nirenjan/libx52.git
				
				
				
			Add command parsing and response logic
This change adds the generic command parsing logic, as well as the response for the following commands: * config load <file> * config reload * config save * config dump <file>reverse-scroll
							parent
							
								
									eb98804607
								
							
						
					
					
						commit
						7b8c71dd35
					
				| 
						 | 
					@ -7,16 +7,21 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdarg.h>
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
#include <poll.h>
 | 
					#include <poll.h>
 | 
				
			||||||
 | 
					#include <signal.h>
 | 
				
			||||||
#include <sys/types.h>
 | 
					#include <sys/types.h>
 | 
				
			||||||
#include <sys/socket.h>
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <arpa/inet.h>
 | 
				
			||||||
#include <unistd.h>
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "pinelog.h"
 | 
					#include "pinelog.h"
 | 
				
			||||||
#include "x52d_const.h"
 | 
					#include "x52d_const.h"
 | 
				
			||||||
#include "x52d_command.h"
 | 
					#include "x52d_command.h"
 | 
				
			||||||
 | 
					#include "x52d_config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_CONN    (X52D_MAX_CLIENTS + 1)
 | 
					#define MAX_CONN    (X52D_MAX_CLIENTS + 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -119,6 +124,182 @@ static int poll_clients(int sock_fd, struct pollfd *pfd)
 | 
				
			||||||
    return rc;
 | 
					    return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined __has_attribute
 | 
				
			||||||
 | 
					#   if __has_attribute(format)
 | 
				
			||||||
 | 
					        __attribute((format(printf, 4, 5)))
 | 
				
			||||||
 | 
					#   endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					static void response_formatted(char *buffer, int *buflen, const char *type,
 | 
				
			||||||
 | 
					                               const char *fmt, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    va_list ap;
 | 
				
			||||||
 | 
					    char response[1024];
 | 
				
			||||||
 | 
					    int resplen;
 | 
				
			||||||
 | 
					    int typelen;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    typelen = strlen(type) + 1;
 | 
				
			||||||
 | 
					    strcpy(response + 2, type);
 | 
				
			||||||
 | 
					    resplen = typelen + 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (*fmt) {
 | 
				
			||||||
 | 
					        va_start(ap, fmt);
 | 
				
			||||||
 | 
					        resplen += vsnprintf(response + typelen, sizeof(response) - typelen, fmt, ap);
 | 
				
			||||||
 | 
					        va_end(ap);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    typelen = htons(resplen);
 | 
				
			||||||
 | 
					    memcpy(response, &typelen, 2);
 | 
				
			||||||
 | 
					    memcpy(buffer, response, resplen);
 | 
				
			||||||
 | 
					    *buflen = resplen;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void response_strings(char *buffer, int *buflen, const char *type, int count, ...)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    va_list ap;
 | 
				
			||||||
 | 
					    char response[1024];
 | 
				
			||||||
 | 
					    int resplen;
 | 
				
			||||||
 | 
					    int arglen;
 | 
				
			||||||
 | 
					    int i;
 | 
				
			||||||
 | 
					    char *arg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arglen = strlen(type) + 1;
 | 
				
			||||||
 | 
					    strcpy(response + 2, type);
 | 
				
			||||||
 | 
					    resplen = arglen + 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    va_start(ap, count);
 | 
				
			||||||
 | 
					    for (i = 0; i < count; i++) {
 | 
				
			||||||
 | 
					        arg = va_arg(ap, char *);
 | 
				
			||||||
 | 
					        arglen = strlen(arg) + 1;
 | 
				
			||||||
 | 
					        if ((size_t)(arglen + resplen) >= sizeof(response)) {
 | 
				
			||||||
 | 
					            PINELOG_ERROR("Too many arguments for response_strings %s", type);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        strcpy(response + resplen, arg);
 | 
				
			||||||
 | 
					        resplen += arglen;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    va_end(ap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    arglen = htons(resplen);
 | 
				
			||||||
 | 
					    memcpy(response, &arglen, 2);
 | 
				
			||||||
 | 
					    memcpy(buffer, response, resplen);
 | 
				
			||||||
 | 
					    *buflen = resplen;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NUMARGS(...) (sizeof((const char *[]){__VA_ARGS__}) / sizeof(const char *))
 | 
				
			||||||
 | 
					#define ERR(...) response_strings(buffer, buflen, "ERR", NUMARGS(__VA_ARGS__), ##__VA_ARGS__)
 | 
				
			||||||
 | 
					#define ERR_fmt(fmt, ...) response_formatted(buffer, buflen, "ERR", fmt, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define OK(...) response_strings(buffer, buflen, "OK", NUMARGS(__VA_ARGS__), ##__VA_ARGS__)
 | 
				
			||||||
 | 
					#define OK_fmt(fmt, ...) response_formatted(buffer, buflen, "OK", fmt, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MATCH(idx, cmd) if (strcasecmp(argv[idx], cmd) == 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool check_file(const char *file_path, int mode)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (*file_path == '\0') {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (mode && access(file_path, mode)) {
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void cmd_config(char *buffer, int *buflen, int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (argc < 2) {
 | 
				
			||||||
 | 
					        ERR("Insufficient arguments for 'config' command");
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MATCH(1, "load") {
 | 
				
			||||||
 | 
					        if (argc == 3) {
 | 
				
			||||||
 | 
					            if (!check_file(argv[2], R_OK)) {
 | 
				
			||||||
 | 
					                ERR_fmt("Invalid file '%s' for 'config load' command", argv[2]);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            x52d_config_load(argv[2]);
 | 
				
			||||||
 | 
					            x52d_config_apply();
 | 
				
			||||||
 | 
					            OK("load", argv[2]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            // Invalid number of args
 | 
				
			||||||
 | 
					            ERR_fmt("Unexpected arguments for 'config load' command; got %d, expected 3", argc);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MATCH(1, "reload") {
 | 
				
			||||||
 | 
					        if (argc == 2) {
 | 
				
			||||||
 | 
					            raise(SIGHUP);
 | 
				
			||||||
 | 
					            OK("reload");
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ERR_fmt("Unexpected arguments for 'config reload' command; got %d, expected 2", argc);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MATCH(1, "dump") {
 | 
				
			||||||
 | 
					        if (argc == 3) {
 | 
				
			||||||
 | 
					            if (!check_file(argv[2], 0)) {
 | 
				
			||||||
 | 
					                ERR_fmt("Invalid file '%s' for 'config dump' command", argv[2]);
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            x52d_config_save(argv[2]);
 | 
				
			||||||
 | 
					            OK("dump", argv[2]);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ERR_fmt("Unexpected arguments for 'config dump' command; got %d, expected 3", argc);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MATCH(1, "save") {
 | 
				
			||||||
 | 
					        if (argc == 2) {
 | 
				
			||||||
 | 
					            raise(SIGUSR1);
 | 
				
			||||||
 | 
					            OK("save");
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ERR_fmt("Unexpected arguments for 'config save' command; got %d, expected 2", argc);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ERR_fmt("Unknown subcommand '%s' for 'config' command", argv[1]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void command_parser(char *buffer, int *buflen)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int argc = 0;
 | 
				
			||||||
 | 
					    char *argv[512] = { 0 };
 | 
				
			||||||
 | 
					    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++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    MATCH(0, "config") {
 | 
				
			||||||
 | 
					        cmd_config(buffer, buflen, argc, argv);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        ERR("Unknown command '%s'", argv[0]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int x52d_command_loop(int sock_fd)
 | 
					int x52d_command_loop(int sock_fd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct pollfd pfd[MAX_CONN];
 | 
					    struct pollfd pfd[MAX_CONN];
 | 
				
			||||||
| 
						 | 
					@ -141,7 +322,7 @@ int x52d_command_loop(int sock_fd)
 | 
				
			||||||
            if (pfd[i].fd == sock_fd) {
 | 
					            if (pfd[i].fd == sock_fd) {
 | 
				
			||||||
                register_client(sock_fd);
 | 
					                register_client(sock_fd);
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                char buffer[1024];
 | 
					                char buffer[1024] = { 0 };
 | 
				
			||||||
                int sent;
 | 
					                int sent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                rc = recv(pfd[i].fd, buffer, sizeof(buffer), 0);
 | 
					                rc = recv(pfd[i].fd, buffer, sizeof(buffer), 0);
 | 
				
			||||||
| 
						 | 
					@ -151,8 +332,10 @@ int x52d_command_loop(int sock_fd)
 | 
				
			||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // TODO: Parse and handle command.
 | 
					                // Parse and handle command.
 | 
				
			||||||
                // Echo it back to the client for now.
 | 
					                command_parser(buffer, &rc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                PINELOG_TRACE("Sending %d bytes in response '%s'", rc, buffer);
 | 
				
			||||||
                sent = send(pfd[i].fd, buffer, rc, 0);
 | 
					                sent = send(pfd[i].fd, buffer, rc, 0);
 | 
				
			||||||
                if (sent != rc) {
 | 
					                if (sent != rc) {
 | 
				
			||||||
                    PINELOG_ERROR(_("Short write to client %d; expected %d bytes, wrote %d bytes"),
 | 
					                    PINELOG_ERROR(_("Short write to client %d; expected %d bytes, wrote %d bytes"),
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@ msgid ""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Project-Id-Version: libx52 0.2.3\n"
 | 
					"Project-Id-Version: libx52 0.2.3\n"
 | 
				
			||||||
"Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\n"
 | 
					"Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\n"
 | 
				
			||||||
"POT-Creation-Date: 2021-11-04 22:04-0700\n"
 | 
					"POT-Creation-Date: 2021-11-05 15:09-0700\n"
 | 
				
			||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
					"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
				
			||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
					"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 | 
				
			||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
					"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
				
			||||||
| 
						 | 
					@ -659,31 +659,31 @@ msgstr ""
 | 
				
			||||||
msgid "Shutting down X52 clock manager thread"
 | 
					msgid "Shutting down X52 clock manager thread"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: daemon/x52d_command.c:48
 | 
					#: daemon/x52d_command.c:53
 | 
				
			||||||
#, c-format
 | 
					#, c-format
 | 
				
			||||||
msgid "Error accepting client connection on command socket: %s"
 | 
					msgid "Error accepting client connection on command socket: %s"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: daemon/x52d_command.c:85
 | 
					#: daemon/x52d_command.c:90
 | 
				
			||||||
#, c-format
 | 
					#, c-format
 | 
				
			||||||
msgid "Error when polling command socket: FD %d, error %d, len %lu"
 | 
					msgid "Error when polling command socket: FD %d, error %d, len %lu"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: daemon/x52d_command.c:112
 | 
					#: daemon/x52d_command.c:117
 | 
				
			||||||
#, c-format
 | 
					#, c-format
 | 
				
			||||||
msgid "Error when polling for command: %s"
 | 
					msgid "Error when polling for command: %s"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: daemon/x52d_command.c:116
 | 
					#: daemon/x52d_command.c:121
 | 
				
			||||||
msgid "Timed out when polling for command"
 | 
					msgid "Timed out when polling for command"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: daemon/x52d_command.c:149
 | 
					#: daemon/x52d_command.c:330
 | 
				
			||||||
#, c-format
 | 
					#, c-format
 | 
				
			||||||
msgid "Error reading from client %d: %s"
 | 
					msgid "Error reading from client %d: %s"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: daemon/x52d_command.c:158
 | 
					#: daemon/x52d_command.c:341
 | 
				
			||||||
#, c-format
 | 
					#, c-format
 | 
				
			||||||
msgid "Short write to client %d; expected %d bytes, wrote %d bytes"
 | 
					msgid "Short write to client %d; expected %d bytes, wrote %d bytes"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								po/xx_PL.po
								
								
								
								
							
							
						
						
									
										14
									
								
								po/xx_PL.po
								
								
								
								
							| 
						 | 
					@ -7,7 +7,7 @@ msgid ""
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Project-Id-Version: libx52 0.2.3\n"
 | 
					"Project-Id-Version: libx52 0.2.3\n"
 | 
				
			||||||
"Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\n"
 | 
					"Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\n"
 | 
				
			||||||
"POT-Creation-Date: 2021-11-04 22:04-0700\n"
 | 
					"POT-Creation-Date: 2021-11-05 15:09-0700\n"
 | 
				
			||||||
"PO-Revision-Date: 2021-11-04 15:35-0700\n"
 | 
					"PO-Revision-Date: 2021-11-04 15:35-0700\n"
 | 
				
			||||||
"Last-Translator: Nirenjan Krishnan <nirenjan@gmail.com>\n"
 | 
					"Last-Translator: Nirenjan Krishnan <nirenjan@gmail.com>\n"
 | 
				
			||||||
"Language-Team: Dummy Language for testing i18n\n"
 | 
					"Language-Team: Dummy Language for testing i18n\n"
 | 
				
			||||||
| 
						 | 
					@ -709,32 +709,32 @@ msgstr "Erroray %d initializingay ockclay eadthray: %s"
 | 
				
			||||||
msgid "Shutting down X52 clock manager thread"
 | 
					msgid "Shutting down X52 clock manager thread"
 | 
				
			||||||
msgstr "Uttingshay ownday X52 ockclay anagermay eadthray"
 | 
					msgstr "Uttingshay ownday X52 ockclay anagermay eadthray"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: daemon/x52d_command.c:48
 | 
					#: daemon/x52d_command.c:53
 | 
				
			||||||
#, c-format
 | 
					#, c-format
 | 
				
			||||||
msgid "Error accepting client connection on command socket: %s"
 | 
					msgid "Error accepting client connection on command socket: %s"
 | 
				
			||||||
msgstr "Erroray acceptingay ientclay onnectioncay onay ommandcay ocketsay: %s"
 | 
					msgstr "Erroray acceptingay ientclay onnectioncay onay ommandcay ocketsay: %s"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: daemon/x52d_command.c:85
 | 
					#: daemon/x52d_command.c:90
 | 
				
			||||||
#, c-format
 | 
					#, c-format
 | 
				
			||||||
msgid "Error when polling command socket: FD %d, error %d, len %lu"
 | 
					msgid "Error when polling command socket: FD %d, error %d, len %lu"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Erroray enwhay ollingpay ommandcay ocketsay: FDay %d, erroray %d, enlay %lu"
 | 
					"Erroray enwhay ollingpay ommandcay ocketsay: FDay %d, erroray %d, enlay %lu"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: daemon/x52d_command.c:112
 | 
					#: daemon/x52d_command.c:117
 | 
				
			||||||
#, c-format
 | 
					#, c-format
 | 
				
			||||||
msgid "Error when polling for command: %s"
 | 
					msgid "Error when polling for command: %s"
 | 
				
			||||||
msgstr "Erroray enwhay ollingpay orfay ommandcay: %s"
 | 
					msgstr "Erroray enwhay ollingpay orfay ommandcay: %s"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: daemon/x52d_command.c:116
 | 
					#: daemon/x52d_command.c:121
 | 
				
			||||||
msgid "Timed out when polling for command"
 | 
					msgid "Timed out when polling for command"
 | 
				
			||||||
msgstr "Imedtay outay enwhay ollingpay orfay ommandcay"
 | 
					msgstr "Imedtay outay enwhay ollingpay orfay ommandcay"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: daemon/x52d_command.c:149
 | 
					#: daemon/x52d_command.c:330
 | 
				
			||||||
#, c-format
 | 
					#, c-format
 | 
				
			||||||
msgid "Error reading from client %d: %s"
 | 
					msgid "Error reading from client %d: %s"
 | 
				
			||||||
msgstr "Erroray eadingray omfray ientclay %d: %s"
 | 
					msgstr "Erroray eadingray omfray ientclay %d: %s"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: daemon/x52d_command.c:158
 | 
					#: daemon/x52d_command.c:341
 | 
				
			||||||
#, c-format
 | 
					#, c-format
 | 
				
			||||||
msgid "Short write to client %d; expected %d bytes, wrote %d bytes"
 | 
					msgid "Short write to client %d; expected %d bytes, wrote %d bytes"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue