Add wayvncctl --wait option
Signed-off-by: Jim Ramsay <i.am@jimramsay.com>pull/186/head
parent
372b530d3a
commit
6e13974b27
|
@ -28,5 +28,6 @@ void* ctl_client_userdata(struct ctl_client*);
|
||||||
|
|
||||||
#define PRINT_JSON 0x00000001
|
#define PRINT_JSON 0x00000001
|
||||||
|
|
||||||
|
int ctl_client_connect(struct ctl_client* self, int timeout);
|
||||||
int ctl_client_run_command(struct ctl_client* self,
|
int ctl_client_run_command(struct ctl_client* self,
|
||||||
int argc, char* argv[], unsigned flags);
|
int argc, char* argv[], unsigned flags);
|
||||||
|
|
|
@ -20,8 +20,10 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <jansson.h>
|
#include <jansson.h>
|
||||||
|
|
||||||
#include "json-ipc.h"
|
#include "json-ipc.h"
|
||||||
|
@ -39,11 +41,12 @@ static bool do_debug = false;
|
||||||
if (do_debug) \
|
if (do_debug) \
|
||||||
fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__);
|
fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__);
|
||||||
|
|
||||||
#define FAILED_TO(action) \
|
#define FAILED_TO(action, ...) \
|
||||||
WARN("Failed to " action ": %m");
|
WARN("Failed to " action ": %m", ##__VA_ARGS__);
|
||||||
|
|
||||||
struct ctl_client {
|
struct ctl_client {
|
||||||
void* userdata;
|
void* userdata;
|
||||||
|
struct sockaddr_un addr;
|
||||||
|
|
||||||
char read_buffer[512];
|
char read_buffer[512];
|
||||||
size_t read_len;
|
size_t read_len;
|
||||||
|
@ -65,37 +68,76 @@ struct ctl_client* ctl_client_new(const char* socket_path, void* userdata)
|
||||||
struct ctl_client* new = calloc(1, sizeof(*new));
|
struct ctl_client* new = calloc(1, sizeof(*new));
|
||||||
new->userdata = userdata;
|
new->userdata = userdata;
|
||||||
|
|
||||||
struct sockaddr_un addr = {
|
if (strlen(socket_path) >= sizeof(new->addr.sun_path)) {
|
||||||
.sun_family = AF_UNIX,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (strlen(socket_path) >= sizeof(addr.sun_path)) {
|
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
FAILED_TO("create unix socket");
|
FAILED_TO("create unix socket");
|
||||||
goto socket_failure;
|
goto socket_failure;
|
||||||
}
|
}
|
||||||
strcpy(addr.sun_path, socket_path);
|
strcpy(new->addr.sun_path, socket_path);
|
||||||
|
new->addr.sun_family = AF_UNIX;
|
||||||
|
|
||||||
new->fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
new->fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (new->fd < 0) {
|
if (new->fd < 0) {
|
||||||
FAILED_TO("create unix socket");
|
FAILED_TO("create unix socket");
|
||||||
goto socket_failure;
|
goto socket_failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connect(new->fd, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
|
|
||||||
FAILED_TO("connect to unix socket");
|
|
||||||
goto connect_failure;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new;
|
return new;
|
||||||
|
|
||||||
connect_failure:
|
|
||||||
close(new->fd);
|
|
||||||
socket_failure:
|
socket_failure:
|
||||||
free(new);
|
free(new);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ctl_client_connect(struct ctl_client* self, int timeout)
|
||||||
|
{
|
||||||
|
// TODO: Support arbitrary timeouts?
|
||||||
|
assert(timeout == 0 || timeout == -1);
|
||||||
|
// TODO: Use inotify instead of polling stat()
|
||||||
|
bool needs_log = true;
|
||||||
|
struct stat sb;
|
||||||
|
while (stat(self->addr.sun_path, &sb) != 0) {
|
||||||
|
if (timeout == 0) {
|
||||||
|
FAILED_TO("find socket path \"%s\"",
|
||||||
|
self->addr.sun_path);
|
||||||
|
goto stat_failure;
|
||||||
|
}
|
||||||
|
if (needs_log) {
|
||||||
|
needs_log = false;
|
||||||
|
DEBUG("Waiting for socket path \"%s\" to appear",
|
||||||
|
self->addr.sun_path);
|
||||||
|
}
|
||||||
|
if (usleep(50000) == -1) {
|
||||||
|
FAILED_TO("wait for socket path");
|
||||||
|
goto stat_failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (S_ISSOCK(sb.st_mode)) {
|
||||||
|
DEBUG("Found socket \"%s\"", self->addr.sun_path);
|
||||||
|
} else {
|
||||||
|
WARN("Path \"%s\" exists but is not a socket (0x%x)",
|
||||||
|
self->addr.sun_path, sb.st_mode);
|
||||||
|
goto stat_failure;
|
||||||
|
}
|
||||||
|
while (connect(self->fd, (struct sockaddr*)&self->addr,
|
||||||
|
sizeof(self->addr)) != 0) {
|
||||||
|
if (timeout == 0 || errno != ENOENT) {
|
||||||
|
FAILED_TO("connect to unix socket \"%s\"",
|
||||||
|
self->addr.sun_path);
|
||||||
|
goto stat_failure;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (usleep(50000) == -1) {
|
||||||
|
FAILED_TO("wait for connect to succeed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
stat_failure:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void ctl_client_destroy(struct ctl_client* self)
|
void ctl_client_destroy(struct ctl_client* self)
|
||||||
{
|
{
|
||||||
close(self->fd);
|
close(self->fd);
|
||||||
|
|
|
@ -53,6 +53,8 @@ static int wayvncctl_usage(FILE* stream, int rc)
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" -S,--socket=<path> Wayvnc control socket path.\n"
|
" -S,--socket=<path> Wayvnc control socket path.\n"
|
||||||
" Default: $XDG_RUNTIME_DIR/wayvncctl\n"
|
" Default: $XDG_RUNTIME_DIR/wayvncctl\n"
|
||||||
|
" -w,--wait Wait for wayvnc to start up if it's\n"
|
||||||
|
" not already running.\n"
|
||||||
" -j,--json Output json on stdout.\n"
|
" -j,--json Output json on stdout.\n"
|
||||||
" -V,--version Show version info.\n"
|
" -V,--version Show version info.\n"
|
||||||
" -v,--verbose Be more verbose.\n"
|
" -v,--verbose Be more verbose.\n"
|
||||||
|
@ -74,15 +76,17 @@ int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
struct wayvncctl self = { 0 };
|
struct wayvncctl self = { 0 };
|
||||||
|
|
||||||
static const char* shortopts = "+S:hVvj";
|
static const char* shortopts = "+S:hVvjw";
|
||||||
|
|
||||||
bool verbose = false;
|
bool verbose = false;
|
||||||
const char* socket_path = NULL;
|
const char* socket_path = NULL;
|
||||||
|
int wait_for_socket = 0;
|
||||||
|
|
||||||
unsigned flags = 0;
|
unsigned flags = 0;
|
||||||
|
|
||||||
static const struct option longopts[] = {
|
static const struct option longopts[] = {
|
||||||
{ "socket", required_argument, NULL, 'S' },
|
{ "socket", required_argument, NULL, 'S' },
|
||||||
|
{ "wait", no_argument, NULL, 'w' },
|
||||||
{ "json", no_argument, NULL, 'j' },
|
{ "json", no_argument, NULL, 'j' },
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ "version", no_argument, NULL, 'V' },
|
{ "version", no_argument, NULL, 'V' },
|
||||||
|
@ -99,6 +103,9 @@ int main(int argc, char* argv[])
|
||||||
case 'S':
|
case 'S':
|
||||||
socket_path = optarg;
|
socket_path = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'w':
|
||||||
|
wait_for_socket = -1;
|
||||||
|
break;
|
||||||
case 'j':
|
case 'j':
|
||||||
flags |= PRINT_JSON;
|
flags |= PRINT_JSON;
|
||||||
break;
|
break;
|
||||||
|
@ -117,12 +124,18 @@ int main(int argc, char* argv[])
|
||||||
argv = &argv[optind];
|
argv = &argv[optind];
|
||||||
|
|
||||||
ctl_client_debug_log(verbose);
|
ctl_client_debug_log(verbose);
|
||||||
|
|
||||||
self.ctl = ctl_client_new(socket_path, &self);
|
self.ctl = ctl_client_new(socket_path, &self);
|
||||||
if (!self.ctl)
|
if (!self.ctl)
|
||||||
goto ctl_client_failure;
|
goto ctl_client_failure;
|
||||||
|
|
||||||
int result = ctl_client_run_command(self.ctl, argc, argv, flags);
|
int result = ctl_client_connect(self.ctl, wait_for_socket);
|
||||||
|
if (result != 0)
|
||||||
|
goto socket_failure;
|
||||||
|
|
||||||
|
result = ctl_client_run_command(self.ctl, argc, argv, flags);
|
||||||
|
|
||||||
|
socket_failure:
|
||||||
ctl_client_destroy(self.ctl);
|
ctl_client_destroy(self.ctl);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -14,6 +14,10 @@ wayvncctl - A command line control client for wayvnc(1)
|
||||||
Set wayvnc control socket path. Default: $XDG_RUNTIME_DIR/wayvncctl
|
Set wayvnc control socket path. Default: $XDG_RUNTIME_DIR/wayvncctl
|
||||||
or /tmp/wayvncctl-$UID
|
or /tmp/wayvncctl-$UID
|
||||||
|
|
||||||
|
*-w, --wait*
|
||||||
|
Wait for wayvnc to start up if it's not already running. Default: Exit
|
||||||
|
immediately with an error if wayvnc is not running.
|
||||||
|
|
||||||
*-j, --json*
|
*-j, --json*
|
||||||
Produce json output to stdout.
|
Produce json output to stdout.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue