2023-03-07 12:50:17 -05:00
|
|
|
#include "log.h"
|
2022-06-04 13:04:51 -04:00
|
|
|
#include "mem.h"
|
2022-02-09 22:58:33 -05:00
|
|
|
#include "ssb.db.h"
|
2021-08-22 15:34:28 -04:00
|
|
|
#include "ssb.export.h"
|
2023-09-13 19:39:52 -04:00
|
|
|
#include "ssb.h"
|
|
|
|
#include "ssb.import.h"
|
2021-01-02 13:10:00 -05:00
|
|
|
#include "task.h"
|
2021-10-24 11:46:30 -04:00
|
|
|
#include "taskstub.js.h"
|
2021-08-19 15:29:37 -04:00
|
|
|
#include "tests.h"
|
2022-06-03 23:01:12 -04:00
|
|
|
#include "util.js.h"
|
2021-01-02 13:10:00 -05:00
|
|
|
|
2023-05-21 17:36:51 -04:00
|
|
|
#include "backtrace.h"
|
|
|
|
#include "sqlite3.h"
|
2021-01-02 13:10:00 -05:00
|
|
|
|
2024-02-25 14:45:31 -05:00
|
|
|
#include <getopt.h>
|
2023-03-19 20:29:46 -04:00
|
|
|
#include <stdlib.h>
|
2021-01-02 13:10:00 -05:00
|
|
|
#include <string.h>
|
|
|
|
|
2023-10-25 22:56:33 -04:00
|
|
|
#if !defined(_WIN32) && !defined(__APPLE__) && !defined(__HAIKU__)
|
2021-01-02 13:10:00 -05:00
|
|
|
#include <signal.h>
|
|
|
|
#include <sys/resource.h>
|
2023-10-04 19:20:57 -04:00
|
|
|
#endif
|
|
|
|
|
2023-11-07 22:36:08 -05:00
|
|
|
#if defined(__linux__)
|
|
|
|
#include <sys/prctl.h>
|
|
|
|
#endif
|
|
|
|
|
2023-10-13 22:11:20 -04:00
|
|
|
#if defined(__APPLE__)
|
|
|
|
#include <TargetConditionals.h>
|
|
|
|
#endif
|
|
|
|
|
2023-10-04 19:20:57 -04:00
|
|
|
#if !defined(_WIN32)
|
2021-01-02 13:10:00 -05:00
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !defined(_countof)
|
|
|
|
#define _countof(a) ((int)(sizeof((a)) / sizeof(*(a))))
|
|
|
|
#endif
|
|
|
|
|
2023-10-13 22:11:20 -04:00
|
|
|
struct backtrace_state* g_backtrace_state;
|
|
|
|
|
2023-10-15 12:55:25 -04:00
|
|
|
const char* k_db_path_default = "db.sqlite";
|
|
|
|
|
2023-10-17 18:43:13 -04:00
|
|
|
#if !TARGET_OS_IPHONE && !defined(__ANDROID__)
|
2021-01-02 13:10:00 -05:00
|
|
|
static int _tf_command_test(const char* file, int argc, char* argv[]);
|
|
|
|
static int _tf_command_import(const char* file, int argc, char* argv[]);
|
|
|
|
static int _tf_command_export(const char* file, int argc, char* argv[]);
|
|
|
|
static int _tf_command_run(const char* file, int argc, char* argv[]);
|
|
|
|
static int _tf_command_sandbox(const char* file, int argc, char* argv[]);
|
2024-02-25 14:45:31 -05:00
|
|
|
static int _tf_command_usage(const char* file);
|
2021-01-02 13:10:00 -05:00
|
|
|
|
2024-02-15 18:35:01 -05:00
|
|
|
typedef struct _command_t
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
const char* name;
|
|
|
|
int (*callback)(const char* file, int argc, char* argv[]);
|
|
|
|
const char* description;
|
|
|
|
} command_t;
|
|
|
|
|
|
|
|
const command_t k_commands[] = {
|
|
|
|
{ "run", _tf_command_run, "Run tildefriends (default)." },
|
|
|
|
{ "sandbox", _tf_command_sandbox, "Run a sandboxed tildefriends sandbox process (used internally)." },
|
|
|
|
{ "import", _tf_command_import, "Import apps to SSB." },
|
|
|
|
{ "export", _tf_command_export, "Export apps from SSB." },
|
|
|
|
{ "test", _tf_command_test, "Test SSB." },
|
|
|
|
};
|
|
|
|
|
|
|
|
static int _tf_command_test(const char* file, int argc, char* argv[])
|
|
|
|
{
|
2023-03-19 20:29:46 -04:00
|
|
|
#if !defined(__ANDROID__)
|
2024-02-25 14:45:31 -05:00
|
|
|
tf_test_options_t test_options =
|
2024-02-15 18:35:01 -05:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
.exe_path = file,
|
2021-01-02 13:10:00 -05:00
|
|
|
};
|
2024-02-25 14:45:31 -05:00
|
|
|
bool show_usage = false;
|
2021-01-02 13:10:00 -05:00
|
|
|
|
2024-02-25 14:45:31 -05:00
|
|
|
while (!show_usage)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
static struct option k_options[] =
|
|
|
|
{
|
|
|
|
{ "tests", required_argument, NULL, 't' },
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ 0 },
|
|
|
|
};
|
|
|
|
int c = getopt_long(argc, argv, "t:h", k_options, NULL);
|
|
|
|
if (c == -1)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case '?':
|
|
|
|
case 'h':
|
|
|
|
default:
|
|
|
|
show_usage = true;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
test_options.tests = optarg;
|
|
|
|
break;
|
|
|
|
}
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
|
|
|
|
2024-02-25 14:45:31 -05:00
|
|
|
for (int i = optind; i < argc; i++)
|
2023-08-25 16:57:55 -04:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
tf_printf("Unexpected argument: %s\n", argv[i]);
|
|
|
|
show_usage = true;
|
2023-08-25 16:57:55 -04:00
|
|
|
}
|
2024-02-25 14:45:31 -05:00
|
|
|
|
|
|
|
if (show_usage)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
tf_printf("\n%s test [options]\n\n", file);
|
|
|
|
tf_printf("options\n");
|
|
|
|
tf_printf(" -t, --tests tests Comma-separated list of tests to run. (default: all)\n");
|
|
|
|
tf_printf(" -h, --help Show this usage information.\n");
|
|
|
|
return EXIT_FAILURE;
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
2024-02-25 14:45:31 -05:00
|
|
|
|
|
|
|
tf_tests(&test_options);
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
#else
|
|
|
|
return EXIT_FAILURE;
|
2023-03-19 20:29:46 -04:00
|
|
|
#endif
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static int _tf_command_import(const char* file, int argc, char* argv[])
|
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
const char* user = "import";
|
|
|
|
const char* db_path = k_db_path_default;
|
|
|
|
bool show_usage = false;
|
2021-01-02 13:10:00 -05:00
|
|
|
|
2024-02-25 14:45:31 -05:00
|
|
|
while (!show_usage)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
static struct option k_options[] =
|
|
|
|
{
|
|
|
|
{ "user", required_argument, NULL, 'u' },
|
|
|
|
{ "db-path", required_argument, NULL, 'd' },
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ 0 },
|
|
|
|
};
|
|
|
|
int c = getopt_long(argc, argv, "u:d:h", k_options, NULL);
|
|
|
|
if (c == -1)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2021-01-02 13:10:00 -05:00
|
|
|
|
2024-02-25 14:45:31 -05:00
|
|
|
switch (c)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
case '?':
|
|
|
|
case 'h':
|
|
|
|
default:
|
|
|
|
show_usage = true;
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
user = optarg;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
db_path = optarg;
|
|
|
|
break;
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
2021-10-10 17:51:38 -04:00
|
|
|
}
|
2024-02-25 14:45:31 -05:00
|
|
|
|
|
|
|
if (show_usage)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
tf_printf("\n%s import [options] [paths...]\n\n", file);
|
|
|
|
tf_printf("options:\n");
|
|
|
|
tf_printf(" -u, --user user User into whose account apps will be imported (default: \"import\").\n");
|
|
|
|
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", k_db_path_default);
|
|
|
|
tf_printf(" -h, --help Show this usage information.\n");
|
|
|
|
return EXIT_FAILURE;
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
|
|
|
|
2024-02-25 14:45:31 -05:00
|
|
|
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path);
|
|
|
|
if (optind < argc)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
for (int i = optind; i < argc; i++)
|
|
|
|
{
|
|
|
|
tf_printf("Importing %s...\n", argv[i]);
|
|
|
|
tf_ssb_import(ssb, user, argv[i]);
|
|
|
|
}
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
2024-02-25 14:45:31 -05:00
|
|
|
else
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
tf_printf("Importing %s...\n", "apps");
|
|
|
|
tf_ssb_import(ssb, user, "apps");
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
2024-02-25 14:45:31 -05:00
|
|
|
tf_ssb_destroy(ssb);
|
|
|
|
return EXIT_SUCCESS;
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static int _tf_command_export(const char* file, int argc, char* argv[])
|
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
const char* user = "core";
|
|
|
|
const char* db_path = k_db_path_default;
|
|
|
|
bool show_usage = false;
|
2021-01-02 13:10:00 -05:00
|
|
|
|
2024-02-25 14:45:31 -05:00
|
|
|
while (!show_usage)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
static const struct option k_options[] =
|
|
|
|
{
|
|
|
|
{ "user", required_argument, NULL, 'u' },
|
|
|
|
{ "db-path", required_argument, NULL, 'd' },
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ 0 },
|
|
|
|
};
|
|
|
|
int c = getopt_long(argc, argv, "u:d:h", k_options, NULL);
|
|
|
|
if (c == -1)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case '?':
|
|
|
|
case 'h':
|
|
|
|
default:
|
|
|
|
show_usage = true;
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
user = optarg;
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
db_path = optarg;
|
|
|
|
break;
|
|
|
|
}
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
2024-02-25 14:45:31 -05:00
|
|
|
|
|
|
|
if (show_usage)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
tf_printf("\n%s export [options] [paths...]\n\n", file);
|
|
|
|
tf_printf("options:\n");
|
|
|
|
tf_printf(" -u, --user user User from whose account apps will be exported (default: \"core\").\n");
|
|
|
|
tf_printf(" -d, --db-path db_path SQLite database path (default: %s).\n", k_db_path_default);
|
|
|
|
tf_printf(" -h, --help Show this usage information.\n");
|
|
|
|
tf_printf("\n");
|
|
|
|
tf_printf("paths Paths of apps to export (example: /~core/ssb /~user/app).\n");
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
tf_ssb_t* ssb = tf_ssb_create(NULL, NULL, db_path);
|
|
|
|
if (optind < argc)
|
|
|
|
{
|
|
|
|
for (int i = optind; i < argc; i++)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
tf_printf("Exporting %s...\n", argv[i]);
|
|
|
|
tf_ssb_export(ssb, argv[i]);
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
2021-10-10 17:51:38 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
const char* k_export[] = {
|
2022-11-30 19:26:51 -05:00
|
|
|
"admin",
|
|
|
|
"api",
|
|
|
|
"apps",
|
2023-03-25 10:33:52 -04:00
|
|
|
"appstore",
|
2022-11-30 19:26:51 -05:00
|
|
|
"db",
|
|
|
|
"docs",
|
|
|
|
"follow",
|
2022-12-28 12:16:50 -05:00
|
|
|
"ssb",
|
2022-11-30 19:26:51 -05:00
|
|
|
"todo",
|
2021-01-02 13:10:00 -05:00
|
|
|
};
|
2022-05-16 18:30:14 -04:00
|
|
|
for (int i = 0; i < (int)_countof(k_export); i++)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2022-11-30 19:26:51 -05:00
|
|
|
char buffer[256];
|
2024-02-25 14:45:31 -05:00
|
|
|
snprintf(buffer, sizeof(buffer), "/~%s/%s", user, k_export[i]);
|
2023-03-07 12:50:17 -05:00
|
|
|
tf_printf("Exporting %s...\n", buffer);
|
2022-11-30 19:26:51 -05:00
|
|
|
tf_ssb_export(ssb, buffer);
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
tf_ssb_destroy(ssb);
|
2024-02-25 14:45:31 -05:00
|
|
|
return EXIT_SUCCESS;
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
2023-10-15 12:55:25 -04:00
|
|
|
#endif
|
2021-01-02 13:10:00 -05:00
|
|
|
|
2024-02-15 18:35:01 -05:00
|
|
|
typedef struct tf_run_args_t
|
|
|
|
{
|
2021-11-14 17:55:21 -05:00
|
|
|
const char* script;
|
|
|
|
int ssb_port;
|
|
|
|
int http_port;
|
|
|
|
int https_port;
|
|
|
|
const char* db_path;
|
|
|
|
int count;
|
2021-12-01 18:29:53 -05:00
|
|
|
const char* args;
|
2023-03-08 18:59:11 -05:00
|
|
|
const char* zip;
|
2023-10-15 13:33:36 -04:00
|
|
|
bool one_proc;
|
2023-11-08 19:28:34 -05:00
|
|
|
bool verbose;
|
2021-11-14 17:55:21 -05:00
|
|
|
bool help;
|
|
|
|
} tf_run_args_t;
|
|
|
|
|
|
|
|
typedef struct _tf_run_thread_data_t
|
2021-01-02 13:10:00 -05:00
|
|
|
{
|
2021-11-14 17:55:21 -05:00
|
|
|
tf_run_args_t args;
|
|
|
|
int index;
|
|
|
|
int result;
|
|
|
|
} tf_run_thread_data_t;
|
|
|
|
|
|
|
|
static int _tf_run_task(const tf_run_args_t* args, int index)
|
|
|
|
{
|
|
|
|
int result = -1;
|
|
|
|
tf_task_t* task = tf_task_create();
|
|
|
|
tf_task_set_trusted(task, true);
|
2023-03-08 19:32:42 -05:00
|
|
|
tf_printf("setting zip path to %s\n", args->zip);
|
2023-03-08 18:59:11 -05:00
|
|
|
tf_task_set_zip_path(task, args->zip);
|
2021-11-14 17:55:21 -05:00
|
|
|
tf_task_set_ssb_port(task, args->ssb_port ? args->ssb_port + index : 0);
|
|
|
|
tf_task_set_http_port(task, args->http_port ? args->http_port + index : 0);
|
|
|
|
tf_task_set_https_port(task, args->https_port ? args->https_port + index : 0);
|
2021-12-01 18:29:53 -05:00
|
|
|
tf_task_set_args(task, args->args);
|
2023-10-15 13:33:36 -04:00
|
|
|
tf_task_set_one_proc(task, args->one_proc);
|
2021-11-14 17:55:21 -05:00
|
|
|
const char* db_path = args->db_path;
|
|
|
|
char db_path_buffer[256];
|
|
|
|
if (index)
|
|
|
|
{
|
|
|
|
snprintf(db_path_buffer, sizeof(db_path_buffer), "%s.%d", args->db_path, index);
|
|
|
|
db_path = db_path_buffer;
|
|
|
|
}
|
|
|
|
tf_task_set_db_path(task, db_path);
|
|
|
|
tf_task_activate(task);
|
2023-11-08 19:28:34 -05:00
|
|
|
tf_ssb_set_verbose(tf_task_get_ssb(task), args->verbose);
|
2023-11-08 18:03:21 -05:00
|
|
|
tf_ssb_start_periodic(tf_task_get_ssb(task));
|
2024-02-14 22:00:34 -05:00
|
|
|
if (args->http_port || args->https_port)
|
2022-06-04 11:43:35 -04:00
|
|
|
{
|
2024-02-14 22:00:34 -05:00
|
|
|
if (args->zip)
|
|
|
|
{
|
|
|
|
tf_ssb_import_from_zip(tf_task_get_ssb(task), args->zip, "core", "apps");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tf_ssb_import(tf_task_get_ssb(task), "core", "apps");
|
|
|
|
}
|
2022-06-04 11:43:35 -04:00
|
|
|
}
|
2021-11-14 17:55:21 -05:00
|
|
|
if (tf_task_execute(task, args->script))
|
|
|
|
{
|
|
|
|
tf_task_run(task);
|
|
|
|
result = 0;
|
|
|
|
}
|
|
|
|
tf_task_destroy(task);
|
2023-03-07 21:49:41 -05:00
|
|
|
tf_printf("_tf_run_task is done. Goodbye.\n");
|
2021-11-14 17:55:21 -05:00
|
|
|
return result;
|
|
|
|
}
|
2021-01-02 13:10:00 -05:00
|
|
|
|
2021-11-14 17:55:21 -05:00
|
|
|
static void _tf_run_task_thread(void* data)
|
|
|
|
{
|
|
|
|
tf_run_thread_data_t* info = data;
|
|
|
|
info->result = _tf_run_task(&info->args, info->index);
|
|
|
|
}
|
|
|
|
|
2023-10-15 12:55:25 -04:00
|
|
|
#if !TARGET_OS_IPHONE
|
2023-10-17 18:43:13 -04:00
|
|
|
static void _shed_privileges()
|
|
|
|
{
|
2023-10-25 22:56:33 -04:00
|
|
|
#if !defined(_WIN32) && !defined(__HAIKU__)
|
2023-10-17 18:43:13 -04:00
|
|
|
struct rlimit zeroLimit;
|
|
|
|
zeroLimit.rlim_cur = 0;
|
|
|
|
zeroLimit.rlim_max = 0;
|
|
|
|
|
|
|
|
// RLIMIT_AS
|
|
|
|
// RLIMIT_CORE
|
|
|
|
// RLIMIT_CPU
|
|
|
|
// RLIMIT_DATA
|
|
|
|
// RLIMIT_FSIZE
|
|
|
|
// RLIMIT_RSS
|
|
|
|
// RLIMIT_RTPRIO
|
|
|
|
// RLIMIT_RTTIME
|
|
|
|
// RLIMIT_SIGPENDING
|
|
|
|
// RLIMIT_STACK
|
|
|
|
|
|
|
|
if (setrlimit(RLIMIT_FSIZE, &zeroLimit) != 0)
|
|
|
|
{
|
|
|
|
perror("setrlimit(RLIMIT_FSIZE, {0, 0})");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
if (setrlimit(RLIMIT_NOFILE, &zeroLimit) != 0)
|
|
|
|
{
|
|
|
|
perror("setrlimit(RLIMIT_NOFILE, {0, 0})");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
if (setrlimit(RLIMIT_NPROC, &zeroLimit) != 0)
|
|
|
|
{
|
|
|
|
perror("setrlimit(RLIMIT_NPROC, {0, 0})");
|
|
|
|
exit(-1);
|
|
|
|
}
|
2023-11-07 22:36:08 -05:00
|
|
|
#if !defined(__MACH__) && !defined(__OpenBSD__)
|
2023-10-17 18:43:13 -04:00
|
|
|
if (setrlimit(RLIMIT_LOCKS, &zeroLimit) != 0)
|
|
|
|
{
|
|
|
|
perror("setrlimit(RLIMIT_LOCKS, {0, 0})");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
if (setrlimit(RLIMIT_MSGQUEUE, &zeroLimit) != 0)
|
|
|
|
{
|
|
|
|
perror("setrlimit(RLIMIT_MSGQUEUE, {0, 0})");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
2024-02-17 09:55:39 -05:00
|
|
|
|
|
|
|
#if defined(__OpenBSD__)
|
|
|
|
/* How do I unveil nothing? */
|
2024-02-17 10:33:08 -05:00
|
|
|
if (unveil("/dev/null", "r") || unveil(NULL, NULL))
|
2024-02-17 09:55:39 -05:00
|
|
|
{
|
|
|
|
perror("unveil");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
if (pledge("stdio unveil", NULL))
|
|
|
|
{
|
|
|
|
perror("pledge");
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
#endif
|
2023-10-17 18:43:13 -04:00
|
|
|
}
|
|
|
|
|
2021-11-14 17:55:21 -05:00
|
|
|
static int _tf_command_run(const char* file, int argc, char* argv[])
|
|
|
|
{
|
2024-02-15 18:35:01 -05:00
|
|
|
tf_run_args_t args = {
|
2021-11-14 17:55:21 -05:00
|
|
|
.count = 1,
|
2021-01-02 13:10:00 -05:00
|
|
|
.script = "core/core.js",
|
|
|
|
.http_port = 12345,
|
2022-01-04 20:58:12 -05:00
|
|
|
.https_port = 12346,
|
2023-08-25 14:51:14 -04:00
|
|
|
.ssb_port = 8008,
|
2023-02-14 21:43:08 -05:00
|
|
|
.db_path = k_db_path_default,
|
2021-01-02 13:10:00 -05:00
|
|
|
};
|
2024-02-25 14:45:31 -05:00
|
|
|
bool show_usage = false;
|
|
|
|
|
|
|
|
while (!show_usage)
|
|
|
|
{
|
|
|
|
static const struct option k_options[] =
|
|
|
|
{
|
|
|
|
{ "script", required_argument, NULL, 's' },
|
|
|
|
{ "ssb-port", required_argument, NULL, 'b' },
|
|
|
|
{ "http-port", required_argument, NULL, 'p' },
|
|
|
|
{ "https-port", required_argument, NULL, 'q' },
|
|
|
|
{ "db-path", required_argument, NULL, 'd' },
|
|
|
|
{ "count", required_argument, NULL, 'n' },
|
|
|
|
{ "args", required_argument, NULL, 'a' },
|
|
|
|
{ "one-proc", no_argument, NULL, 'o' },
|
|
|
|
{ "zip", required_argument, NULL, 'z' },
|
|
|
|
{ "verbose", no_argument, NULL, 'v' },
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
};
|
|
|
|
int c = getopt_long(argc, argv, "s:b:p:q:d:n:a:oz:vh", k_options, NULL);
|
|
|
|
if (c == -1)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case '?':
|
|
|
|
case 'h':
|
|
|
|
default:
|
|
|
|
show_usage = true;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
args.script = optarg;
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
args.ssb_port = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
args.http_port = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
args.https_port = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
args.db_path = optarg;
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
args.count = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
args.args = optarg;
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
args.one_proc = true;
|
|
|
|
break;
|
|
|
|
case 'z':
|
|
|
|
args.zip = optarg;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
args.verbose = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-01-02 13:10:00 -05:00
|
|
|
|
2024-02-25 14:45:31 -05:00
|
|
|
if (show_usage)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
tf_printf("\n%s run [options]\n\n", file);
|
|
|
|
tf_printf("options\n");
|
|
|
|
tf_printf(" -s, --script script Script to run (default: core/core.js).\n");
|
|
|
|
tf_printf(" -b, --ssb-port port Port on which to run SSB (default: 8008, 0 disables).\n");
|
|
|
|
tf_printf(" -p, --http-port port Port on which to run Tilde Friends web server (default: 12345).\n");
|
|
|
|
tf_printf(" -q, --https-port port Port on which to run secure Tilde Friends web server (default: 12346).\n");
|
|
|
|
tf_printf(" -d, --db-path path SQLite database path (default: %s).\n", k_db_path_default);
|
|
|
|
tf_printf(" -n, --count count Number of instances to run.\n");
|
|
|
|
tf_printf(" -a, --args args Arguments of the format key=value,foo=bar,verbose=true.\n");
|
|
|
|
tf_printf(" -o, --one-proc Run everything in one process (unsafely!).\n");
|
|
|
|
tf_printf(" -z, --zip path Zip archive from which to load files.\n");
|
|
|
|
tf_printf(" -v, --verbose Log raw messages.\n");
|
|
|
|
tf_printf(" -h, --help Show this usage information.\n");
|
|
|
|
return EXIT_FAILURE;
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int result = 0;
|
2022-05-16 18:30:14 -04:00
|
|
|
#if !defined(_WIN32) && !defined(__MACH__)
|
2021-01-02 13:10:00 -05:00
|
|
|
setpgid(0, 0);
|
|
|
|
#endif
|
2021-11-14 17:55:21 -05:00
|
|
|
|
|
|
|
if (args.count == 1)
|
2021-01-02 13:10:00 -05:00
|
|
|
{
|
2021-11-14 17:55:21 -05:00
|
|
|
_tf_run_task(&args, 0);
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
2021-11-14 17:55:21 -05:00
|
|
|
if (args.count > 1)
|
2021-01-02 13:10:00 -05:00
|
|
|
{
|
2022-06-04 13:04:51 -04:00
|
|
|
uv_thread_t* threads = tf_malloc(sizeof(uv_thread_t) * args.count);
|
|
|
|
tf_run_thread_data_t* data = tf_malloc(sizeof(tf_run_thread_data_t) * args.count);
|
2024-02-15 18:35:01 -05:00
|
|
|
for (int i = 0; i < args.count; i++)
|
2021-11-14 17:55:21 -05:00
|
|
|
{
|
2024-02-15 18:35:01 -05:00
|
|
|
data[i] = (tf_run_thread_data_t) {
|
2021-11-14 17:55:21 -05:00
|
|
|
.args = args,
|
|
|
|
.index = i,
|
|
|
|
};
|
|
|
|
uv_thread_create(&threads[i], _tf_run_task_thread, &data[i]);
|
|
|
|
}
|
|
|
|
for (int i = 0; i < args.count; i++)
|
|
|
|
{
|
|
|
|
uv_thread_join(&threads[i]);
|
|
|
|
if (data[i].result != 0)
|
|
|
|
{
|
|
|
|
result = data[i].result;
|
|
|
|
}
|
|
|
|
}
|
2022-06-04 13:04:51 -04:00
|
|
|
tf_free(data);
|
|
|
|
tf_free(threads);
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int _tf_command_sandbox(const char* file, int argc, char* argv[])
|
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
bool show_usage = false;
|
2021-01-02 13:10:00 -05:00
|
|
|
|
2024-02-25 14:45:31 -05:00
|
|
|
while (!show_usage)
|
|
|
|
{
|
|
|
|
static const struct option k_options[] =
|
|
|
|
{
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ 0 },
|
|
|
|
};
|
|
|
|
int c = getopt_long(argc, argv, "h", k_options, NULL);
|
|
|
|
if (c == -1)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case '?':
|
|
|
|
case 'h':
|
|
|
|
default:
|
|
|
|
show_usage = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-01-02 13:10:00 -05:00
|
|
|
|
2024-02-25 14:45:31 -05:00
|
|
|
if (show_usage)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
tf_printf("\nUsage: %s sandbox [options]\n\n", file);
|
|
|
|
tf_printf("options:\n");
|
|
|
|
tf_printf(" -h, --help Show this usage information.\n");
|
|
|
|
return EXIT_FAILURE;
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
|
|
|
|
2023-11-07 22:36:08 -05:00
|
|
|
#if defined(__linux__)
|
2021-01-02 13:10:00 -05:00
|
|
|
prctl(PR_SET_PDEATHSIG, SIGHUP);
|
|
|
|
#endif
|
|
|
|
tf_task_t* task = tf_task_create();
|
2023-10-15 13:33:36 -04:00
|
|
|
tf_task_configure_from_fd(task, STDIN_FILENO);
|
2023-10-17 18:43:13 -04:00
|
|
|
_shed_privileges();
|
2022-01-02 13:17:58 -05:00
|
|
|
/* The caller will trigger tf_task_activate with a message. */
|
2021-01-02 13:10:00 -05:00
|
|
|
tf_task_run(task);
|
|
|
|
tf_task_destroy(task);
|
2024-02-25 14:45:31 -05:00
|
|
|
return EXIT_SUCCESS;
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
|
|
|
|
2023-10-17 18:43:13 -04:00
|
|
|
#if !defined(__ANDROID__)
|
2024-02-25 14:45:31 -05:00
|
|
|
static int _tf_command_usage(const char* file)
|
2021-01-02 13:10:00 -05:00
|
|
|
{
|
2023-03-07 12:50:17 -05:00
|
|
|
tf_printf("Usage: %s command [command-options]\n", file);
|
|
|
|
tf_printf("commands:\n");
|
2022-05-16 18:30:14 -04:00
|
|
|
for (int i = 0; i < (int)_countof(k_commands); i++)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2023-03-07 12:50:17 -05:00
|
|
|
tf_printf(" %s - %s\n", k_commands[i].name, k_commands[i].description);
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
2023-12-30 13:59:02 -05:00
|
|
|
return -1;
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
2023-10-16 09:57:40 -04:00
|
|
|
#endif
|
2023-10-17 18:43:13 -04:00
|
|
|
#endif
|
2021-01-02 13:10:00 -05:00
|
|
|
|
2022-09-24 16:54:54 -04:00
|
|
|
static void _backtrace_error(void* data, const char* message, int errnum)
|
|
|
|
{
|
2023-03-07 12:50:17 -05:00
|
|
|
tf_printf("libbacktrace error %d: %s\n", errnum, message);
|
2022-09-24 16:54:54 -04:00
|
|
|
}
|
|
|
|
|
2023-08-04 23:10:24 -04:00
|
|
|
static void _error_handler(int sig)
|
|
|
|
{
|
|
|
|
const char* stack = tf_util_backtrace_string();
|
|
|
|
tf_printf("ERROR:\n%s\n", stack);
|
|
|
|
tf_free((void*)stack);
|
|
|
|
_exit(1);
|
|
|
|
}
|
|
|
|
|
2023-10-16 09:57:40 -04:00
|
|
|
static void _startup(int argc, char* argv[])
|
2021-01-02 13:10:00 -05:00
|
|
|
{
|
2024-01-07 21:18:10 -05:00
|
|
|
char buffer[8] = { 0 };
|
|
|
|
size_t buffer_size = sizeof(buffer);
|
|
|
|
bool tracking = uv_os_getenv("TF_MEM_TRACKING", buffer, &buffer_size) == 0 && strcmp(buffer, "1") == 0;
|
2023-02-18 16:00:39 -05:00
|
|
|
for (int i = 1; i < argc; i++)
|
|
|
|
{
|
|
|
|
if (strcmp(argv[i], "sandbox") == 0)
|
|
|
|
{
|
|
|
|
tracking = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-23 19:06:59 -04:00
|
|
|
#if defined(__ANDROID__)
|
|
|
|
setenv("UV_USE_IO_URING", "0", 1);
|
|
|
|
#endif
|
|
|
|
|
2023-02-18 16:00:39 -05:00
|
|
|
tf_mem_startup(tracking);
|
2024-02-15 18:35:01 -05:00
|
|
|
g_backtrace_state = backtrace_create_state(argv[0], 0, _backtrace_error, NULL);
|
2022-09-24 16:54:54 -04:00
|
|
|
|
2023-11-07 22:36:08 -05:00
|
|
|
#if defined(__linux__)
|
2021-08-19 15:29:37 -04:00
|
|
|
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
2022-05-16 18:30:14 -04:00
|
|
|
#endif
|
2022-06-04 13:04:51 -04:00
|
|
|
tf_mem_replace_uv_allocator();
|
|
|
|
tf_mem_replace_tls_allocator();
|
2023-02-18 14:14:06 -05:00
|
|
|
tf_mem_replace_sqlite_allocator();
|
2021-01-02 13:10:00 -05:00
|
|
|
uv_setup_args(argc, argv);
|
|
|
|
tf_taskstub_startup();
|
|
|
|
|
2022-05-16 18:30:14 -04:00
|
|
|
#if !defined(_WIN32)
|
2021-10-10 17:51:38 -04:00
|
|
|
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
|
|
|
|
{
|
2021-01-02 13:10:00 -05:00
|
|
|
perror("signal");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2023-08-04 23:10:24 -04:00
|
|
|
bool use_error_handler = false;
|
|
|
|
#if defined(__ANDROID__)
|
|
|
|
use_error_handler = true;
|
|
|
|
#endif
|
2023-08-22 12:48:12 -04:00
|
|
|
if (use_error_handler)
|
2023-08-04 23:10:24 -04:00
|
|
|
{
|
2023-08-22 12:49:42 -04:00
|
|
|
if (
|
|
|
|
#if !defined(_WIN32)
|
2024-02-17 14:22:02 -05:00
|
|
|
signal(SIGSYS, _error_handler) == SIG_ERR ||
|
2023-08-22 12:49:42 -04:00
|
|
|
#endif
|
2024-02-17 14:22:02 -05:00
|
|
|
signal(SIGSEGV, _error_handler) == SIG_ERR)
|
2023-08-22 12:48:12 -04:00
|
|
|
{
|
|
|
|
perror("signal");
|
|
|
|
}
|
2023-08-04 23:10:24 -04:00
|
|
|
}
|
2023-10-16 09:57:40 -04:00
|
|
|
}
|
|
|
|
|
2023-10-17 18:43:13 -04:00
|
|
|
#if defined(__ANDROID__)
|
2023-10-16 09:57:40 -04:00
|
|
|
int main(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
_startup(argc, argv);
|
2023-10-17 18:43:13 -04:00
|
|
|
int result = -1;
|
|
|
|
if (argc > 1)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2023-10-17 18:43:13 -04:00
|
|
|
if (strcmp(argv[1], "run") == 0)
|
2021-10-10 17:51:38 -04:00
|
|
|
{
|
2023-10-17 18:43:13 -04:00
|
|
|
result = _tf_command_run(argv[0], argc - 2, argv + 2);
|
|
|
|
}
|
|
|
|
else if (strcmp(argv[1], "sandbox") == 0)
|
|
|
|
{
|
|
|
|
result = _tf_command_sandbox(argv[0], argc - 2, argv + 2);
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
2023-02-18 16:00:39 -05:00
|
|
|
}
|
|
|
|
tf_mem_shutdown();
|
|
|
|
return result;
|
2021-01-02 13:10:00 -05:00
|
|
|
}
|
2023-10-19 20:16:01 -04:00
|
|
|
#elif TARGET_OS_IPHONE
|
2023-10-15 12:55:25 -04:00
|
|
|
void tf_run_thread_start(const char* zip_path)
|
|
|
|
{
|
2023-10-16 09:57:40 -04:00
|
|
|
_startup(0, NULL);
|
2023-10-15 12:55:25 -04:00
|
|
|
uv_thread_t* thread = tf_malloc(sizeof(uv_thread_t));
|
|
|
|
tf_run_thread_data_t* data = tf_malloc(sizeof(tf_run_thread_data_t));
|
2024-02-15 18:35:01 -05:00
|
|
|
tf_run_args_t args = {
|
2023-10-15 12:55:25 -04:00
|
|
|
.count = 1,
|
|
|
|
.script = "core/core.js",
|
|
|
|
.http_port = 12345,
|
|
|
|
.https_port = 12346,
|
|
|
|
.ssb_port = 8008,
|
|
|
|
.db_path = k_db_path_default,
|
2023-10-15 13:42:04 -04:00
|
|
|
.one_proc = true,
|
2023-10-15 12:55:25 -04:00
|
|
|
.zip = zip_path,
|
|
|
|
};
|
2024-02-15 18:35:01 -05:00
|
|
|
*data = (tf_run_thread_data_t) {
|
2023-10-15 12:55:25 -04:00
|
|
|
.args = args,
|
|
|
|
};
|
|
|
|
uv_thread_create(thread, _tf_run_task_thread, data);
|
|
|
|
}
|
2023-10-17 18:43:13 -04:00
|
|
|
#else
|
|
|
|
int main(int argc, char* argv[])
|
|
|
|
{
|
|
|
|
_startup(argc, argv);
|
|
|
|
|
|
|
|
int result = 0;
|
|
|
|
if (argc >= 2)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < (int)_countof(k_commands); i++)
|
|
|
|
{
|
|
|
|
const command_t* command = &k_commands[i];
|
|
|
|
if (strcmp(argv[1], command->name) == 0)
|
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
result = command->callback(argv[0], argc - 1, argv + 1);
|
2023-10-17 18:43:13 -04:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
2024-02-25 14:45:31 -05:00
|
|
|
result = _tf_command_usage(argv[0]);
|
2023-10-17 18:43:13 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-02-25 14:45:31 -05:00
|
|
|
result = _tf_command_run(argv[0], argc, argv);
|
2023-10-17 18:43:13 -04:00
|
|
|
}
|
|
|
|
done:
|
|
|
|
tf_mem_shutdown();
|
|
|
|
return result;
|
|
|
|
}
|
2023-10-16 21:30:38 -04:00
|
|
|
#endif
|