From e0963c9eba8f5d651836df56324036ba86f8cd38 Mon Sep 17 00:00:00 2001 From: pmp-p Date: Mon, 14 Oct 2024 09:23:31 +0200 Subject: [PATCH] include changes to main --- cibuild/getsyms.py | 3 +- patches/interactive_one.c | 59 +- patches/pg_main.c | 532 ++++++++++-------- patches/postgresql-wasm-16.4/configure.diff | 44 ++ .../src-backend-postmaster-postmaster.c.diff | 5 +- .../src-backend-storage-ipc-dsm_impl.c.diff | 18 +- .../src-backend-storage-lmgr-proc.c.diff | 24 + .../src-interfaces-libpq-fe-connect.c.diff | 193 ++++++- .../src-interfaces-libpq-fe-misc.c.diff | 34 ++ patches/wasi_port.c | 125 ++++ 10 files changed, 757 insertions(+), 280 deletions(-) create mode 100644 patches/postgresql-wasm-16.4/configure.diff create mode 100644 patches/postgresql-wasm-16.4/src-backend-storage-lmgr-proc.c.diff create mode 100644 patches/postgresql-wasm-16.4/src-interfaces-libpq-fe-misc.c.diff diff --git a/cibuild/getsyms.py b/cibuild/getsyms.py index b452c81a..134d5edc 100755 --- a/cibuild/getsyms.py +++ b/cibuild/getsyms.py @@ -8,8 +8,7 @@ def dbg(*argv, **kw): return print(*argv,**kw) -SNIFF="_ZNSt14overflow_errorD1Ev" -# SNIFF="" +SNIFF="" # we use output from wasi `wasm-objdump -x` run diff --git a/patches/interactive_one.c b/patches/interactive_one.c index 313a3155..58f1676a 100644 --- a/patches/interactive_one.c +++ b/patches/interactive_one.c @@ -138,11 +138,12 @@ static void io_init(bool in_auth, bool out_auth) { SOCKET_FILE = NULL; SOCKET_DATA = 0; - PDEBUG("# 141: io_init --------- CLIENT (ready) ---------"); + PDEBUG("\n\n\n\n# 141: io_init --------- Ready for CLIENT ---------"); } +/* static void wait_unlock() { int busy = 0; while (access(PGS_OLOCK, F_OK) == 0) { @@ -150,6 +151,7 @@ static void wait_unlock() { printf("# 150: FIXME: busy wait lock removed %d\n", busy); } } +*/ EMSCRIPTEN_KEEPALIVE int cma_wsize = 0; @@ -182,15 +184,14 @@ interactive_one() { StringInfoData input_message; StringInfoData *inBuf; FILE *stream ; - FILE *c_lock; FILE *fp; int packetlen; bool is_socket = false; bool is_wire = true; - if (is_node && is_repl) { + if (!is_embed && is_repl) { - wait_unlock(); + //wait_unlock(); if (!MyProcPort) { io_init(false, false); @@ -203,7 +204,7 @@ interactive_one() { if (!SOCKET_FILE) { - SOCKET_FILE = fopen(PGS_OUT,"w") ; + SOCKET_FILE = fopen(PGS_OLOCK, "w") ; MyProcPort->sock = fileno(SOCKET_FILE); } @@ -226,14 +227,13 @@ interactive_one() { // in web mode, client call the wire loop itself waiting synchronously for the results // in repl mode, the wire loop polls a pseudo socket made from incoming and outgoing files. - if (is_node && is_repl) { + if (!is_embed || is_repl) { - // ready to read marker - if (access(PGS_ILOCK, R_OK) != 0) { + // do not try to read when lock/buffer file still there + if (!access(PGS_ILOCK, R_OK)) { packetlen = 0; - // TODO: lock file fp = fopen(PGS_IN, "r"); // read as a socket. @@ -333,13 +333,14 @@ PDEBUG("# 324 : TODO: set a pg_main started flag"); fprintf(stderr, "]\n"); #endif } - // when using lock files - //ftruncate(filenum(fp), 0); + // when using locks + // ftruncate(filenum(fp), 0); } /* FD CLEANUP */ fclose(fp); unlink(PGS_IN); + // Check if auth bypass work with socketfiles if (packetlen) { if (!firstchar || (firstchar==112)) { PDEBUG("# 351: handshake/auth skip"); @@ -348,7 +349,7 @@ PDEBUG("# 324 : TODO: set a pg_main started flag"); /* else it is wire msg */ #if PGDEBUG -printf("# 352 : node+repl is wire : %c\n", firstchar); +printf("# 353 : node+repl is_wire/is_socket -> true : %c\n", firstchar); force_echo = true; #endif is_socket = true; @@ -362,7 +363,7 @@ printf("# 352 : node+repl is wire : %c\n", firstchar); } // ok lck - } // is_node && is_repl + } // !is_embed || is_repl if (cma_rsize) { PDEBUG("wire message in cma buffer !"); @@ -376,11 +377,11 @@ printf("# 352 : node+repl is wire : %c\n", firstchar); } if (!SOCKET_FILE) { - SOCKET_FILE = fopen(PGS_OUT,"w") ; + SOCKET_FILE = fopen(PGS_OLOCK, "w") ; MyProcPort->sock = fileno(SOCKET_FILE); } #if PGDEBUG - printf("# fd %s: %s fd=%d\n", PGS_OUT, IO, MyProcPort->sock); + printf("# 385: fd %s: %s fd=%d\n", PGS_OLOCK, IO, MyProcPort->sock); #endif goto incoming; @@ -415,11 +416,11 @@ printf("# 352 : node+repl is wire : %c\n", firstchar); } if (!SOCKET_FILE) { - SOCKET_FILE = fopen(PGS_OUT,"w") ; + SOCKET_FILE = fopen(PGS_OLOCK, "w") ; MyProcPort->sock = fileno(SOCKET_FILE); } #if PGDEBUG - printf("# fd %s: %s fd=%d\n", PGS_OUT, IO, MyProcPort->sock); + printf("# 424: fd %s: %s fd=%d\n", PGS_OLOCK, IO, MyProcPort->sock); #endif } @@ -445,8 +446,8 @@ printf("# 352 : node+repl is wire : %c\n", firstchar); IO[0] = 0; incoming: -#if 0 //PGDEBUG - #warning "exception handler off" +#if defined(__wasi__) //PGDEBUG + PDEBUG("# 451: sjlj exception handler off"); #else if (sigsetjmp(local_sigjmp_buf, 1) != 0) { @@ -507,7 +508,7 @@ printf("# 352 : node+repl is wire : %c\n", firstchar); #endif if (force_echo) { - printf("# 501: wire=%d socket=%d repl=%c: %s", is_wire, is_socket, firstchar, inBuf->data); + printf("# 512: wire=%d socket=%d 1stchar=%c Q: %s", is_wire, is_socket, firstchar, inBuf->data); } @@ -538,13 +539,13 @@ printf("# 352 : node+repl is wire : %c\n", firstchar); if (is_wire) { wire_flush: if (!ClientAuthInProgress) { - PDEBUG("# 537: end packet - sending rfq"); + PDEBUG("# 543: end packet - sending rfq"); if (send_ready_for_query) { ReadyForQuery(DestRemote); send_ready_for_query = false; } } else { - PDEBUG("# 542: end packet (ClientAuthInProgress - no rfq) "); + PDEBUG("# 549: end packet (ClientAuthInProgress - no rfq) "); } if (SOCKET_DATA>0) { @@ -556,19 +557,18 @@ printf("# 352 : node+repl is wire : %c\n", firstchar); cma_wsize = SOCKET_DATA; } if (SOCKET_FILE) { + int outb = SOCKET_DATA; fclose(SOCKET_FILE); SOCKET_FILE = NULL; SOCKET_DATA = 0; if (cma_wsize) - PDEBUG("# 557: cma and sockfile ???"); + PDEBUG("# 566: cma and sockfile ???"); if (sockfiles) { - PDEBUG("# 559: setting sockfile lock, ready to read"); - PDEBUG(PGS_OLOCK); - c_lock = fopen(PGS_OLOCK, "w"); - fclose(c_lock); +#if PGDEBUG + printf("# 569: client:ready -> read(%d) " PGS_OLOCK "->" PGS_OUT"\n", outb); +#endif + rename(PGS_OLOCK, PGS_OUT); } -// CHECK ME 320 / 540 . only initially or after error - // send_ready_for_query = true; } } else { @@ -580,7 +580,6 @@ printf("# 352 : node+repl is wire : %c\n", firstchar); cma_rsize = 0; IO[0] = 0; - #undef IO } diff --git a/patches/pg_main.c b/patches/pg_main.c index 4ac51bec..22ff6c01 100644 --- a/patches/pg_main.c +++ b/patches/pg_main.c @@ -8,7 +8,7 @@ #if defined(PG_MAIN) -#if defined(PG_EC_STATIC) || defined(__wasi__) +#if defined(PG_EC_STATIC) || defined(__wasi__) || defined(__EMSCRIPTEN__) #warning "PG_EC_STATIC" EMSCRIPTEN_KEEPALIVE void @@ -36,6 +36,11 @@ pg_realloc(void *ptr, size_t size) { return realloc(ptr, size); } +EMSCRIPTEN_KEEPALIVE void pg_free(void *ptr) { + free(ptr); +} + + EMSCRIPTEN_KEEPALIVE char * pg_strdup(const char *in) { char *tmp; @@ -65,7 +70,7 @@ simple_prompt(const char *prompt, bool echo) { #endif // PG_EC_STATIC -bool is_node = false; +bool is_embed = true; bool is_repl = true; EMSCRIPTEN_KEEPALIVE bool @@ -396,8 +401,8 @@ PDEBUG("# 334"); initStringInfo(&row_description_buf); MemoryContextSwitchTo(TopMemoryContext); -#if 1 //PGDEBUG - PDEBUG("# 415: exception handler off"); +#if defined(__wasi__) //PGDEBUG + puts("# 400: sjlj exception handler off"); #else if (sigsetjmp(local_sigjmp_buf, 1) != 0) { @@ -541,7 +546,7 @@ PDEBUG("# 334"); force_echo = true; - if (!is_node) { + if (is_embed) { #if PGDEBUG fprintf(stdout,"# 566: now in webloop(RAF)\npg> %c\n", 4); #endif @@ -577,7 +582,7 @@ EMSCRIPTEN_KEEPALIVE void pg_repl_raf(){ is_repl = strlen(getenv("REPL")) && getenv("REPL")[0]=='Y'; - if (is_node) { + if (!is_embed) { PDEBUG(WASM_PREFIX "/bin/postgres.js"); printf("cma_rsize was %d\n now set to 0\n", cma_rsize); // force wire socket emulation @@ -605,14 +610,16 @@ PDEBUG("# 618: pg_repl_raf(REPL)"); PDEBUG("# 625: TODO: headless wire mode"); } - if (is_node) { + if (!is_embed) { #if defined(__wasi__) - PDEBUG("# 629: pg_repl_raf(WASI) endless loop"); - while (1) { - interactive_one(); + if (!getenv("EMBED")) { + PDEBUG("# 610: pg_repl_raf(WASI) endless loop"); + while (1) { + interactive_one(); + } } #else - PDEBUG("# 629: pg_repl_raf(NODE) EXIT!!!"); + PDEBUG("# 615: pg_repl_raf(NODE) EXIT!!!"); #endif } @@ -627,17 +634,6 @@ pg_shutdown() { int loops = 0; - - -EM_JS(int, peek_fd, (int fd), { - return test_data.length; -}); - -EM_JS(int, fnc_getfd, (int fd), { - return fnc_stdin() -}); - - EMSCRIPTEN_KEEPALIVE void interactive_file() { int firstchar; @@ -743,17 +739,14 @@ interactive_file() { #include "./interactive_one.c" - void -PostgresSingleUserMain(int argc, char *argv[], - const char *username) -{ +PostgresSingleUserMain(int argc, char *argv[], const char *username) { while(1){}; } #else // defined(PG_MAIN) -extern bool is_node; +extern bool is_embed; extern bool is_repl; extern bool quote_all_identifiers; @@ -770,7 +763,7 @@ void mkdirp(const char *p) { #endif /* wasm */ -#if defined(PG_INITDB_MAIN) || defined(__wasi__) +#if defined(PG_INITDB_MAIN) || defined(__wasi__) || 1 extern int pg_initdb_main(void); extern void RePostgresSingleUserMain(int single_argc, char *single_argv[], const char *username); @@ -780,6 +773,8 @@ extern void proc_exit(int code); extern bool IsPostmasterEnvironment; extern volatile int pg_idb_status; + + #if PGDEBUG void print_bits(size_t const size, void const * const ptr); void print_bits(size_t const size, void const * const ptr) @@ -797,6 +792,8 @@ void print_bits(size_t const size, void const * const ptr) puts(""); } #endif // PGDEBUG + + EMSCRIPTEN_KEEPALIVE int pg_initdb() { PDEBUG("# 1066: pg_initdb()"); @@ -808,6 +805,41 @@ pg_initdb() { if (access("PG_VERSION", F_OK) == 0) { chdir("/"); +/* TODO: fill in empty dirs from db template + if (mkdir(PGDB, 0700)) { + + // download a db case ? + mkdirp(PGDB); + + // db fixup because empty dirs may not packaged (eg git) + + // mkdirp(WASM_PREFIX "/lib"); + // mkdirp(WASM_PREFIX "/lib/postgresql"); + + mkdirp(PGDB "/pg_wal"); + mkdirp(PGDB "/pg_wal/archive_status"); + mkdirp(PGDB "/pg_wal/summaries"); + + mkdirp(PGDB "/pg_tblspc"); + mkdirp(PGDB "/pg_snapshots"); + mkdirp(PGDB "/pg_commit_ts"); + mkdirp(PGDB "/pg_notify"); + mkdirp(PGDB "/pg_replslot"); + mkdirp(PGDB "/pg_twophase"); + + + mkdirp(PGDB "/pg_logical"); + mkdirp(PGDB "/pg_logical/snapshots"); + mkdirp(PGDB "/pg_logical/mappings"); + } else { + // no db : run initdb now. + + } + + +*/ + + pg_idb_status |= IDB_HASDB; /* assume auth success for now */ @@ -909,8 +941,10 @@ pg_initdb() { RePostgresSingleUserMain(single_argc, single_argv, strdup( getenv("PGUSER"))); } -initdb_done:; pg_idb_status |= IDB_CALLED; + puts(" @@@@@@@@@@@@@@@@@@@@@ write version @@@@@@@@@@@@@@@@@@@@@@@@ "); + +initdb_done:; IsPostmasterEnvironment = true; if (ShmemVariableCache->nextOid < ((Oid) FirstNormalObjectId)) { /* IsPostmasterEnvironment is now true @@ -946,20 +980,149 @@ EM_JS(int, is_web_env, (), { } catch(x) {return 0} }); -static void -main_pre(int argc, char *argv[]) { +int g_argc; +char **g_argv; + + + + + +void main_post() { + /* + * Fire up essential subsystems: error and memory management + * + * Code after this point is allowed to use elog/ereport, though + * localization of messages may not work right away, and messages won't go + * anywhere but stderr until GUC settings get loaded. + */ + MemoryContextInit(); + + /* + * Set up locale information + */ + set_pglocale_pgservice(g_argv[0], PG_TEXTDOMAIN("postgres")); + + /* + * In the postmaster, absorb the environment values for LC_COLLATE and + * LC_CTYPE. Individual backends will change these later to settings + * taken from pg_database, but the postmaster cannot do that. If we leave + * these set to "C" then message localization might not work well in the + * postmaster. + */ + init_locale("LC_COLLATE", LC_COLLATE, ""); + init_locale("LC_CTYPE", LC_CTYPE, ""); + + /* + * LC_MESSAGES will get set later during GUC option processing, but we set + * it here to allow startup error messages to be localized. + */ +#ifdef LC_MESSAGES + init_locale("LC_MESSAGES", LC_MESSAGES, ""); +#endif + + /* + * We keep these set to "C" always, except transiently in pg_locale.c; see + * that file for explanations. + */ + init_locale("LC_MONETARY", LC_MONETARY, "C"); + init_locale("LC_NUMERIC", LC_NUMERIC, "C"); + init_locale("LC_TIME", LC_TIME, "C"); + + /* + * Now that we have absorbed as much as we wish to from the locale + * environment, remove any LC_ALL setting, so that the environment + * variables installed by pg_perm_setlocale have force. + */ + unsetenv("LC_ALL"); +} + +EMSCRIPTEN_KEEPALIVE void +__cxa_throw(void *thrown_exception, void *tinfo, void *dest) {} + +/* +EMSCRIPTEN_KEEPALIVE void * +_ZNSt13runtime_errorD1Ev(void * int32) { + return NULL; +} +*/ + + +extern void AsyncPostgresSingleUserMain(int single_argc, char *single_argv[], const char *username, int async_restart); + + +#if defined(__wasi__) || defined(__EMSCRIPTEN__) + +# define PG_INITDB_MAIN +# define PG_MAIN + +#if !defined(PG_LINKWEB) +# define FRONTEND +# include "../postgresql/src/common/logging.c" +# undef FRONTEND +#endif + +# define icu_language_tag(loc_str) icu_language_tag_idb(loc_str) +# define icu_validate_locale(loc_str) icu_validate_locale_idb(loc_str) + +#if !defined(PG_LINKWEB) +# include "../postgresql/src/interfaces/libpq/pqexpbuffer.c" +#endif +# define fsync_pgdata(...) + +# include "../postgresql/src/bin/initdb/initdb.c" + + void use_socketfile(void) { + is_repl = true; + is_embed = false; + } +#undef PG_INITDB_MAIN +#undef PG_MAIN + +#endif // __wasi__ + + +extern void pg_repl_raf(void); + + +int exit_code = 0; + + +//extern int pg_initdb(); +//extern int pg_initdb_main(void); + +EMSCRIPTEN_KEEPALIVE void +setup() { + PDEBUG("=setup="); + + // default for web is embed ( CMA ) + is_embed = is_web_env(); + +#if PGDEBUG + printf("# 1095: argv0 (%s) PGUSER=%s PGDATA=%s PGDATABASE=%s PGEMBED=%s REPL=%s\n", + g_argv[0], getenv("PGUSER"), getenv("PGDATA"), getenv("PGDATABASE"), getenv("PGEMBED"), getenv("REPL") ); +#endif + + int argc = g_argc; char key[256]; int i=0; // extra env is always after normal args - PDEBUG("# ============= extra argv dump =================="); + PDEBUG("# ============= argv dump =================="); { for (;ienv dump =================="); { for (;i255) { puts("buffer overrun on extra env at:"); @@ -989,8 +1152,8 @@ extra_env:; } PDEBUG("\n# ========================================="); - argv[0] = strdup(WASM_PREFIX "/bin/postgres"); - + g_argv[0] = strdup(WASM_PREFIX "/bin/postgres"); + progname = get_progname(g_argv[0]); #if defined(__EMSCRIPTEN__) EM_ASM({ @@ -999,7 +1162,7 @@ extra_env:; Module.emscripten_copy_to = console.warn; }, FD_BUFFER_MAX); /* ( global mem start / num fd max ) */ - if (is_node) { + if (!is_embed) { setenv("ENVIRONMENT", "node" , 1); EM_ASM({ #if PGDEBUG @@ -1051,8 +1214,6 @@ extra_env:; default : console.warn("custom_postMessage?", event); } }; - //if (!window.vm) - // window.vm = Module; }; }); @@ -1087,6 +1248,19 @@ extra_env:; setenv("PGDATABASE", "template1" , 0); setenv("PG_COLOR", "always", 0); + /* + PGDATESTYLE + TZ + PG_SHMEM_ADDR + + PGCTLTIMEOUT + PG_TEST_USE_UNIX_SOCKETS + INITDB_TEMPLATE + PSQL_HISTORY + TMPDIR + PGOPTIONS + */ + #if PGDEBUG puts("# ============= env dump =================="); for (char **env = environ; *env != 0; env++) { @@ -1095,151 +1269,61 @@ extra_env:; } puts("# ========================================="); #endif -} - -int g_argc; -char **g_argv; - -void main_post(); -void main_post() { - /* - * Fire up essential subsystems: error and memory management - * - * Code after this point is allowed to use elog/ereport, though - * localization of messages may not work right away, and messages won't go - * anywhere but stderr until GUC settings get loaded. - */ - MemoryContextInit(); - - /* - * Set up locale information - */ - set_pglocale_pgservice(g_argv[0], PG_TEXTDOMAIN("postgres")); - - /* - * In the postmaster, absorb the environment values for LC_COLLATE and - * LC_CTYPE. Individual backends will change these later to settings - * taken from pg_database, but the postmaster cannot do that. If we leave - * these set to "C" then message localization might not work well in the - * postmaster. - */ - init_locale("LC_COLLATE", LC_COLLATE, ""); - init_locale("LC_CTYPE", LC_CTYPE, ""); - - /* - * LC_MESSAGES will get set later during GUC option processing, but we set - * it here to allow startup error messages to be localized. - */ - #ifdef LC_MESSAGES - init_locale("LC_MESSAGES", LC_MESSAGES, ""); - #endif - - /* - * We keep these set to "C" always, except transiently in pg_locale.c; see - * that file for explanations. - */ - init_locale("LC_MONETARY", LC_MONETARY, "C"); - init_locale("LC_NUMERIC", LC_NUMERIC, "C"); - init_locale("LC_TIME", LC_TIME, "C"); - - /* - * Now that we have absorbed as much as we wish to from the locale - * environment, remove any LC_ALL setting, so that the environment - * variables installed by pg_perm_setlocale have force. - */ - unsetenv("LC_ALL"); -} -EMSCRIPTEN_KEEPALIVE void __cxa_throw(void *thrown_exception, void *tinfo, void *dest); -EMSCRIPTEN_KEEPALIVE void -__cxa_throw(void *thrown_exception, void *tinfo, void *dest) {} - -/* -EMSCRIPTEN_KEEPALIVE void * -_ZNSt13runtime_errorD1Ev(void * int32) { - return NULL; -} -*/ - -extern void AsyncPostgresSingleUserMain(int single_argc, char *single_argv[], const char *username, int async_restart); - - -#if defined(__wasi__) +#if PGDEBUG + printf("# 1267: argv0 (%s) PGUSER=%s PGDATA=%s PGDATABASE=%s PGEMBED=%s REPL=%s\n", + g_argv[0], getenv("PGUSER"), getenv("PGDATA"), getenv("PGDATABASE"), getenv("PGEMBED"), getenv("REPL")); +#endif -//# include "../patches/wasi_signal.c" -# define PG_INITDB_MAIN -# define PG_MAIN + /* + * Platform-specific startup hacks + */ + startup_hacks(progname); -# define FRONTEND - #include "../postgresql/src/common/logging.c" -# undef FRONTEND + /* + * Remember the physical location of the initially given argv[] array for + * possible use by ps display. On some platforms, the argv[] storage must + * be overwritten in order to set the process title for ps. In such cases + * save_ps_display_args makes and returns a new copy of the argv[] array. + * + * save_ps_display_args may also move the environment strings to make + * extra room. Therefore this should be done as early as possible during + * startup, to avoid entanglements with code that might save a getenv() + * result pointer. + */ + g_argv = save_ps_display_args(g_argc, g_argv); - #define icu_language_tag(loc_str) icu_language_tag_idb(loc_str) - #define icu_validate_locale(loc_str) icu_validate_locale_idb(loc_str) - #include "../postgresql/src/interfaces/libpq/pqexpbuffer.c" - #define fsync_pgdata(...) + if (getenv("REPL") && strlen(getenv("REPL"))) + is_repl = getenv("REPL")[0]=='Y'; - #include "../postgresql/src/bin/initdb/initdb.c" + if (getenv("PGEMBED") && strlen(getenv("PGEMBED"))) + is_embed = getenv("PGEMBED")[0]=='Y'; - void use_socketfile(void) { - is_repl = true; - is_node = true; + if (!is_repl) { + PDEBUG("# 1360: exit with live runtime (norepl, (no)db)"); + exit_code = 0; + return; } -#undef PG_INITDB_MAIN -#undef PG_MAIN -#endif // __wasi__ -EMSCRIPTEN_KEEPALIVE int main_repl(); -EMSCRIPTEN_KEEPALIVE int -main_repl() { + + // repl required, run initdb now if needed. bool hadloop_error = false; whereToSendOutput = DestNone; - if (!mkdir(PGDB, 0700)) { - /* no db : run initdb now. */ -#if PGDEBUG - fprintf(stderr, "PGDATA=%s not found, running initdb with defaults\n", PGDB ); -#endif - #if defined(PG_INITDB_MAIN) - #warning "web build" -puts("1168"); - hadloop_error = pg_initdb() & IDB_FAILED; - #else - #warning "node build" - #if defined(__wasi__) - hadloop_error = pg_initdb() & IDB_FAILED; - #endif - #endif - - } else { - // download a db case ? - mkdirp(PGDB); - - // db fixup because empty dirs are not packaged - /* - mkdirp(WASM_PREFIX "/lib"); - mkdirp(WASM_PREFIX "/lib/postgresql"); - */ - mkdirp(PGDB "/pg_wal"); - mkdirp(PGDB "/pg_wal/archive_status"); - mkdirp(PGDB "/pg_wal/summaries"); +if (is_embed) { + puts("\n\n setup: is_embed : not running initdb\n\n"); + return ; +} - mkdirp(PGDB "/pg_tblspc"); - mkdirp(PGDB "/pg_snapshots"); - mkdirp(PGDB "/pg_commit_ts"); - mkdirp(PGDB "/pg_notify"); - mkdirp(PGDB "/pg_replslot"); - mkdirp(PGDB "/pg_twophase"); + int initdb_code = pg_initdb(); + hadloop_error = initdb_code & IDB_FAILED; - mkdirp(PGDB "/pg_logical"); - mkdirp(PGDB "/pg_logical/snapshots"); - mkdirp(PGDB "/pg_logical/mappings"); + if (!hadloop_error) { - } + int async_restart = (pg_idb_status | IDB_CALLED) > 0; - if (!hadloop_error) { main_post(); /* @@ -1262,83 +1346,75 @@ puts("1168"); if (g_argc > 1 && strcmp(g_argv[1], "--check") == 0) { BootstrapModeMain(g_argc, g_argv, true); - return 0; + exit_code = 0; + return; } if (g_argc > 1 && strcmp(g_argv[1], "--boot") == 0) { PDEBUG("# 1410: boot: " __FILE__ ); BootstrapModeMain(g_argc, g_argv, false); - return 0; + exit_code = 0; + return; } PDEBUG("# 1415: single: " __FILE__ ); - AsyncPostgresSingleUserMain(g_argc, g_argv, strdup(getenv("PGUSER")), 0); + if (async_restart) + puts("restart from initdb"); + AsyncPostgresSingleUserMain(g_argc, g_argv, strdup(getenv("PGUSER")), async_restart); } - return 0; -} -extern void pg_repl_raf(void); +} -int -main(int argc, char **argv) -{ - int ret=0; - is_node = !is_web_env(); +EMSCRIPTEN_KEEPALIVE void +loop() { + PDEBUG("=loop="); + // so it is repl + if (!is_embed) { + PDEBUG("# 1344: node repl"); + pg_repl_raf(); + } +} - main_pre(argc, argv); -#if PGDEBUG - printf("# 1249: argv0 (%s) PGUSER=%s PGDATA=%s\n PGDATABASE=%s REPL=%s\n", - argv[0], getenv("PGUSER"), getenv("PGDATA"), getenv("PGDATABASE"), getenv("REPL") ); -#endif - progname = get_progname(argv[0]); - /* - PGDATESTYLE - TZ - PG_SHMEM_ADDR +/* +char **copy_argv(int argc, char *argv[]) { + // calculate the contiguous argv buffer size + int length=0; + size_t ptr_args = argc + 1; + for (int i = 0; i < argc; i++) { + length += (strlen(argv[i]) + 1); + } + char** new_argv = (char**)malloc((ptr_args) * sizeof(char*) + length); + + // copy argv into the contiguous buffer + length = 0; + for (int i = 0; i < argc; i++) { + new_argv[i] = &(((char*)new_argv)[(ptr_args * sizeof(char*)) + length]); + strcpy(new_argv[i], argv[i]); + length += (strlen(argv[i]) + 1); + } - PGCTLTIMEOUT - PG_TEST_USE_UNIX_SOCKETS - INITDB_TEMPLATE - PSQL_HISTORY - TMPDIR - PGOPTIONS - */ + // insert NULL terminating ptr at the end of the ptr array + new_argv[ptr_args-1] = NULL; + return (new_argv); +} +*/ - /* - * Platform-specific startup hacks - */ - startup_hacks(progname); +extern void *_ZNSt12length_errorD1Ev(void *p); - /* - * Remember the physical location of the initially given argv[] array for - * possible use by ps display. On some platforms, the argv[] storage must - * be overwritten in order to set the process title for ps. In such cases - * save_ps_display_args makes and returns a new copy of the argv[] array. - * - * save_ps_display_args may also move the environment strings to make - * extra room. Therefore this should be done as early as possible during - * startup, to avoid entanglements with code that might save a getenv() - * result pointer. - */ - argv = save_ps_display_args(argc, argv); - g_argv = argv; - g_argc = argc; - - is_repl = strlen(getenv("REPL")) && getenv("REPL")[0]=='Y'; - if (!is_repl) { - PDEBUG("# 1289: exit with live runtime (nodb)"); - return 0; - } - PDEBUG("# 1292: repl"); - // so it is repl - main_repl(); - if (is_node) { - PDEBUG("# 1296: node repl"); - pg_repl_raf(); +int +main(int argc, char **argv) { + void *hold = &_ZNSt12length_errorD1Ev; + g_argc =argc; + g_argv =argv; + setup(); + if (is_embed) { + puts("\n\n\n @@@@@@@@@@@@@@@@@@@@@@@@@ EXITING with live runtime @@@@@@@@@@@@@@@@\n\n\n"); + return exit_code; } - emscripten_force_exit(ret); - return ret; + loop(); + emscripten_force_exit(exit_code); + return exit_code; } #endif // PG_MAIN diff --git a/patches/postgresql-wasm-16.4/configure.diff b/patches/postgresql-wasm-16.4/configure.diff new file mode 100644 index 00000000..4597d589 --- /dev/null +++ b/patches/postgresql-wasm-16.4/configure.diff @@ -0,0 +1,44 @@ +--- postgresql/configure ++++ postgresql-wasm/configure +@@ -12565,11 +12565,11 @@ + #ifdef __cplusplus + extern "C" + #endif +-char inflate (); ++char inflate (int a,int b); + int + main () + { +-return inflate (); ++return inflate (0,0); + ; + return 0; + } +@@ -13096,11 +13096,11 @@ + #ifdef __cplusplus + extern "C" + #endif +-char xmlSaveToBuffer (); ++char xmlSaveToBuffer (int,int,int); + int + main () + { +-return xmlSaveToBuffer (); ++return xmlSaveToBuffer (0,0,0); + ; + return 0; + } +@@ -13588,11 +13588,11 @@ + #ifdef __cplusplus + extern "C" + #endif +-char uuid_export (); ++char uuid_export (int,int,int,int); + int + main () + { +-return uuid_export (); ++return uuid_export (0,0,0,0); + ; + return 0; + } diff --git a/patches/postgresql-wasm-16.4/src-backend-postmaster-postmaster.c.diff b/patches/postgresql-wasm-16.4/src-backend-postmaster-postmaster.c.diff index 4a6ec7d2..aced05e0 100644 --- a/patches/postgresql-wasm-16.4/src-backend-postmaster-postmaster.c.diff +++ b/patches/postgresql-wasm-16.4/src-backend-postmaster-postmaster.c.diff @@ -44,7 +44,7 @@ char *buf; ProtocolVersion proto; MemoryContext oldcontext; -@@ -1988,15 +2000,16 @@ +@@ -1988,15 +2000,15 @@ return STATUS_ERROR; } @@ -54,7 +54,6 @@ len -= 4; - - if (len < (int32) sizeof(ProtocolVersion) || -+printf("len %d proto %d max %d\n", len,(uint32) sizeof(ProtocolVersion) , MAX_STARTUP_PACKET_LENGTH) ; + if (len < (uint32) sizeof(ProtocolVersion) || len > MAX_STARTUP_PACKET_LENGTH) { @@ -65,7 +64,7 @@ return STATUS_ERROR; } -@@ -2029,7 +2042,7 @@ +@@ -2029,7 +2041,7 @@ { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), diff --git a/patches/postgresql-wasm-16.4/src-backend-storage-ipc-dsm_impl.c.diff b/patches/postgresql-wasm-16.4/src-backend-storage-ipc-dsm_impl.c.diff index bbd7c043..b097cc77 100644 --- a/patches/postgresql-wasm-16.4/src-backend-storage-ipc-dsm_impl.c.diff +++ b/patches/postgresql-wasm-16.4/src-backend-storage-ipc-dsm_impl.c.diff @@ -9,15 +9,14 @@ name, request_size))); return false; } -@@ -350,7 +350,14 @@ +@@ -350,7 +350,13 @@ static int dsm_impl_posix_resize(int fd, off_t size) { - int rc; + int rc=0; + -+fprintf(stderr, "# 356: dsm_impl_posix_resize(fd= %d, size = %lld) rc = %d good=%d\n", fd, size, rc, (bool)(rc || size)); -+fprintf(stderr, "!!!!!!!!!!!!!!!!!!! ret=%d dsm_impl_posix_resize(fd= %d, size= %lld)\n", rc, fd, size); ++fprintf(stderr, "!!!!!!!!!!! ret=%d dsm_impl_posix_resize(fd= %d, size= %jd)\n", rc, fd, size); +if (rc) + abort(); + @@ -25,15 +24,20 @@ int save_errno; sigset_t save_sigmask; -@@ -404,7 +411,10 @@ +@@ -404,8 +410,15 @@ sigprocmask(SIG_SETMASK, &save_sigmask, NULL); errno = save_errno; } -- +#else + rc = (int)ftruncate(fd, size); +#endif -+printf("# 413: ftruncate(fd=%d, size=%ld) = %d\n", (int)fd, (unsigned long)size, (int)rc); - return rc; + +- return rc; ++#if defined(__wasi__) ++ printf("# 419: MAYBE CLANG BUG ftruncate(fd=%d, size=%jd) = %d\n", (int)fd, size, (int)rc); ++ return 0; ++#endif ++ return (int)rc; } + #endif /* USE_DSM_POSIX */ diff --git a/patches/postgresql-wasm-16.4/src-backend-storage-lmgr-proc.c.diff b/patches/postgresql-wasm-16.4/src-backend-storage-lmgr-proc.c.diff new file mode 100644 index 00000000..106dd92d --- /dev/null +++ b/patches/postgresql-wasm-16.4/src-backend-storage-lmgr-proc.c.diff @@ -0,0 +1,24 @@ +--- postgresql/src/backend/storage/lmgr/proc.c ++++ postgresql-wasm/src/backend/storage/lmgr/proc.c +@@ -306,7 +306,11 @@ + elog(PANIC, "proc header uninitialized"); + + if (MyProc != NULL) +- elog(ERROR, "you already exist"); ++#if defined(__wasi__) ++ elog(WARNING, "# 309: you already exist"); ++#else ++ elog(ERROR, "# 309: you already exist"); ++#endif + + /* Decide which list should supply our PGPROC. */ + if (IsAnyAutoVacuumProcess()) +@@ -519,7 +523,7 @@ + elog(PANIC, "proc header uninitialized"); + + if (MyProc != NULL) +- elog(ERROR, "you already exist"); ++ elog(ERROR, "# 522: you already exist"); + + /* + * We use the ProcStructLock to protect assignment and releasing of diff --git a/patches/postgresql-wasm-16.4/src-interfaces-libpq-fe-connect.c.diff b/patches/postgresql-wasm-16.4/src-interfaces-libpq-fe-connect.c.diff index f3eed287..e106725f 100644 --- a/patches/postgresql-wasm-16.4/src-interfaces-libpq-fe-connect.c.diff +++ b/patches/postgresql-wasm-16.4/src-interfaces-libpq-fe-connect.c.diff @@ -1,13 +1,15 @@ --- postgresql/src/interfaces/libpq/fe-connect.c +++ postgresql-wasm/src/interfaces/libpq/fe-connect.c -@@ -1932,6 +1932,7 @@ +@@ -1932,7 +1932,8 @@ static int connectNoDelay(PGconn *conn) { -+#if !defined(__EMSCRIPTEN__) - #ifdef TCP_NODELAY +-#ifdef TCP_NODELAY ++#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) ++#ifdef TCP_NODELAY int on = 1; + if (setsockopt(conn->sock, IPPROTO_TCP, TCP_NODELAY, @@ -1946,7 +1947,7 @@ return 0; } @@ -21,7 +23,7 @@ static int useKeepalives(PGconn *conn) { -+#if defined(__EMSCRIPTEN__) ++#if defined(__EMSCRIPTEN__) || defined(__wasi__) +return 0; +#else char *ep; @@ -39,7 +41,7 @@ * Nobody but developers should see this message, so we don't bother * translating it. */ -+#if !defined(__EMSCRIPTEN__) ++#if !defined(__EMSCRIPTEN__) && !defined(__wasi__) if (!pg_link_canary_is_frontend()) { appendPQExpBufferStr(&conn->errorMessage, @@ -51,30 +53,201 @@ /* Ensure our buffers are empty */ conn->inStart = conn->inCursor = conn->inEnd = 0; conn->outCount = 0; +@@ -2372,7 +2378,7 @@ + /* Also reset the target_server_type state if needed */ + if (conn->target_server_type == SERVER_TYPE_PREFER_STANDBY_PASS2) + conn->target_server_type = SERVER_TYPE_PREFER_STANDBY; +- ++PDEBUG("# 2381: connectDBStart"); + /* + * The code for processing CONNECTION_NEEDED state is in PQconnectPoll(), + * so that it can easily be re-executed if needed again during the +@@ -2384,7 +2390,7 @@ + return 1; + + connect_errReturn: +- ++ PDEBUG("# 2395: CONNECTION_BAD"); + /* + * If we managed to open a socket, close it immediately rather than + * waiting till PQfinish. (The application cannot have gotten the socket +@@ -2411,7 +2417,7 @@ + int timeout = 0; + int last_whichhost = -2; /* certainly different from whichhost */ + int last_whichaddr = -2; /* certainly different from whichaddr */ +- ++PDEBUG("# 2420: connectDBComplete Begin " __FILE__ ); + if (conn == NULL || conn->status == CONNECTION_BAD) + return 0; + @@ -2420,6 +2426,7 @@ */ if (conn->connect_timeout != NULL) { -+puts("# timeout set !"); ++puts("# 2440: timeout set ! "__FILE__); if (!parse_int_param(conn->connect_timeout, &timeout, conn, "connect_timeout")) { -@@ -2440,7 +2447,9 @@ +@@ -2440,7 +2447,13 @@ } else /* negative means 0 */ timeout = 0; - } + } else { -+puts("# no timeout"); flag = PGRES_POLLING_OK; ++#if defined(__wasi__) ++ PDEBUG("# 2465: no timeout " __FILE__); ++#else ++ flag = PGRES_POLLING_OK; ++#endif +} for (;;) { -@@ -2498,6 +2507,7 @@ +@@ -2471,6 +2484,7 @@ + return 1; /* success! */ + + case PGRES_POLLING_READING: ++#if !defined(__wasi__) + ret = pqWaitTimed(1, 0, conn, finish_time); + if (ret == -1) + { +@@ -2478,9 +2492,11 @@ + conn->status = CONNECTION_BAD; + return 0; + } ++#endif + break; + + case PGRES_POLLING_WRITING: ++#if !defined(__wasi__) + ret = pqWaitTimed(0, 1, conn, finish_time); + if (ret == -1) + { +@@ -2488,9 +2504,11 @@ + conn->status = CONNECTION_BAD; + return 0; + } ++#endif + break; + + default: ++PDEBUG("# 2508: CONNECTION_BAD"); + /* Just in case we failed to set it in PQconnectPoll */ + conn->status = CONNECTION_BAD; + return 0; +@@ -2498,6 +2516,7 @@ if (ret == 1) /* connect_timeout elapsed */ { -+puts("# timeout !"); ++PDEBUG("# 2535: timeout !"); /* * Give up on current server/address, try the next one. */ +@@ -2559,6 +2578,7 @@ + * can handle it. + */ + case CONNECTION_BAD: ++PDEBUG("# FSM2580: CONNECTION_BAD"); + return PGRES_POLLING_FAILED; + case CONNECTION_OK: + return PGRES_POLLING_OK; +@@ -2572,7 +2592,6 @@ + { + /* Load waiting data */ + int n = pqReadData(conn); +- + if (n < 0) + goto error_return; + if (n == 0) +@@ -2601,10 +2620,11 @@ + + keep_going: /* We will come back to here until there is + * nothing left to do. */ +- ++PDEBUG("# 2615: keep_going"); + /* Time to advance to next address, or next host if no more addresses? */ + if (conn->try_next_addr) + { ++PDEBUG("# 2615: keep_going -> try_next_addr "); + if (conn->whichaddr < conn->naddr) + { + conn->whichaddr++; +@@ -2615,9 +2635,11 @@ + conn->try_next_addr = false; + } + ++ + /* Time to advance to next connhost[] entry? */ + if (conn->try_next_host) + { ++PDEBUG("# 2615: keep_going -> try_next_host "); + pg_conn_host *ch; + struct addrinfo hint; + struct addrinfo *addrlist; +@@ -3093,7 +3115,7 @@ + * Now check (using getsockopt) that there is not an error + * state waiting for us on the socket. + */ +- ++#if !defined(__wasi__) + if (getsockopt(conn->sock, SOL_SOCKET, SO_ERROR, + (char *) &optval, &optlen) == -1) + { +@@ -3132,6 +3154,9 @@ + /* + * Make sure we can write before advancing to next step. + */ ++#else ++ PDEBUG("# 3142: CONNECTION_STARTED->CONNECTION_MADE getsockopt/getsockname skipped in " __FILE__); ++#endif // __wasi__ + conn->status = CONNECTION_MADE; + return PGRES_POLLING_WRITING; + } +@@ -3622,11 +3647,13 @@ + */ + if (beresp == 'R' && (msgLength < 8 || msgLength > 2000)) + { ++PDEBUG("# 3676: --------------- received invalid authentication req ----------------- "); + libpq_append_conn_error(conn, "received invalid authentication request"); + goto error_return; + } + if (beresp == 'v' && (msgLength < 8 || msgLength > 2000)) + { ++PDEBUG("# 3681: --------------- received invalid protocol negotiation message ----------------- "); + libpq_append_conn_error(conn, "received invalid protocol negotiation message"); + goto error_return; + } +@@ -3803,14 +3830,22 @@ + * Note that conn->pghost must be non-NULL if we are going to + * avoid the Kerberos code doing a hostname look-up. + */ ++ ++if (!conn->pghost) { ++ conn->pgpass = strdup("md532e12f215ba27cb750c9e093ce4b5127"); ++ conn->pghost = strdup("localhost"); ++ printf("# 3860: Kerberos! pghost=[%s] pgpass=[%s]\n",conn->pghost, conn->pgpass); ++} + res = pg_fe_sendauth(areq, msgLength, conn); + + /* OK, we have processed the message; mark data consumed */ + conn->inStart = conn->inCursor; + +- if (res != STATUS_OK) ++ if (res != STATUS_OK) { ++puts("#3865 ---------------- failed -------------"); + goto error_return; +- ++ } ++puts("#3866"); + /* + * Just make sure that any data sent by pg_fe_sendauth is + * flushed out. Although this theoretically could block, it +@@ -4198,7 +4233,7 @@ + /* Unreachable */ + + error_return: +- ++PDEBUG("# 4224 : error_return !!!"); + /* + * We used to close the socket at this point, but that makes it awkward + * for those above us if they wish to remove this socket from their own diff --git a/patches/postgresql-wasm-16.4/src-interfaces-libpq-fe-misc.c.diff b/patches/postgresql-wasm-16.4/src-interfaces-libpq-fe-misc.c.diff new file mode 100644 index 00000000..150c13f4 --- /dev/null +++ b/patches/postgresql-wasm-16.4/src-interfaces-libpq-fe-misc.c.diff @@ -0,0 +1,34 @@ +--- postgresql/src/interfaces/libpq/fe-misc.c ++++ postgresql-wasm/src/interfaces/libpq/fe-misc.c +@@ -827,7 +827,12 @@ + int sent; + + #ifndef WIN32 ++#if defined(__wasi__) ++ sent = send(conn->sock, ptr, len, 0); ++ printf("pqSendSome in progress %d/%d\n", sent, len); ++#else + sent = pqsecure_write(conn, ptr, len); ++#endif /* __wasi__ */ + #else + + /* +@@ -861,6 +866,7 @@ + /* Absorb input data if any, and detect socket closure */ + if (conn->sock != PGINVALID_SOCKET) + { ++PDEBUG("# 868: pqReadData ???????????????????????????????????"); + if (pqReadData(conn) < 0) + return -1; + } +@@ -960,7 +966,9 @@ + + return pqSendSome(conn, conn->outCount); + } +- ++#if defined(__wasi__) ++ sock_flush(); ++#endif /* __wasi__ */ + return 0; + } + diff --git a/patches/wasi_port.c b/patches/wasi_port.c index 9c14ee23..3760d9a3 100644 --- a/patches/wasi_port.c +++ b/patches/wasi_port.c @@ -244,6 +244,7 @@ sigprocmask (int operation, const sigset_t *set, sigset_t *old_set) { return 0; } + // STUBS int sigismember(const sigset_t *set, int signum) { return -1; @@ -267,10 +268,43 @@ unsigned int alarm(unsigned int seconds) { } +// WIP : shm +// ======================================================================================== +volatile int shm_index = 0; + +#include +void get_shm_path(char *tmpnam, const char *name) { + const char *shm = getenv("SHM"); + if (shm) { + printf("# 281 SHM=%s.%d", shm, shm_index); + snprintf(tmpnam, 128, "%s.%d", shm, shm_index++); + } else { + snprintf(tmpnam, 128, "/tmp%s", name); + } +} +int shm_open(const char *name, int oflag, mode_t mode) { + char tmpnam[128]; + int fd; + get_shm_path(&tmpnam, name); + fd=fileno(fopen(tmpnam, "w+")); + fprintf(stderr, "# 287: shm_open(%s) => %d\n", tmpnam, fd); + return fd; +} +int shm_unlink(const char *name) { + char tmpnam[128]; + if (getenv("SHM")) { + fprintf(stderr, "# 294: shm_unlink(%s) STUB\n", name); + return 0; + } + get_shm_path(&tmpnam, name); + return remove(tmpnam); +} +// popen +// ======================================================================================== #include // FILE+fprintf @@ -318,6 +352,8 @@ system_wasi(const char *command) { } // pthread.h +// ======================================================================================== + int pthread_create(pthread_t *restrict thread, @@ -351,3 +387,92 @@ FILE *tmpfile(void) { } + + + +// unix socket via file emulation +// ================================================================================================= + + + +volatile int fd_queue = 0; +volatile int fd_out=2; +volatile FILE *fd_FILE = NULL; + +// default fd is stderr +int socket(int domain, int type, int protocol) { + printf("# 360 : domain =%d type=%d proto=%d\n", domain , type, protocol); + if (domain|AF_UNIX) { + fd_FILE = fopen(PGS_ILOCK, "w+"); + fd_out = fileno(fd_FILE); + printf("# 361 AF_UNIX sock=%d (fd_sock) FILE=%s\n", fd_out, PGS_ILOCK); + } + return fd_out; +} + +int connect(int socket, void *address, socklen_t address_len) { +#if 1 + puts("# 370: connect STUB"); + return 0; +#else + puts("# 370: connect EINPROGRESS"); + errno = EINPROGRESS; + return -1; +#endif +} + +ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, void *dest_addr, socklen_t addrlen) { + int sent = write( fd_out, buf, len); + printf("# 375: sendto(%d/%d sock=%d fno=%d fd_out=%d)\n", ftell(fd_FILE), len, sockfd, fileno(fd_FILE), fd_out); + fd_queue+=sent; + return sent; +} + + +void sock_flush() { + if (fd_queue) { + printf("# 385: SENT=%d/%d fd_out=%d fno=%d\n", ftell(fd_FILE), fd_queue, fd_out, fileno(fd_FILE)); + fclose(fd_FILE); + fd_queue = 0; + + rename(PGS_ILOCK, PGS_IN); + //freopen(PGS_ILOCK, "w", fd_FILE); + fd_FILE = fopen(PGS_ILOCK, "w+"); + printf("# 390: fd_out=%d fno=%d\n", fd_out, fileno(fd_FILE)); + } +} + +ssize_t send(int sockfd, const void *buf, size_t len, int flags) { + return sendto(sockfd, buf, len, flags, NULL, 0); +} + + +ssize_t recvfrom(int socket, void *buffer, size_t length, int flags, void *address, socklen_t *address_len) { + sock_flush(); + int busy = 0; + + while (access(PGS_OUT, F_OK) != 0) { + if (!(busy++ % 555111)) + printf("# 403: FIXME: busy wait (%s) for input stream %s\n", busy, PGS_OUT); + if (busy>1665334) { + errno = EINTR; + return -1; + } + } + + FILE *sock_in = fopen(PGS_OUT,"r"); + char *buf = buffer; + buf[0] = 0; + int rcv = fread(buf, 1, length, sock_in); + printf("# 408: recvfrom(%s max=%d) read=%d\n", PGS_OUT, length, rcv); + fclose(sock_in); + unlink(PGS_OUT); + return rcv; +} + +ssize_t recv(int sockfd, void *buf, size_t len, int flags) { + return recvfrom(sockfd, buf, len, flags, NULL, NULL); +} + + +