mirror of
https://github.com/tsl0922/ttyd.git
synced 2026-01-02 08:54:23 +01:00
drop libwebsockets < 3.2.0 support
This commit is contained in:
16
src/http.c
16
src/http.c
@@ -6,10 +6,6 @@
|
||||
#include "server.h"
|
||||
#include "utils.h"
|
||||
|
||||
#if LWS_LIBRARY_VERSION_MAJOR < 2
|
||||
#define HTTP_STATUS_FOUND 302
|
||||
#endif
|
||||
|
||||
enum { AUTH_OK, AUTH_FAIL, AUTH_ERROR };
|
||||
|
||||
static char *html_cache = NULL;
|
||||
@@ -21,7 +17,7 @@ static int check_auth(struct lws *wsi, struct pss_http *pss) {
|
||||
char buf[256];
|
||||
int len = lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_HTTP_AUTHORIZATION);
|
||||
if (len >= 7 && strstr(buf, "Basic ")) {
|
||||
if (!strcmp(buf +6, server->credential)) return AUTH_OK;
|
||||
if (!strcmp(buf + 6, server->credential)) return AUTH_OK;
|
||||
}
|
||||
|
||||
unsigned char buffer[1024 + LWS_PRE], *p, *end;
|
||||
@@ -89,12 +85,7 @@ static void pss_buffer_free(struct pss_http *pss) {
|
||||
static void access_log(struct lws *wsi, const char *path) {
|
||||
char rip[50];
|
||||
|
||||
#if LWS_LIBRARY_VERSION_NUMBER >= 2004000
|
||||
lws_get_peer_simple(lws_get_network_wsi(wsi), rip, sizeof(rip));
|
||||
#else
|
||||
char name[100];
|
||||
lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name, sizeof(name), rip, sizeof(rip));
|
||||
#endif
|
||||
lwsl_notice("HTTP %s - %s\n", path, rip);
|
||||
}
|
||||
|
||||
@@ -186,14 +177,9 @@ int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
||||
lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS) < 0)
|
||||
return 1;
|
||||
|
||||
#if LWS_LIBRARY_VERSION_MAJOR < 2
|
||||
if (lws_write_http(wsi, output, output_len) < 0) return 1;
|
||||
goto try_to_reuse;
|
||||
#else
|
||||
pss->buffer = pss->ptr = output;
|
||||
pss->len = output_len;
|
||||
lws_callback_on_writable(wsi);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#include <errno.h>
|
||||
#include <json.h>
|
||||
#include <libwebsockets.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <json.h>
|
||||
#include <libwebsockets.h>
|
||||
|
||||
#include "pty.h"
|
||||
#include "server.h"
|
||||
@@ -35,16 +35,14 @@ static int send_initial_message(struct lws *wsi, int index) {
|
||||
return lws_write(wsi, p, (size_t)n, LWS_WRITE_BINARY);
|
||||
}
|
||||
|
||||
static json_object* parse_window_size(const char *buf, size_t len, uint16_t *cols, uint16_t *rows) {
|
||||
static json_object *parse_window_size(const char *buf, size_t len, uint16_t *cols, uint16_t *rows) {
|
||||
json_tokener *tok = json_tokener_new();
|
||||
json_object *obj = json_tokener_parse_ex(tok, buf, len);
|
||||
struct json_object *o = NULL;
|
||||
|
||||
if (json_object_object_get_ex(obj, "columns", &o))
|
||||
*cols = (uint16_t) json_object_get_int(o);
|
||||
if (json_object_object_get_ex(obj, "rows", &o))
|
||||
*rows = (uint16_t) json_object_get_int(o);
|
||||
|
||||
if (json_object_object_get_ex(obj, "columns", &o)) *cols = (uint16_t)json_object_get_int(o);
|
||||
if (json_object_object_get_ex(obj, "rows", &o)) *rows = (uint16_t)json_object_get_int(o);
|
||||
|
||||
json_tokener_free(tok);
|
||||
return obj;
|
||||
}
|
||||
@@ -52,7 +50,7 @@ static json_object* parse_window_size(const char *buf, size_t len, uint16_t *col
|
||||
static bool check_host_origin(struct lws *wsi) {
|
||||
char buf[256];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
int len = lws_hdr_copy(wsi, buf, (int) sizeof(buf), WSI_TOKEN_ORIGIN);
|
||||
int len = lws_hdr_copy(wsi, buf, (int)sizeof(buf), WSI_TOKEN_ORIGIN);
|
||||
if (len <= 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -68,23 +66,23 @@ static bool check_host_origin(struct lws *wsi) {
|
||||
|
||||
char host_buf[256];
|
||||
memset(host_buf, 0, sizeof(host_buf));
|
||||
len = lws_hdr_copy(wsi, host_buf, (int) sizeof(host_buf), WSI_TOKEN_HOST);
|
||||
len = lws_hdr_copy(wsi, host_buf, (int)sizeof(host_buf), WSI_TOKEN_HOST);
|
||||
|
||||
return len > 0 && strcasecmp(buf, host_buf) == 0;
|
||||
}
|
||||
|
||||
static void process_read_cb(void *ctx, pty_buf_t *buf, bool eof) {
|
||||
struct pss_tty *pss = (struct pss_tty *) ctx;
|
||||
struct pss_tty *pss = (struct pss_tty *)ctx;
|
||||
if (eof && !process_running(pss->process))
|
||||
pss->lws_close_status = pss->process->exit_code == 0 ? 1000 : 1006;
|
||||
else
|
||||
pss->pty_buf = buf;
|
||||
|
||||
|
||||
lws_callback_on_writable(pss->wsi);
|
||||
}
|
||||
|
||||
static void process_exit_cb(void *ctx, pty_process *process) {
|
||||
struct pss_tty *pss = (struct pss_tty *) ctx;
|
||||
struct pss_tty *pss = (struct pss_tty *)ctx;
|
||||
pss->process = NULL;
|
||||
if (process->killed) {
|
||||
lwsl_notice("process killed with signal %d, pid: %d\n", process->exit_signal, process->pid);
|
||||
@@ -107,7 +105,7 @@ static bool spawn_process(struct pss_tty *pss, uint16_t columns, uint16_t rows)
|
||||
}
|
||||
argv[n] = NULL;
|
||||
|
||||
pty_process *process = process_init((void *) pss, server->loop, argv);
|
||||
pty_process *process = process_init((void *)pss, server->loop, argv);
|
||||
if (columns > 0) process->columns = columns;
|
||||
if (rows > 0) process->rows = rows;
|
||||
strncpy(process->term, server->terminal_type, sizeof(process->term));
|
||||
@@ -126,13 +124,13 @@ static bool spawn_process(struct pss_tty *pss, uint16_t columns, uint16_t rows)
|
||||
static void wsi_output(struct lws *wsi, pty_buf_t *buf) {
|
||||
if (buf == NULL) return;
|
||||
char *message = xmalloc(LWS_PRE + 1 + buf->len);
|
||||
char *ptr= message + LWS_PRE;
|
||||
char *ptr = message + LWS_PRE;
|
||||
|
||||
*ptr = OUTPUT;
|
||||
memcpy(ptr + 1, buf->base, buf->len);
|
||||
size_t n = buf->len + 1;
|
||||
|
||||
if (lws_write(wsi, (unsigned char *) ptr, n, LWS_WRITE_BINARY) < n) {
|
||||
if (lws_write(wsi, (unsigned char *)ptr, n, LWS_WRITE_BINARY) < n) {
|
||||
lwsl_err("write OUTPUT to WS\n");
|
||||
}
|
||||
|
||||
@@ -157,7 +155,7 @@ int callback_tty(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
||||
}
|
||||
if (server->credential != NULL) {
|
||||
n = lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_HTTP_AUTHORIZATION);
|
||||
if (n < 7 || !strstr(buf, "Basic ") || strcmp(buf +6, server->credential)) return 1;
|
||||
if (n < 7 || !strstr(buf, "Basic ") || strcmp(buf + 6, server->credential)) return 1;
|
||||
}
|
||||
|
||||
n = lws_hdr_copy(wsi, pss->path, sizeof(pss->path), WSI_TOKEN_GET_URI);
|
||||
@@ -195,13 +193,7 @@ int callback_tty(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
||||
|
||||
server->client_count++;
|
||||
|
||||
#if LWS_LIBRARY_VERSION_NUMBER >= 2004000
|
||||
lws_get_peer_simple(lws_get_network_wsi(wsi), pss->address, sizeof(pss->address));
|
||||
#else
|
||||
char name[100];
|
||||
lws_get_peer_addresses(wsi, lws_get_socket_fd(wsi), name, sizeof(name), pss->address,
|
||||
sizeof(pss->address));
|
||||
#endif
|
||||
lwsl_notice("WS %s - %s, clients: %d\n", pss->path, pss->address, server->client_count);
|
||||
break;
|
||||
|
||||
@@ -269,8 +261,8 @@ int callback_tty(struct lws *wsi, enum lws_callback_reasons reason, void *user,
|
||||
}
|
||||
break;
|
||||
case RESIZE_TERMINAL:
|
||||
json_object_put(parse_window_size(pss->buffer + 1, pss->len - 1,
|
||||
&pss->process->columns, &pss->process->rows));
|
||||
json_object_put(parse_window_size(pss->buffer + 1, pss->len - 1, &pss->process->columns,
|
||||
&pss->process->rows));
|
||||
pty_resize(pss->process);
|
||||
break;
|
||||
case PAUSE:
|
||||
|
||||
55
src/pty.c
55
src/pty.c
@@ -32,9 +32,7 @@ static void alloc_cb(uv_handle_t *unused, size_t suggested_size, uv_buf_t *buf)
|
||||
buf->len = suggested_size;
|
||||
}
|
||||
|
||||
static void close_cb(uv_handle_t *handle) {
|
||||
free(handle);
|
||||
}
|
||||
static void close_cb(uv_handle_t *handle) { free(handle); }
|
||||
|
||||
pty_buf_t *pty_buf_init(char *base, size_t len) {
|
||||
pty_buf_t *buf = xmalloc(sizeof(pty_buf_t));
|
||||
@@ -65,7 +63,7 @@ done:
|
||||
}
|
||||
|
||||
static void write_cb(uv_write_t *req, int unused) {
|
||||
pty_buf_t *buf = (pty_buf_t *)req->data;
|
||||
pty_buf_t *buf = (pty_buf_t *) req->data;
|
||||
pty_buf_free(buf);
|
||||
free(req);
|
||||
}
|
||||
@@ -152,10 +150,10 @@ bool pty_resize(pty_process *process) {
|
||||
if (process == NULL) return false;
|
||||
if (process->columns <= 0 || process->rows <= 0) return false;
|
||||
#ifdef _WIN32
|
||||
COORD size = { (int16_t) process->columns, (int16_t) process->rows };
|
||||
COORD size = {(int16_t) process->columns, (int16_t) process->rows};
|
||||
return pResizePseudoConsole(process->pty, size) == S_OK;
|
||||
#else
|
||||
struct winsize size = { process->rows, process->columns, 0, 0 };
|
||||
struct winsize size = {process->rows, process->columns, 0, 0};
|
||||
return ioctl(process->pty, TIOCSWINSZ, &size) == 0;
|
||||
#endif
|
||||
}
|
||||
@@ -180,15 +178,12 @@ bool conpty_init() {
|
||||
static struct {
|
||||
char *name;
|
||||
FARPROC *ptr;
|
||||
} conpty_entry[] = {
|
||||
{ "CreatePseudoConsole", (FARPROC *)&pCreatePseudoConsole },
|
||||
{ "ResizePseudoConsole", (FARPROC *)&pResizePseudoConsole },
|
||||
{ "ClosePseudoConsole", (FARPROC *)&pClosePseudoConsole },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
for (int i = 0;
|
||||
conpty_entry[i].name != NULL && conpty_entry[i].ptr != NULL; i++) {
|
||||
if (uv_dlsym(&kernel, conpty_entry[i].name, (void **)conpty_entry[i].ptr)) {
|
||||
} conpty_entry[] = {{"CreatePseudoConsole", (FARPROC *) &pCreatePseudoConsole},
|
||||
{"ResizePseudoConsole", (FARPROC *) &pResizePseudoConsole},
|
||||
{"ClosePseudoConsole", (FARPROC *) &pClosePseudoConsole},
|
||||
{NULL, NULL}};
|
||||
for (int i = 0; conpty_entry[i].name != NULL && conpty_entry[i].ptr != NULL; i++) {
|
||||
if (uv_dlsym(&kernel, conpty_entry[i].name, (void **) conpty_entry[i].ptr)) {
|
||||
uv_dlclose(&kernel);
|
||||
return false;
|
||||
}
|
||||
@@ -212,7 +207,7 @@ static WCHAR *join_args(char **argv) {
|
||||
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, args, -1, NULL, 0);
|
||||
if (len <= 0) goto failed;
|
||||
WCHAR *ws = (WCHAR*) xmalloc(len * sizeof(WCHAR));
|
||||
WCHAR *ws = (WCHAR *) xmalloc(len * sizeof(WCHAR));
|
||||
if (len != MultiByteToWideChar(CP_UTF8, 0, args, -1, ws, len)) {
|
||||
free(ws);
|
||||
goto failed;
|
||||
@@ -228,7 +223,7 @@ static bool conpty_setup(HPCON *hnd, COORD size, STARTUPINFOEXW *si_ex, char **i
|
||||
static int count = 0;
|
||||
char buf[256];
|
||||
HPCON pty = INVALID_HANDLE_VALUE;
|
||||
SECURITY_ATTRIBUTES sa = { 0 };
|
||||
SECURITY_ATTRIBUTES sa = {0};
|
||||
HANDLE in_pipe = INVALID_HANDLE_VALUE;
|
||||
HANDLE out_pipe = INVALID_HANDLE_VALUE;
|
||||
const DWORD open_mode = PIPE_ACCESS_INBOUND | PIPE_ACCESS_OUTBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE;
|
||||
@@ -260,14 +255,14 @@ static bool conpty_setup(HPCON *hnd, COORD size, STARTUPINFOEXW *si_ex, char **i
|
||||
si_ex->StartupInfo.hStdInput = NULL;
|
||||
si_ex->StartupInfo.hStdOutput = NULL;
|
||||
size_t bytes_required;
|
||||
InitializeProcThreadAttributeList(NULL, 1, 0, &bytes_required);
|
||||
InitializeProcThreadAttributeList(NULL, 1, 0, &bytes_required);
|
||||
si_ex->lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST) xmalloc(bytes_required);
|
||||
if (!InitializeProcThreadAttributeList(si_ex->lpAttributeList, 1, 0, &bytes_required)) {
|
||||
print_error("InitializeProcThreadAttributeList");
|
||||
goto failed;
|
||||
}
|
||||
if (!UpdateProcThreadAttribute(si_ex->lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE,
|
||||
pty, sizeof(HPCON), NULL, NULL)) {
|
||||
if (!UpdateProcThreadAttribute(si_ex->lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, pty, sizeof(HPCON),
|
||||
NULL, NULL)) {
|
||||
print_error("UpdateProcThreadAttribute");
|
||||
goto failed;
|
||||
}
|
||||
@@ -288,9 +283,7 @@ done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void connect_cb(uv_connect_t *req, int status) {
|
||||
free(req);
|
||||
}
|
||||
static void connect_cb(uv_connect_t *req, int status) { free(req); }
|
||||
|
||||
static void CALLBACK conpty_exit(void *context, BOOLEAN unused) {
|
||||
pty_process *process = (pty_process *) context;
|
||||
@@ -316,7 +309,7 @@ int pty_spawn(pty_process *process, pty_read_cb read_cb, pty_exit_cb exit_cb) {
|
||||
char *in_name = NULL;
|
||||
char *out_name = NULL;
|
||||
DWORD flags = EXTENDED_STARTUPINFO_PRESENT | CREATE_UNICODE_ENVIRONMENT;
|
||||
COORD size = { (int16_t) process->columns, (int16_t) process->rows };
|
||||
COORD size = {(int16_t) process->columns, (int16_t) process->rows};
|
||||
|
||||
if (!conpty_setup(&process->pty, size, &process->si, &in_name, &out_name)) return 1;
|
||||
|
||||
@@ -329,8 +322,8 @@ int pty_spawn(pty_process *process, pty_read_cb read_cb, pty_exit_cb exit_cb) {
|
||||
uv_connect_t *out_req = xmalloc(sizeof(uv_connect_t));
|
||||
uv_pipe_connect(in_req, io->in, in_name, connect_cb);
|
||||
uv_pipe_connect(out_req, io->out, out_name, connect_cb);
|
||||
|
||||
PROCESS_INFORMATION pi = { 0 };
|
||||
|
||||
PROCESS_INFORMATION pi = {0};
|
||||
cmdline = join_args(process->argv);
|
||||
if (cmdline == NULL) goto cleanup;
|
||||
|
||||
@@ -351,7 +344,7 @@ int pty_spawn(pty_process *process, pty_read_cb read_cb, pty_exit_cb exit_cb) {
|
||||
process->async.data = process;
|
||||
uv_async_init(process->loop, &process->async, async_cb);
|
||||
|
||||
if(!RegisterWaitForSingleObject(&process->wait, pi.hProcess, conpty_exit, process, INFINITE, WT_EXECUTEONLYONCE)) {
|
||||
if (!RegisterWaitForSingleObject(&process->wait, pi.hProcess, conpty_exit, process, INFINITE, WT_EXECUTEONLYONCE)) {
|
||||
print_error("RegisterWaitForSingleObject");
|
||||
pty_io_free(io);
|
||||
goto cleanup;
|
||||
@@ -380,7 +373,7 @@ static bool fd_duplicate(int fd, uv_pipe_t *pipe) {
|
||||
if (!fd_set_cloexec(fd_dup)) return false;
|
||||
|
||||
int status = uv_pipe_open(pipe, fd_dup);
|
||||
if(status) close(fd_dup);
|
||||
if (status) close(fd_dup);
|
||||
return status == 0;
|
||||
}
|
||||
|
||||
@@ -419,7 +412,7 @@ int pty_spawn(pty_process *process, pty_read_cb read_cb, pty_exit_cb exit_cb) {
|
||||
uv_disable_stdio_inheritance();
|
||||
|
||||
int master, pid;
|
||||
struct winsize size = { process->rows, process->columns, 0, 0 };
|
||||
struct winsize size = {process->rows, process->columns, 0, 0};
|
||||
pid = forkpty(&master, NULL, NULL, &size);
|
||||
if (pid < 0) {
|
||||
status = -errno;
|
||||
@@ -439,12 +432,12 @@ int pty_spawn(pty_process *process, pty_read_cb read_cb, pty_exit_cb exit_cb) {
|
||||
status = -errno;
|
||||
goto error;
|
||||
}
|
||||
if(fcntl(master, F_SETFD, flags | O_NONBLOCK) == -1) {
|
||||
if (fcntl(master, F_SETFD, flags | O_NONBLOCK) == -1) {
|
||||
status = -errno;
|
||||
goto error;
|
||||
}
|
||||
if (!fd_set_cloexec(master)) {
|
||||
status=-errno;
|
||||
status = -errno;
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef HPCON
|
||||
# define HPCON VOID *
|
||||
#define HPCON VOID *
|
||||
#endif
|
||||
#ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
|
||||
# define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016
|
||||
#define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016
|
||||
#endif
|
||||
|
||||
bool conpty_init();
|
||||
@@ -51,7 +51,7 @@ struct pty_process_ {
|
||||
uv_thread_t tid;
|
||||
#endif
|
||||
char **argv;
|
||||
|
||||
|
||||
uv_loop_t *loop;
|
||||
uv_async_t async;
|
||||
pty_io_t *io;
|
||||
|
||||
195
src/server.c
195
src/server.c
@@ -22,68 +22,63 @@ struct lws_context *context;
|
||||
struct server *server;
|
||||
struct endpoints endpoints = {"/ws", "/", "/token", ""};
|
||||
|
||||
extern int callback_http(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
extern int callback_tty(struct lws *wsi, enum lws_callback_reasons reason,
|
||||
void *user, void *in, size_t len);
|
||||
extern int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
|
||||
extern int callback_tty(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
|
||||
|
||||
// websocket protocols
|
||||
static const struct lws_protocols protocols[] = {
|
||||
{"http-only", callback_http, sizeof(struct pss_http), 0},
|
||||
{"tty", callback_tty, sizeof(struct pss_tty), 0},
|
||||
{NULL, NULL, 0, 0}};
|
||||
static const struct lws_protocols protocols[] = {{"http-only", callback_http, sizeof(struct pss_http), 0},
|
||||
{"tty", callback_tty, sizeof(struct pss_tty), 0},
|
||||
{NULL, NULL, 0, 0}};
|
||||
|
||||
#ifndef LWS_WITHOUT_EXTENSIONS
|
||||
// websocket extensions
|
||||
static const struct lws_extension extensions[] = {
|
||||
{"permessage-deflate", lws_extension_callback_pm_deflate,
|
||||
"permessage-deflate"},
|
||||
{"permessage-deflate", lws_extension_callback_pm_deflate, "permessage-deflate"},
|
||||
{"deflate-frame", lws_extension_callback_pm_deflate, "deflate_frame"},
|
||||
{NULL, NULL, NULL}};
|
||||
#endif
|
||||
|
||||
#if LWS_LIBRARY_VERSION_NUMBER >= 4000000
|
||||
static const uint32_t backoff_ms[] = { 1000, 2000, 3000, 4000, 5000 };
|
||||
static const uint32_t backoff_ms[] = {1000, 2000, 3000, 4000, 5000};
|
||||
static lws_retry_bo_t retry = {
|
||||
.retry_ms_table = backoff_ms,
|
||||
.retry_ms_table_count = LWS_ARRAY_SIZE(backoff_ms),
|
||||
.conceal_count = LWS_ARRAY_SIZE(backoff_ms),
|
||||
.secs_since_valid_ping = 5,
|
||||
.secs_since_valid_hangup = 10,
|
||||
.jitter_percent = 0,
|
||||
};
|
||||
.retry_ms_table = backoff_ms,
|
||||
.retry_ms_table_count = LWS_ARRAY_SIZE(backoff_ms),
|
||||
.conceal_count = LWS_ARRAY_SIZE(backoff_ms),
|
||||
.secs_since_valid_ping = 5,
|
||||
.secs_since_valid_hangup = 10,
|
||||
.jitter_percent = 0,
|
||||
};
|
||||
#endif
|
||||
|
||||
// command line options
|
||||
static const struct option options[] = {
|
||||
{"port", required_argument, NULL, 'p'},
|
||||
{"interface", required_argument, NULL, 'i'},
|
||||
{"credential", required_argument, NULL, 'c'},
|
||||
{"uid", required_argument, NULL, 'u'},
|
||||
{"gid", required_argument, NULL, 'g'},
|
||||
{"signal", required_argument, NULL, 's'},
|
||||
{"index", required_argument, NULL, 'I'},
|
||||
{"base-path", required_argument, NULL, 'b'},
|
||||
static const struct option options[] = {{"port", required_argument, NULL, 'p'},
|
||||
{"interface", required_argument, NULL, 'i'},
|
||||
{"credential", required_argument, NULL, 'c'},
|
||||
{"uid", required_argument, NULL, 'u'},
|
||||
{"gid", required_argument, NULL, 'g'},
|
||||
{"signal", required_argument, NULL, 's'},
|
||||
{"index", required_argument, NULL, 'I'},
|
||||
{"base-path", required_argument, NULL, 'b'},
|
||||
#if LWS_LIBRARY_VERSION_NUMBER >= 4000000
|
||||
{"ping-interval", required_argument, NULL, 'P'},
|
||||
{"ping-interval", required_argument, NULL, 'P'},
|
||||
#endif
|
||||
{"ipv6", no_argument, NULL, '6'},
|
||||
{"ssl", no_argument, NULL, 'S'},
|
||||
{"ssl-cert", required_argument, NULL, 'C'},
|
||||
{"ssl-key", required_argument, NULL, 'K'},
|
||||
{"ssl-ca", required_argument, NULL, 'A'},
|
||||
{"url-arg", no_argument, NULL, 'a'},
|
||||
{"readonly", no_argument, NULL, 'R'},
|
||||
{"terminal-type", required_argument, NULL, 'T'},
|
||||
{"client-option", required_argument, NULL, 't'},
|
||||
{"check-origin", no_argument, NULL, 'O'},
|
||||
{"max-clients", required_argument, NULL, 'm'},
|
||||
{"once", no_argument, NULL, 'o'},
|
||||
{"browser", no_argument, NULL, 'B'},
|
||||
{"debug", required_argument, NULL, 'd'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{NULL, 0, 0, 0}};
|
||||
{"ipv6", no_argument, NULL, '6'},
|
||||
{"ssl", no_argument, NULL, 'S'},
|
||||
{"ssl-cert", required_argument, NULL, 'C'},
|
||||
{"ssl-key", required_argument, NULL, 'K'},
|
||||
{"ssl-ca", required_argument, NULL, 'A'},
|
||||
{"url-arg", no_argument, NULL, 'a'},
|
||||
{"readonly", no_argument, NULL, 'R'},
|
||||
{"terminal-type", required_argument, NULL, 'T'},
|
||||
{"client-option", required_argument, NULL, 't'},
|
||||
{"check-origin", no_argument, NULL, 'O'},
|
||||
{"max-clients", required_argument, NULL, 'm'},
|
||||
{"once", no_argument, NULL, 'o'},
|
||||
{"browser", no_argument, NULL, 'B'},
|
||||
{"debug", required_argument, NULL, 'd'},
|
||||
{"version", no_argument, NULL, 'v'},
|
||||
{"help", no_argument, NULL, 'h'},
|
||||
{NULL, 0, 0, 0}};
|
||||
|
||||
#if LWS_LIBRARY_VERSION_NUMBER < 4000000
|
||||
static const char *opt_string = "p:i:c:u:g:s:I:b:6aSC:K:A:Rt:T:Om:oBd:vh";
|
||||
@@ -167,7 +162,7 @@ static struct server *server_new(int argc, char **argv, int start) {
|
||||
char *ptr = ts->command;
|
||||
for (int i = 0; i < cmd_argc; i++) {
|
||||
size_t len = strlen(ts->argv[i]);
|
||||
ptr = memcpy (ptr, ts->argv[i], len + 1) + len;
|
||||
ptr = memcpy(ptr, ts->argv[i], len + 1) + len;
|
||||
if (i != cmd_argc - 1) {
|
||||
*ptr++ = ' ';
|
||||
}
|
||||
@@ -186,18 +181,22 @@ static void server_free(struct server *ts) {
|
||||
if (ts->index != NULL) free(ts->index);
|
||||
free(ts->command);
|
||||
free(ts->prefs_json);
|
||||
|
||||
int i = 0;
|
||||
do {
|
||||
free(ts->argv[i++]);
|
||||
} while (ts->argv[i] != NULL);
|
||||
free(ts->argv);
|
||||
|
||||
if (strlen(ts->socket_path) > 0) {
|
||||
struct stat st;
|
||||
if (!stat(ts->socket_path, &st)) {
|
||||
unlink(ts->socket_path);
|
||||
}
|
||||
}
|
||||
|
||||
uv_loop_close(ts->loop);
|
||||
|
||||
free(ts->loop);
|
||||
free(ts);
|
||||
}
|
||||
@@ -209,8 +208,7 @@ static void signal_cb(uv_signal_t *watcher, int signum) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
get_sig_name(watcher->signum, sig_name, sizeof(sig_name));
|
||||
lwsl_notice("received signal: %s (%d), exiting...\n", sig_name,
|
||||
watcher->signum);
|
||||
lwsl_notice("received signal: %s (%d), exiting...\n", sig_name, watcher->signum);
|
||||
break;
|
||||
default:
|
||||
signal(SIGABRT, SIG_DFL);
|
||||
@@ -219,14 +217,11 @@ static void signal_cb(uv_signal_t *watcher, int signum) {
|
||||
|
||||
if (force_exit) exit(EXIT_FAILURE);
|
||||
force_exit = true;
|
||||
|
||||
lws_cancel_service(context);
|
||||
#if LWS_LIBRARY_VERSION_MAJOR >= 3
|
||||
uv_stop(server->loop);
|
||||
|
||||
lwsl_notice("send ^C to force exit.\n");
|
||||
#else
|
||||
lws_libuv_stop(context);
|
||||
exit(EXIT_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int parse_int(char *name, char *str) {
|
||||
@@ -237,7 +232,7 @@ static int parse_int(char *name, char *str) {
|
||||
fprintf(stderr, "ttyd: invalid value for %s: %s\n", name, str);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return (int) val;
|
||||
return (int)val;
|
||||
}
|
||||
|
||||
static int calc_command_start(int argc, char **argv) {
|
||||
@@ -300,8 +295,7 @@ int main(int argc, char **argv) {
|
||||
info.gid = -1;
|
||||
info.uid = -1;
|
||||
info.max_http_header_pool = 16;
|
||||
info.options = LWS_SERVER_OPTION_LIBUV | LWS_SERVER_OPTION_VALIDATE_UTF8 |
|
||||
LWS_SERVER_OPTION_DISABLE_IPV6;
|
||||
info.options = LWS_SERVER_OPTION_LIBUV | LWS_SERVER_OPTION_VALIDATE_UTF8 | LWS_SERVER_OPTION_DISABLE_IPV6;
|
||||
#ifndef LWS_WITHOUT_EXTENSIONS
|
||||
info.extensions = extensions;
|
||||
#endif
|
||||
@@ -394,13 +388,11 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
struct stat st;
|
||||
if (stat(server->index, &st) == -1) {
|
||||
fprintf(stderr, "Can not stat index.html: %s, error: %s\n",
|
||||
server->index, strerror(errno));
|
||||
fprintf(stderr, "Can not stat index.html: %s, error: %s\n", server->index, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (S_ISDIR(st.st_mode)) {
|
||||
fprintf(stderr, "Invalid index.html path: %s, is it a dir?\n",
|
||||
server->index);
|
||||
fprintf(stderr, "Invalid index.html path: %s, is it a dir?\n", server->index);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
@@ -417,18 +409,16 @@ int main(int argc, char **argv) {
|
||||
#undef sc
|
||||
} break;
|
||||
#if LWS_LIBRARY_VERSION_NUMBER >= 4000000
|
||||
case 'P':
|
||||
{
|
||||
int interval = parse_int("ping-interval", optarg);
|
||||
if (interval <= 0) {
|
||||
fprintf(stderr, "ttyd: invalid ping interval: %s\n", optarg);
|
||||
return -1;
|
||||
}
|
||||
retry.secs_since_valid_ping = interval;
|
||||
retry.secs_since_valid_hangup = interval + 7;
|
||||
info.retry_and_idle_policy = &retry;
|
||||
case 'P': {
|
||||
int interval = parse_int("ping-interval", optarg);
|
||||
if (interval <= 0) {
|
||||
fprintf(stderr, "ttyd: invalid ping interval: %s\n", optarg);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
retry.secs_since_valid_ping = interval;
|
||||
retry.secs_since_valid_hangup = interval + 7;
|
||||
info.retry_and_idle_policy = &retry;
|
||||
} break;
|
||||
#endif
|
||||
case '6':
|
||||
info.options &= ~(LWS_SERVER_OPTION_DISABLE_IPV6);
|
||||
@@ -451,8 +441,7 @@ int main(int argc, char **argv) {
|
||||
break;
|
||||
#endif
|
||||
case 'T':
|
||||
strncpy(server->terminal_type, optarg,
|
||||
sizeof(server->terminal_type) - 1);
|
||||
strncpy(server->terminal_type, optarg, sizeof(server->terminal_type) - 1);
|
||||
server->terminal_type[sizeof(server->terminal_type) - 1] = '\0';
|
||||
break;
|
||||
case '?':
|
||||
@@ -463,22 +452,16 @@ int main(int argc, char **argv) {
|
||||
char *option = optarg;
|
||||
char *key = strsep(&option, "=");
|
||||
if (key == NULL) {
|
||||
fprintf(stderr,
|
||||
"ttyd: invalid client option: %s, format: key=value\n",
|
||||
optarg);
|
||||
fprintf(stderr, "ttyd: invalid client option: %s, format: key=value\n", optarg);
|
||||
return -1;
|
||||
}
|
||||
char *value = strsep(&option, "=");
|
||||
if (value == NULL) {
|
||||
fprintf(stderr,
|
||||
"ttyd: invalid client option: %s, format: key=value\n",
|
||||
optarg);
|
||||
fprintf(stderr, "ttyd: invalid client option: %s, format: key=value\n", optarg);
|
||||
return -1;
|
||||
}
|
||||
struct json_object *obj = json_tokener_parse(value);
|
||||
json_object_object_add(
|
||||
client_prefs, key,
|
||||
obj != NULL ? obj : json_object_new_string(value));
|
||||
json_object_object_add(client_prefs, key, obj != NULL ? obj : json_object_new_string(value));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -496,13 +479,11 @@ int main(int argc, char **argv) {
|
||||
|
||||
lws_set_log_level(debug_level, NULL);
|
||||
|
||||
#if LWS_LIBRARY_VERSION_MAJOR >= 2
|
||||
char server_hdr[128] = "";
|
||||
sprintf(server_hdr, "ttyd/%s (libwebsockets/%s)", TTYD_VERSION,
|
||||
LWS_LIBRARY_VERSION);
|
||||
sprintf(server_hdr, "ttyd/%s (libwebsockets/%s)", TTYD_VERSION, LWS_LIBRARY_VERSION);
|
||||
info.server_string = server_hdr;
|
||||
#endif
|
||||
#if LWS_LIBRARY_VERSION_NUMBER >= 2001000 && LWS_LIBRARY_VERSION_NUMBER < 4000000
|
||||
|
||||
#if LWS_LIBRARY_VERSION_NUMBER < 4000000
|
||||
info.ws_ping_pong_interval = 5;
|
||||
#endif
|
||||
|
||||
@@ -511,11 +492,10 @@ int main(int argc, char **argv) {
|
||||
if (endswith(info.iface, ".sock") || endswith(info.iface, ".socket")) {
|
||||
#if defined(LWS_USE_UNIX_SOCK) || defined(LWS_WITH_UNIX_SOCK)
|
||||
info.options |= LWS_SERVER_OPTION_UNIX_SOCK;
|
||||
info.port = 0; // warmcat/libwebsockets#1985
|
||||
info.port = 0; // warmcat/libwebsockets#1985
|
||||
strncpy(server->socket_path, info.iface, sizeof(server->socket_path) - 1);
|
||||
#else
|
||||
fprintf(stderr,
|
||||
"libwebsockets is not compiled with UNIX domain socket support");
|
||||
fprintf(stderr, "libwebsockets is not compiled with UNIX domain socket support");
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
@@ -529,17 +509,13 @@ int main(int argc, char **argv) {
|
||||
info.ssl_ca_filepath = ca_path;
|
||||
info.options |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;
|
||||
}
|
||||
#if LWS_LIBRARY_VERSION_MAJOR >= 2
|
||||
info.options |= LWS_SERVER_OPTION_REDIRECT_HTTP_TO_HTTPS;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
lwsl_notice("ttyd %s (libwebsockets %s)\n", TTYD_VERSION,
|
||||
LWS_LIBRARY_VERSION);
|
||||
lwsl_notice("ttyd %s (libwebsockets %s)\n", TTYD_VERSION, LWS_LIBRARY_VERSION);
|
||||
lwsl_notice("tty configuration:\n");
|
||||
if (server->credential != NULL)
|
||||
lwsl_notice(" credential: %s\n", server->credential);
|
||||
if (server->credential != NULL) lwsl_notice(" credential: %s\n", server->credential);
|
||||
lwsl_notice(" start command: %s\n", server->command);
|
||||
lwsl_notice(" close signal: %s (%d)\n", server->sig_name, server->sig_code);
|
||||
lwsl_notice(" terminal type: %s\n", server->terminal_type);
|
||||
@@ -553,19 +529,14 @@ int main(int argc, char **argv) {
|
||||
if (server->check_origin) lwsl_notice(" check origin: true\n");
|
||||
if (server->url_arg) lwsl_notice(" allow url arg: true\n");
|
||||
if (server->readonly) lwsl_notice(" readonly: true\n");
|
||||
if (server->max_clients > 0)
|
||||
lwsl_notice(" max clients: %d\n", server->max_clients);
|
||||
if (server->max_clients > 0) lwsl_notice(" max clients: %d\n", server->max_clients);
|
||||
if (server->once) lwsl_notice(" once: true\n");
|
||||
if (server->index != NULL) {
|
||||
lwsl_notice(" custom index.html: %s\n", server->index);
|
||||
}
|
||||
if (server->index != NULL) lwsl_notice(" custom index.html: %s\n", server->index);
|
||||
|
||||
#if LWS_LIBRARY_VERSION_MAJOR >= 3
|
||||
void *foreign_loops[1];
|
||||
foreign_loops[0] = server->loop;
|
||||
info.foreign_loops = foreign_loops;
|
||||
info.options |= LWS_SERVER_OPTION_EXPLICIT_VHOSTS;
|
||||
#endif
|
||||
|
||||
context = lws_create_context(&info);
|
||||
if (context == NULL) {
|
||||
@@ -573,16 +544,12 @@ int main(int argc, char **argv) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if LWS_LIBRARY_VERSION_MAJOR >= 3
|
||||
struct lws_vhost *vhost = lws_create_vhost(context, &info);
|
||||
if (vhost == NULL) {
|
||||
lwsl_err("libwebsockets vhost creation failed\n");
|
||||
return 1;
|
||||
}
|
||||
int port = lws_get_vhost_listen_port(vhost);
|
||||
#else
|
||||
int port = info.port;
|
||||
#endif
|
||||
lwsl_notice(" Listening on port: %d\n", port);
|
||||
|
||||
if (browser) {
|
||||
@@ -591,8 +558,7 @@ int main(int argc, char **argv) {
|
||||
open_uri(url);
|
||||
}
|
||||
|
||||
#if LWS_LIBRARY_VERSION_MAJOR >= 3
|
||||
#define sig_count 2
|
||||
#define sig_count 2
|
||||
int sig_nums[] = {SIGINT, SIGTERM};
|
||||
uv_signal_t signals[sig_count];
|
||||
for (int i = 0; i < sig_count; i++) {
|
||||
@@ -605,16 +571,7 @@ int main(int argc, char **argv) {
|
||||
for (int i = 0; i < sig_count; i++) {
|
||||
uv_signal_stop(&signals[i]);
|
||||
}
|
||||
#undef sig_count
|
||||
#else
|
||||
#if LWS_LIBRARY_VERSION_MAJOR < 2
|
||||
lws_uv_initloop(context, server->loop, signal_cb, 0);
|
||||
#else
|
||||
lws_uv_sigint_cfg(context, 1, signal_cb);
|
||||
lws_uv_initloop(context, server->loop, 0);
|
||||
#endif
|
||||
lws_libuv_run(context, 0);
|
||||
#endif
|
||||
#undef sig_count
|
||||
|
||||
lws_context_destroy(context);
|
||||
|
||||
|
||||
@@ -72,5 +72,5 @@ struct server {
|
||||
char socket_path[255]; // UNIX domain socket path
|
||||
char terminal_type[30]; // terminal type to report
|
||||
|
||||
uv_loop_t *loop; // the libuv event loop
|
||||
uv_loop_t *loop; // the libuv event loop
|
||||
};
|
||||
|
||||
144
src/utils.c
144
src/utils.c
@@ -8,10 +8,9 @@
|
||||
|
||||
#if defined(__linux__) && !defined(__ANDROID__)
|
||||
const char *sys_signame[NSIG] = {
|
||||
"zero", "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "UNUSED", "FPE",
|
||||
"KILL", "USR1", "SEGV", "USR2", "PIPE", "ALRM", "TERM", "STKFLT", "CHLD",
|
||||
"CONT", "STOP", "TSTP", "TTIN", "TTOU", "URG", "XCPU", "XFSZ", "VTALRM",
|
||||
"PROF", "WINCH", "IO", "PWR", "SYS", NULL};
|
||||
"zero", "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "UNUSED", "FPE", "KILL", "USR1",
|
||||
"SEGV", "USR2", "PIPE", "ALRM", "TERM", "STKFLT", "CHLD", "CONT", "STOP", "TSTP", "TTIN",
|
||||
"TTOU", "URG", "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "IO", "PWR", "SYS", NULL};
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
@@ -19,10 +18,9 @@ const char *sys_signame[NSIG] = {
|
||||
#undef NSIG
|
||||
#define NSIG 33
|
||||
const char *sys_signame[NSIG] = {
|
||||
"zero", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "EMT", "FPE",
|
||||
"KILL", "BUS", "SEGV", "SYS", "PIPE", "ALRM", "TERM", "URG", "STOP",
|
||||
"TSTP", "CONT", "CHLD", "TTIN", "TTOU", "IO", "XCPU", "XFSZ", "VTALRM",
|
||||
"PROF", "WINCH", "PWR", "USR1", "USR2", NULL};
|
||||
"zero", "HUP", "INT", "QUIT", "ILL", "TRAP", "IOT", "EMT", "FPE", "KILL", "BUS",
|
||||
"SEGV", "SYS", "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", "CONT", "CHLD", "TTIN",
|
||||
"TTOU", "IO", "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "PWR", "USR1", "USR2", NULL};
|
||||
#endif
|
||||
|
||||
void *xmalloc(size_t size) {
|
||||
@@ -54,8 +52,7 @@ bool endswith(const char *str, const char *suffix) {
|
||||
}
|
||||
|
||||
int get_sig_name(int sig, char *buf, size_t len) {
|
||||
int n =
|
||||
snprintf(buf, len, "SIG%s", sig < NSIG ? sys_signame[sig] : "unknown");
|
||||
int n = snprintf(buf, len, "SIG%s", sig < NSIG ? sys_signame[sig] : "unknown");
|
||||
uppercase(buf);
|
||||
return n;
|
||||
}
|
||||
@@ -63,8 +60,7 @@ int get_sig_name(int sig, char *buf, size_t len) {
|
||||
int get_sig(const char *sig_name) {
|
||||
for (int sig = 1; sig < NSIG; sig++) {
|
||||
const char *name = sys_signame[sig];
|
||||
if (name != NULL && (strcasecmp(name, sig_name) == 0 ||
|
||||
strcasecmp(name, sig_name + 3) == 0))
|
||||
if (name != NULL && (strcasecmp(name, sig_name) == 0 || strcasecmp(name, sig_name + 3) == 0))
|
||||
return sig;
|
||||
}
|
||||
return atoi(sig_name);
|
||||
@@ -76,7 +72,7 @@ int open_uri(char *uri) {
|
||||
sprintf(command, "open %s > /dev/null 2>&1", uri);
|
||||
return system(command);
|
||||
#elif defined(_WIN32) || defined(__CYGWIN__)
|
||||
return ShellExecute(0, 0, uri, 0, 0, SW_SHOW) > (HINSTANCE) 32 ? 0 : 1;
|
||||
return ShellExecute(0, 0, uri, 0, 0, SW_SHOW) > (HINSTANCE)32 ? 0 : 1;
|
||||
#else
|
||||
// check if X server is running
|
||||
if (system("xset -q > /dev/null 2>&1")) return 1;
|
||||
@@ -89,81 +85,71 @@ int open_uri(char *uri) {
|
||||
#ifdef _WIN32
|
||||
char *strsep(char **sp, char *sep) {
|
||||
char *p, *s;
|
||||
if (sp == NULL || *sp == NULL || **sp == '\0') return(NULL);
|
||||
if (sp == NULL || *sp == NULL || **sp == '\0') return (NULL);
|
||||
s = *sp;
|
||||
p = s + strcspn(s, sep);
|
||||
if (*p != '\0') *p++ = '\0';
|
||||
*sp = p;
|
||||
return(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
const char *quote_arg(const char *arg) {
|
||||
int len = 0, n = 0;
|
||||
int force_quotes = 0;
|
||||
char *q, *d;
|
||||
const char *p = arg;
|
||||
if (!*p) force_quotes = 1;
|
||||
while (*p) {
|
||||
if (isspace(*p) || *p == '*' || *p == '?' || *p == '{' || *p == '\'')
|
||||
force_quotes = 1;
|
||||
else if (*p == '"')
|
||||
n++;
|
||||
else if (*p == '\\') {
|
||||
int count = 0;
|
||||
while (*p == '\\') {
|
||||
count++;
|
||||
p++;
|
||||
len++;
|
||||
}
|
||||
if (*p == '"' || !*p)
|
||||
n += count*2 + 1;
|
||||
continue;
|
||||
}
|
||||
len++;
|
||||
p++;
|
||||
}
|
||||
if (!force_quotes && n == 0)
|
||||
return arg;
|
||||
int len = 0, n = 0;
|
||||
int force_quotes = 0;
|
||||
char *q, *d;
|
||||
const char *p = arg;
|
||||
if (!*p) force_quotes = 1;
|
||||
while (*p) {
|
||||
if (isspace(*p) || *p == '*' || *p == '?' || *p == '{' || *p == '\'')
|
||||
force_quotes = 1;
|
||||
else if (*p == '"')
|
||||
n++;
|
||||
else if (*p == '\\') {
|
||||
int count = 0;
|
||||
while (*p == '\\') {
|
||||
count++;
|
||||
p++;
|
||||
len++;
|
||||
}
|
||||
if (*p == '"' || !*p) n += count * 2 + 1;
|
||||
continue;
|
||||
}
|
||||
len++;
|
||||
p++;
|
||||
}
|
||||
if (!force_quotes && n == 0) return arg;
|
||||
|
||||
d = q = xmalloc(len + n + 3);
|
||||
*d++ = '"';
|
||||
while (*arg) {
|
||||
if (*arg == '"')
|
||||
*d++ = '\\';
|
||||
else if (*arg == '\\') {
|
||||
int count = 0;
|
||||
while (*arg == '\\') {
|
||||
count++;
|
||||
*d++ = *arg++;
|
||||
}
|
||||
if (*arg == '"' || !*arg) {
|
||||
while (count-- > 0)
|
||||
*d++ = '\\';
|
||||
if (!*arg)
|
||||
break;
|
||||
*d++ = '\\';
|
||||
}
|
||||
}
|
||||
*d++ = *arg++;
|
||||
}
|
||||
*d++ = '"';
|
||||
*d++ = '\0';
|
||||
return q;
|
||||
d = q = xmalloc(len + n + 3);
|
||||
*d++ = '"';
|
||||
while (*arg) {
|
||||
if (*arg == '"')
|
||||
*d++ = '\\';
|
||||
else if (*arg == '\\') {
|
||||
int count = 0;
|
||||
while (*arg == '\\') {
|
||||
count++;
|
||||
*d++ = *arg++;
|
||||
}
|
||||
if (*arg == '"' || !*arg) {
|
||||
while (count-- > 0) *d++ = '\\';
|
||||
if (!*arg) break;
|
||||
*d++ = '\\';
|
||||
}
|
||||
}
|
||||
*d++ = *arg++;
|
||||
}
|
||||
*d++ = '"';
|
||||
*d++ = '\0';
|
||||
return q;
|
||||
}
|
||||
|
||||
void print_error(char *func) {
|
||||
LPVOID buffer;
|
||||
DWORD dw = GetLastError();
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
dw,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &buffer,
|
||||
0, NULL );
|
||||
wprintf(L"== %s failed with error %d: %s", func, dw, buffer);
|
||||
LocalFree(buffer);
|
||||
void print_error(char *func) {
|
||||
LPVOID buffer;
|
||||
DWORD dw = GetLastError();
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buffer, 0, NULL);
|
||||
wprintf(L"== %s failed with error %d: %s", func, dw, buffer);
|
||||
LocalFree(buffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user