GNUnet 0.29.1-dev.1-3-g346358e26
 
Loading...
Searching...
No Matches
pq_connect.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet
3 Copyright (C) 2017, 2019, 2020, 2021, 2023 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
26#include "platform.h"
27#include "pq.h"
28#include <poll.h>
29#include <pthread.h>
30
31
33#define PSQL_OUTPUT_BYTES (64 * 1024)
34
36#define PSQL_OUTPUT_LINES 250
37
38
44static void
46{
47 if (NULL == db->conn)
48 return;
49 PQfinish (db->conn);
50 db->conn = NULL;
51 db->prepared_check_patch = false;
52 db->prepared_get_oid_by_name = false;
53}
54
55
65{
66 PGresult *res;
67
68 if (db->prepared_check_patch)
69 return GNUNET_OK;
70 res = PQprepare (db->conn,
71 "gnunet_pq_check_patch",
72 "SELECT"
73 " applied_by"
74 " FROM _v.patches"
75 " WHERE patch_name = $1"
76 " LIMIT 1",
77 1,
78 NULL);
79 if (PGRES_COMMAND_OK !=
80 PQresultStatus (res))
81 {
83 "Failed to run SQL logic to setup database versioning logic: %s/%s\n",
84 PQresultErrorMessage (res),
85 PQerrorMessage (db->conn));
86 PQclear (res);
88 return GNUNET_SYSERR;
89 }
90 PQclear (res);
91 db->prepared_check_patch = true;
92 return GNUNET_OK;
93}
94
95
105{
106 PGresult *res;
107
108 if (db->prepared_get_oid_by_name)
109 return GNUNET_OK;
110 res = PQprepare (db->conn,
111 "gnunet_pq_get_oid_by_name",
112 "SELECT typname, oid"
113 " FROM pg_type"
114 " WHERE oid = to_regtype($1)",
115 1,
116 NULL);
117 if (PGRES_COMMAND_OK != PQresultStatus (res))
118 {
120 "Failed to run SQL statement prepare OID lookups: %s/%s\n",
121 PQresultErrorMessage (res),
122 PQerrorMessage (db->conn));
123 PQclear (res);
125 return GNUNET_SYSERR;
126 }
127 PQclear (res);
128 db->prepared_get_oid_by_name = true;
129 return GNUNET_OK;
130}
131
132
144{
145 PGresult *res;
146 ExecStatusType est;
147
148 if (GNUNET_OK == db->versioning_ok)
149 return GNUNET_OK;
150 if (GNUNET_NO == db->versioning_ok)
151 return GNUNET_NO;
152 res = PQexec (db->conn,
153 "SELECT"
154 " schema_name"
155 " FROM information_schema.schemata"
156 " WHERE schema_name='_v';");
157 est = PQresultStatus (res);
158 if ( (PGRES_COMMAND_OK != est) &&
159 (PGRES_TUPLES_OK != est) )
160 {
162 "Failed to run statement to check versioning schema. Bad!\n");
163 PQclear (res);
164 return GNUNET_SYSERR;
165 }
166 if (0 == PQntuples (res))
167 {
168 PQclear (res);
169 db->versioning_ok = GNUNET_NO;
171 "_v schema not found\n");
172 return GNUNET_NO;
173 }
174 PQclear (res);
175 db->versioning_ok = GNUNET_OK;
176 return GNUNET_OK;
177}
178
179
193 const char *load_path,
194 unsigned int patch_number)
195{
196 const char *load_path_suffix;
197 size_t slen = strlen (load_path) + 10;
198 char patch_name[slen];
199
200 if (GNUNET_SYSERR ==
202 {
203 GNUNET_break (0);
204 return GNUNET_SYSERR; /* no versioning, cannot check */
205 }
206 load_path_suffix = strrchr (load_path,
207 '/');
208 if (NULL == load_path_suffix)
209 load_path_suffix = load_path;
210 else
211 load_path_suffix++; /* skip '/' */
212 GNUNET_snprintf (patch_name,
213 sizeof (patch_name),
214 "%s%04u",
215 load_path_suffix,
216 patch_number);
217 {
218 struct GNUNET_PQ_QueryParam params[] = {
219 GNUNET_PQ_query_param_string (patch_name),
221 };
222 char *applied_by;
223 struct GNUNET_PQ_ResultSpec rs[] = {
224 GNUNET_PQ_result_spec_string ("applied_by",
225 &applied_by),
227 };
228 enum GNUNET_DB_QueryStatus qs;
229
230 if (GNUNET_OK !=
232 {
233 GNUNET_break (0);
234 return GNUNET_SYSERR;
235 }
237 "gnunet_pq_check_patch",
238 params,
239 rs);
240 switch (qs)
241 {
244 "Database version %s already applied by %s\n",
245 patch_name,
246 applied_by);
248 return GNUNET_OK;
250 return GNUNET_NO;
252 GNUNET_break (0);
253 return GNUNET_SYSERR;
255 GNUNET_break (0);
256 return GNUNET_SYSERR;
257 }
258 GNUNET_assert (0);
259 return GNUNET_SYSERR;
260 }
261}
262
263
272static void
274 const PGresult *res)
275{
276 /* do nothing, intentionally */
277 (void) arg;
278 (void) res;
279}
280
281
289static void
291 const char *message)
292{
293 (void) arg;
295 "pq",
296 "%s",
297 message);
298}
299
300
312static char *
314 const char *infix)
315{
316 char *fn;
317
318 GNUNET_asprintf (&fn,
319 "%s%s.sql",
320 db->load_path,
321 infix);
322 return fn;
323}
324
325
340 const char *load_suffix,
341 unsigned int patch_number)
342{
343 size_t slen = strlen (load_suffix) + 10;
344 char patch_name[slen];
345 char *fn;
347
348 GNUNET_snprintf (patch_name,
349 sizeof (patch_name),
350 "%s%04u",
351 load_suffix,
352 patch_number);
353 fn = get_sql_file_name (db,
354 patch_name);
356 GNUNET_free (fn);
357 return ret;
358}
359
360
375static bool
377 const char *load_suffix,
378 unsigned int from,
379 unsigned int *found)
380{
381 for (unsigned int i = from; i<5; i++)
382 {
383 if (GNUNET_YES !=
385 load_suffix,
386 i))
387 continue;
388 *found = i;
389 return true;
390 }
391 return false;
392}
393
394
402static void
403log_psql_output (char *output,
404 size_t size,
405 bool truncated)
406{
407 size_t start = 0;
408 unsigned int lines = 0;
409
410 for (size_t i = size; i > 0; i--)
411 {
412 /* A trailing newline terminates the last line, not an extra empty one. */
413 if ( ('\n' == output[i - 1]) &&
414 (i < size) &&
415 (PSQL_OUTPUT_LINES == ++lines) )
416 {
417 start = i;
418 truncated = true;
419 break;
420 }
421 }
422 if (truncated)
424 "psql stderr truncated to the last %u lines and %u bytes; earlier output omitted\n",
427 output[size] = '\0';
428 for (size_t i = start; i < size; i++)
429 {
430 /* Do not let an embedded NUL hide the remaining diagnostics. */
431 if ('\0' == output[i])
432 output[i] = '?';
433 if ('\n' != output[i])
434 continue;
435 output[i] = '\0';
437 "psql: %s\n",
438 &output[start]);
439 start = i + 1;
440 }
441 if (start < size)
443 "psql: %s\n",
444 &output[start]);
445}
446
447
450 const char *buf)
451{
452 struct GNUNET_Process *psql;
454 unsigned long code;
455 char *fn;
456 struct GNUNET_DISK_PipeHandle *errors;
457 char *output;
458 size_t used = 0;
459 bool truncated = false;
460 bool capture_failed = false;
461 bool child_exited = false;
462 int queued = 0;
463 const struct GNUNET_DISK_FileHandle *reader;
464 struct pollfd ready;
466
467 fn = get_sql_file_name (db,
468 buf);
469 if (GNUNET_YES !=
471 {
472 GNUNET_free (fn);
473 return GNUNET_NO;
474 }
476 "Applying SQL file `%s' on database %s\n",
477 fn,
478 db->config_str);
480 if (NULL == errors)
481 {
483 "pipe for psql stderr",
484 fn);
485 GNUNET_free (fn);
486 return GNUNET_SYSERR;
487 }
488 output = GNUNET_malloc (PSQL_OUTPUT_BYTES + 1);
489 reader = GNUNET_DISK_pipe_handle (errors,
491 ready = (struct pollfd) {
493 .events = POLLIN
494 };
496 if (GNUNET_OK !=
498 psql,
500 STDERR_FILENO)))
501 {
503 "Failed to configure psql stderr capture for SQL file `%s'\n",
504 fn);
505 goto cleanup;
506 }
507 if (GNUNET_OK !=
509 "psql",
510 "psql",
511 db->config_str,
512 "-f",
513 fn,
514 "-q",
515 "--set",
516 "ON_ERROR_STOP=1",
517 NULL))
518 {
520 "exec",
521 "psql");
522 goto cleanup;
523 }
524 /* Drain while psql is running so verbose scripts cannot fill the pipe.
525 Descendants may inherit stderr: once psql exits, drain only the bytes
526 already queued instead of waiting for every inherited writer to close. */
527 while (true)
528 {
529 char chunk[4096];
530 ssize_t count;
531 size_t wanted = sizeof (chunk);
532
533 if (! child_exited)
534 {
536
538 false,
539 &type,
540 &code);
541 if (GNUNET_SYSERR == status)
542 goto wait_failed;
543 if (GNUNET_OK == status)
544 {
545 child_exited = true;
546 while (0 > ioctl (ready.fd, FIONREAD, &queued))
547 {
548 if (EINTR == errno)
549 continue;
551 "inspect queued psql stderr",
552 fn);
553 capture_failed = true;
554 break;
555 }
556 if (capture_failed)
557 break;
558 }
559 }
560 if (child_exited)
561 {
562 if (0 == queued)
563 break;
564 wanted = GNUNET_MIN (wanted, (size_t) queued);
565 }
566 count = GNUNET_DISK_file_read (reader,
567 chunk,
568 wanted);
569 if (0 == count)
570 break;
571 if (0 > count)
572 {
573 if (EINTR == errno)
574 continue;
575 if ( (EAGAIN == errno) || (EWOULDBLOCK == errno) )
576 {
577 if (child_exited)
578 break;
579 /* Periodically recheck the child even if an inherited writer keeps
580 the pipe open without producing output. */
581 if ( (0 > poll (&ready, 1, 100)) && (EINTR != errno) )
582 {
584 "poll psql stderr",
585 fn);
586 capture_failed = true;
587 break;
588 }
589 continue;
590 }
592 "read psql stderr",
593 fn);
594 capture_failed = true;
595 break;
596 }
597 if (child_exited)
598 queued -= count;
599 if (used + count > PSQL_OUTPUT_BYTES)
600 {
601 size_t discard = used + count - PSQL_OUTPUT_BYTES;
602
603 memmove (output,
604 output + discard,
605 used - discard);
606 used -= discard;
607 truncated = true;
608 }
609 memcpy (output + used,
610 chunk,
611 count);
612 used += count;
613 }
614 if (capture_failed && (! child_exited))
615 (void) GNUNET_process_kill (psql,
616 SIGKILL);
617 if (GNUNET_OK !=
619 true,
620 &type,
621 &code))
622 goto wait_failed;
623 if ( (GNUNET_OS_PROCESS_EXITED != type) ||
624 (0 != code) )
625 {
628 "Failed to execute SQL file `%s': psql terminated by signal %lu\n",
629 fn,
630 code);
631 else
633 "Failed to execute SQL file `%s': psql exit code was %lu\n",
634 fn,
635 code);
636 capture_failed = true;
637 }
638 if (capture_failed)
639 log_psql_output (output,
640 used,
641 truncated);
642 else
643 ret = GNUNET_OK;
644 goto cleanup;
645wait_failed:
646 /* ECHILD means another reaper already collected the process; its PID
647 must not be signalled since it could have been reused. */
648 {
649 int eno = errno;
650
652 "wait for psql",
653 fn);
654 if (ECHILD != eno)
655 {
656 (void) GNUNET_process_kill (psql,
657 SIGKILL);
658 (void) GNUNET_process_wait (psql,
659 true,
660 NULL,
661 NULL);
662 }
663 }
664 log_psql_output (output,
665 used,
666 truncated);
667cleanup:
669 GNUNET_DISK_pipe_close (errors);
670 GNUNET_free (output);
671 GNUNET_free (fn);
672 return ret;
673}
674
675
678 const char *load_suffix)
679{
681 "Loading SQL resources from `%s'\n",
682 load_suffix);
683 for (unsigned int i = 1; i<10000; i++)
684 {
686 unsigned int next;
687
689 load_suffix,
690 i);
691 if (GNUNET_SYSERR == ret)
692 {
693 GNUNET_break (0);
694 return GNUNET_SYSERR;
695 }
696 if (GNUNET_OK == ret)
697 continue; /* patch already applied, skip it */
698 /* patch not applied, check if it (or, in case the numbering
699 has a hole, any later patch) exists... */
700 if (find_next_patch (db,
701 load_suffix,
702 i,
703 &next))
704 return GNUNET_NO;
705 return GNUNET_OK;
706 }
707 GNUNET_break (0); /* 10k patches applied!? */
708 return GNUNET_OK;
709}
710
711
714 const char *load_suffix)
715{
716 size_t slen = strlen (load_suffix) + 10;
717 char patch_name[slen];
718
720 "Loading SQL resources from `%s'\n",
721 load_suffix);
722 for (unsigned int i = 1; i<10000; i++)
723 {
725
727 load_suffix,
728 i);
729 if (GNUNET_SYSERR == ret)
730 {
731 GNUNET_break (0);
732 return GNUNET_SYSERR;
733 }
734 if (GNUNET_OK == ret)
735 continue; /* patch already applied, skip it */
736
737 GNUNET_snprintf (patch_name,
738 sizeof (patch_name),
739 "%s%04u",
740 load_suffix,
741 i);
743 patch_name);
744 if (GNUNET_NO == ret)
745 {
746 unsigned int next;
747
748 /* No such file. Before we conclude that we are done, make sure
749 this really is the end of the sequence and not a hole in the
750 numbering: applying the patches beyond the hole (or, worse,
751 silently not applying them) would leave the database in an
752 undefined state. */
753 if (find_next_patch (db,
754 load_suffix,
755 i + 1,
756 &next))
757 {
759 "Gap in SQL patch sequence: `%s%04u' is missing, but `%s%04u' exists; refusing to apply patches out of order\n",
760 load_suffix,
761 i,
762 load_suffix,
763 next);
764 return GNUNET_SYSERR;
765 }
766 break; /* no such file, we are done */
767 }
768 if (GNUNET_SYSERR == ret)
769 return GNUNET_SYSERR;
770 }
771 return GNUNET_OK;
772}
773
774
775void
777{
778 if (1 ==
779 PQconsumeInput (db->conn))
780 return;
781 if (CONNECTION_BAD != PQstatus (db->conn))
782 return;
784}
785
786
789 struct GNUNET_PQ_Context *db,
790 const char *name,
791 Oid *oid)
792{
793 /* Check if the entry is in the cache already */
794 for (unsigned int i = 0; i < db->oids.num; i++)
795 {
796 /* Pointer comparison */
797 if (name == db->oids.table[i].name)
798 {
799 *oid = db->oids.table[i].oid;
800 return GNUNET_OK;
801 }
802 }
803
804 /* No entry found in cache, ask database */
805 {
806 enum GNUNET_DB_QueryStatus qs;
807 struct GNUNET_PQ_QueryParam params[] = {
810 };
811 struct GNUNET_PQ_ResultSpec spec[] = {
813 oid),
815 };
816
817 GNUNET_assert (NULL != db);
818
820 "gnunet_pq_get_oid_by_name",
821 params,
822 spec);
824 return GNUNET_SYSERR;
825 }
826
827 /* Add the entry to the cache */
828 if (NULL == db->oids.table)
829 {
830 db->oids.table = GNUNET_new_array (8,
831 typeof(*db->oids.table));
832 db->oids.cap = 8;
833 db->oids.num = 0;
834 }
835
836 if (db->oids.cap <= db->oids.num)
837 GNUNET_array_grow (db->oids.table,
838 db->oids.cap,
839 db->oids.cap + 8);
840
841 db->oids.table[db->oids.num].name = name;
842 db->oids.table[db->oids.num].oid = *oid;
843 db->oids.num++;
844
845 return GNUNET_OK;
846}
847
848
859{
860 static const char *typnames[] = {
861 "bool",
862 "int2",
863 "int4",
864 "int8",
865 "bytea",
866 "varchar"
867 };
868 Oid oid;
869
870 for (size_t i = 0; i< sizeof(typnames) / sizeof(*typnames); i++)
871 {
872 if (GNUNET_OK !=
874 typnames[i],
875 &oid))
876 {
878 "pq",
879 "Couldn't retrieve OID for type %s\n",
880 typnames[i]);
881 return GNUNET_SYSERR;
882 }
883 }
884 return GNUNET_OK;
885}
886
887
888void
890{
892 -1);
894 db->versioning_ok = GNUNET_SYSERR; /* new connection, new game */
895 db->conn = PQconnectdb (db->config_str);
896 if ( (NULL == db->conn) ||
897 (CONNECTION_OK != PQstatus (db->conn)) )
898 {
900 "pq",
901 "Database connection to '%s' failed: %s\n",
902 db->config_str,
903 (NULL != db->conn)
904 ? PQerrorMessage (db->conn)
905 : "PQconnectdb returned NULL");
907 return;
908 }
909 PQsetNoticeReceiver (db->conn,
911 db);
912 PQsetNoticeProcessor (db->conn,
914 db);
915 if (NULL != db->rc)
916 db->rc (db->rc_cls,
917 db);
918
919 /* Prepare statement for OID lookup by name */
920 if (GNUNET_OK !=
922 return;
923
924 /* Reset the OID-cache and retrieve the OIDs for the supported Array types */
925 db->oids.num = 0;
927 {
929 "Failed to retrieve OID information for array types!\n");
931 return;
932 }
934 PQsocket (db->conn));
935}
936
937
940{
942
944 if (GNUNET_SYSERR == ret)
945 return GNUNET_SYSERR;
946 if (GNUNET_YES == ret)
947 return GNUNET_NO; /* already setup */
949 "versioning");
950 if (GNUNET_NO == ret)
951 {
953 "Failed to find SQL file to load database versioning logic\n");
954 return GNUNET_SYSERR;
955 }
956 if (GNUNET_SYSERR == ret)
957 {
959 "Failed to run SQL logic to setup database versioning logic\n");
960 return GNUNET_SYSERR;
961 }
962 db->versioning_ok = GNUNET_YES;
963 return GNUNET_OK;
964}
965
966
967struct GNUNET_PQ_Context *
969 const char *section,
972{
973 struct GNUNET_PQ_Context *db;
974 char *conninfo;
975 char *load_path;
976
977 if (GNUNET_OK !=
979 section,
980 "CONFIG",
981 &conninfo))
982 conninfo = GNUNET_strdup ("");
983 load_path = NULL;
984 if (GNUNET_OK !=
986 section,
987 "SQL_DIR",
988 &load_path))
989 {
991 section,
992 "SQL_DIR");
993 }
995 db->versioning_ok = GNUNET_SYSERR;
996 db->config_str = conninfo;
997 db->load_path = load_path;
998 db->rc = rc;
999 db->rc_cls = rc_cls;
1000 db->channel_map = GNUNET_CONTAINER_multishortmap_create (16,
1001 true);
1003 if (NULL == db->conn)
1004 {
1006 GNUNET_free (db->config_str);
1007 GNUNET_free (db);
1008 return NULL;
1009 }
1010 return db;
1011}
1012
1013
1014void
1016{
1017 if (NULL == db)
1018 return;
1019 GNUNET_assert (0 ==
1022 if (NULL != db->poller_task)
1023 {
1024 GNUNET_SCHEDULER_cancel (db->poller_task);
1025 db->poller_task = NULL;
1026 }
1027 GNUNET_free (db->load_path);
1028 GNUNET_free (db->config_str);
1029 GNUNET_free (db->oids.table);
1030 db->oids.num = 0;
1031 db->oids.cap = 0;
1032 PQfinish (db->conn);
1033 GNUNET_free (db);
1034}
1035
1036
1037/* end of pq/pq_connect.c */
static int start
Set if we are to start default services (including ARM).
Definition gnunet-arm.c:38
static int ret
Final status code.
Definition gnunet-arm.c:93
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition gnunet-arm.c:108
static char * name
Name (label) of the records to list.
static char * res
Currently read line or NULL on EOF.
static uint32_t type
Type string converted to DNS type value.
static int status
The program status; 0 for success.
Definition gnunet-nse.c:39
static struct GNUNET_FS_DirectoryBuilder * db
static void cleanup()
Cleanup task.
GNUNET_DB_QueryStatus
Status code returned from functions running database commands.
@ GNUNET_DB_STATUS_SUCCESS_ONE_RESULT
The transaction succeeded, and yielded one result.
@ GNUNET_DB_STATUS_HARD_ERROR
A hard error occurred, retrying will not help.
@ GNUNET_DB_STATUS_SUCCESS_NO_RESULTS
The transaction succeeded, but yielded zero results.
@ GNUNET_DB_STATUS_SOFT_ERROR
A soft error occurred, retrying the transaction may succeed.
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_uint32(const char *name, uint32_t *u32)
uint32_t expected.
enum GNUNET_DB_QueryStatus GNUNET_PQ_eval_prepared_singleton_select(struct GNUNET_PQ_Context *db, const char *statement_name, const struct GNUNET_PQ_QueryParam *params, struct GNUNET_PQ_ResultSpec *rs)
Execute a named prepared statement that is a SELECT statement which must return a single result in co...
Definition pq_eval.c:199
void(* GNUNET_PQ_ReconnectCallback)(void *cls, struct GNUNET_PQ_Context *pq)
Function called each time we connect or reconnect to the database.
struct GNUNET_PQ_ResultSpec GNUNET_PQ_result_spec_string(const char *name, char **dst)
0-terminated string expected.
#define GNUNET_PQ_query_param_end
End of query parameter specification.
void GNUNET_PQ_cleanup_result(struct GNUNET_PQ_ResultSpec *rs)
Free all memory that was allocated in rs during GNUNET_PQ_extract_result().
Definition pq.c:143
uint32_t oid
struct GNUNET_PQ_QueryParam GNUNET_PQ_query_param_string(const char *ptr)
Generate query parameter for a string.
#define GNUNET_PQ_result_spec_end
End of result parameter specification.
#define GNUNET_PQ_RECONNECT_CALLBACK_CLOSURE
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
const struct GNUNET_DISK_FileHandle * GNUNET_DISK_pipe_handle(const struct GNUNET_DISK_PipeHandle *p, enum GNUNET_DISK_PipeEnd n)
Get the handle to a particular pipe end.
Definition disk.c:1703
struct GNUNET_DISK_PipeHandle * GNUNET_DISK_pipe(enum GNUNET_DISK_PipeFlags pf)
Creates an interprocess channel.
Definition disk.c:1524
enum GNUNET_GenericReturnValue GNUNET_DISK_file_test_read(const char *fil)
Check that fil corresponds to a filename and the file has read permissions.
Definition disk.c:565
enum GNUNET_GenericReturnValue GNUNET_DISK_pipe_close(struct GNUNET_DISK_PipeHandle *p)
Closes an interprocess channel.
Definition disk.c:1671
int GNUNET_DISK_internal_file_handle(const struct GNUNET_DISK_FileHandle *fh)
Retrieve OS file handle.
Definition disk.c:1731
ssize_t GNUNET_DISK_file_read(const struct GNUNET_DISK_FileHandle *h, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition disk.c:704
@ GNUNET_DISK_PF_BLOCKING_WRITE
Configure write end to block when writing if set.
@ GNUNET_DISK_PIPE_END_READ
The reading-end of a pipe.
struct GNUNET_CONTAINER_MultiShortmap * GNUNET_CONTAINER_multishortmap_create(unsigned int len, int do_not_copy_keys)
Create a multi peer map (hash map for public keys of peers).
void GNUNET_CONTAINER_multishortmap_destroy(struct GNUNET_CONTAINER_MultiShortmap *map)
Destroy a hash map.
unsigned int GNUNET_CONTAINER_multishortmap_size(const struct GNUNET_CONTAINER_MultiShortmap *map)
Get the number of key-value pairs in the map.
#define GNUNET_log(kind,...)
#define GNUNET_log_from(kind, comp,...)
GNUNET_GenericReturnValue
Named constants for return values.
#define GNUNET_MIN(a, b)
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
void GNUNET_log_config_missing(enum GNUNET_ErrorType kind, const char *section, const char *option)
Log error message about missing configuration option.
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
int GNUNET_snprintf(char *buf, size_t size, const char *format,...) __attribute__((format(printf
Like snprintf, just aborts if the buffer is of insufficient size.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
enum GNUNET_GenericReturnValue GNUNET_process_run_command_va(struct GNUNET_Process *p, const char *filename,...)
Set the command and start a process.
Definition os_process.c:906
enum GNUNET_GenericReturnValue GNUNET_process_wait(struct GNUNET_Process *proc, bool blocking, enum GNUNET_OS_ProcessStatusType *type, unsigned long *code)
Wait for a process to terminate.
void GNUNET_process_destroy(struct GNUNET_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition os_process.c:363
#define GNUNET_process_set_options(proc,...)
Set the requested options for the process.
GNUNET_OS_ProcessStatusType
Process status types.
#define GNUNET_process_option_inherit_wpipe(wpipe, child_fd)
Have child process inherit a pipe for writing.
enum GNUNET_GenericReturnValue GNUNET_process_kill(struct GNUNET_Process *proc, int sig)
Sends a signal to the process.
Definition os_process.c:307
struct GNUNET_Process * GNUNET_process_create(enum GNUNET_OS_InheritStdioFlags std_inheritance)
Create a process handle.
Definition os_process.c:465
@ GNUNET_OS_INHERIT_STD_NONE
No standard streams should be inherited.
@ GNUNET_OS_PROCESS_SIGNALED
The process was killed by a signal.
@ GNUNET_OS_PROCESS_EXITED
The process exited with a return code.
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:986
static unsigned int size
Size of the "table".
Definition peer.c:68
shared internal data structures of libgnunetpq
void GNUNET_PQ_event_reconnect_(struct GNUNET_PQ_Context *db, int fd)
Internal API.
Definition pq_event.c:446
static enum GNUNET_GenericReturnValue check_patch_applied(struct GNUNET_PQ_Context *db, const char *load_path, unsigned int patch_number)
Check if the patch with patch_number from the given load_path was already applied on the db.
Definition pq_connect.c:192
#define PSQL_OUTPUT_LINES
Maximum number of retained stderr lines emitted on failure.
Definition pq_connect.c:36
static char * get_sql_file_name(const struct GNUNET_PQ_Context *db, const char *infix)
Construct the name of the SQL file with the given filename infix in the load path of db.
Definition pq_connect.c:313
static enum GNUNET_GenericReturnValue prepare_check_patch(struct GNUNET_PQ_Context *db)
Prepare the "gnunet_pq_check_patch" statement.
Definition pq_connect.c:64
enum GNUNET_GenericReturnValue GNUNET_PQ_check_current(struct GNUNET_PQ_Context *db, const char *load_suffix)
Check if the database is current with respect to database migrations using prefix.
Definition pq_connect.c:677
static bool find_next_patch(const struct GNUNET_PQ_Context *db, const char *load_suffix, unsigned int from, unsigned int *found)
Find the lowest patch number of at least from for which an SQL file exists in the load path of db.
Definition pq_connect.c:376
static void pq_notice_receiver_cb(void *arg, const PGresult *res)
Function called by libpq whenever it wants to log something.
Definition pq_connect.c:273
static void reset_connection(struct GNUNET_PQ_Context *db)
Close connection to db and mark it as uninitialized.
Definition pq_connect.c:45
static enum GNUNET_GenericReturnValue prepare_get_oid_by_name(struct GNUNET_PQ_Context *db)
Prepare the "gnunet_pq_get_oid_by_name" statement.
Definition pq_connect.c:104
void GNUNET_PQ_reconnect_if_down(struct GNUNET_PQ_Context *db)
Reinitialize the database db if the connection is down.
Definition pq_connect.c:776
void GNUNET_PQ_disconnect(struct GNUNET_PQ_Context *db)
Disconnect from the database, destroying the prepared statements and releasing other associated resou...
struct GNUNET_PQ_Context * GNUNET_PQ_init(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, GNUNET_PQ_ReconnectCallback rc, GNUNET_PQ_RECONNECT_CALLBACK_CLOSURE *rc_cls)
Definition pq_connect.c:968
static enum GNUNET_GenericReturnValue check_versioning_ok(struct GNUNET_PQ_Context *db)
Check if the "_v" versioning schema exists (and cache the result in db).
Definition pq_connect.c:143
static void log_psql_output(char *output, size_t size, bool truncated)
Log the last lines of captured psql stderr through the component logger.
Definition pq_connect.c:403
#define PSQL_OUTPUT_BYTES
Maximum stderr tail retained from one psql invocation.
Definition pq_connect.c:33
void GNUNET_PQ_reconnect_(struct GNUNET_PQ_Context *db)
Reinitialize the database db.
Definition pq_connect.c:889
enum GNUNET_GenericReturnValue GNUNET_PQ_load_versioning(struct GNUNET_PQ_Context *db)
Setup database versioning.
Definition pq_connect.c:939
static void pq_notice_processor_cb(void *arg, const char *message)
Function called by libpq whenever it wants to log something.
Definition pq_connect.c:290
enum GNUNET_GenericReturnValue GNUNET_PQ_get_oid_by_name(struct GNUNET_PQ_Context *db, const char *name, Oid *oid)
Returns the oid for a given datatype by name.
Definition pq_connect.c:788
enum GNUNET_GenericReturnValue GNUNET_PQ_exec_sql(struct GNUNET_PQ_Context *db, const char *buf)
Execute SQL statements from buf against db.
Definition pq_connect.c:449
static enum GNUNET_GenericReturnValue patch_file_exists(const struct GNUNET_PQ_Context *db, const char *load_suffix, unsigned int patch_number)
Check if the SQL file for the patch with the given patch_number exists in the load path of db.
Definition pq_connect.c:339
static enum GNUNET_GenericReturnValue load_initial_oids(struct GNUNET_PQ_Context *db)
Load the initial set of OIDs for the supported array-datatypes.
Definition pq_connect.c:858
enum GNUNET_GenericReturnValue GNUNET_PQ_run_sql(struct GNUNET_PQ_Context *db, const char *load_suffix)
Within the db context, run all the SQL files in the load path where the name starts with the load_suf...
Definition pq_connect.c:713
Handle used to access files (and pipes).
Handle used to manage a pipe.
Definition disk.c:69
Handle to Postgres database.
Definition pq.h:36
GNUNET_PQ_ReconnectCallback rc
Function to call whenever we needed to reconnect conn.
Definition pq.h:45
char * load_path
Path to load SQL files from.
Definition pq.h:60
GNUNET_PQ_RECONNECT_CALLBACK_CLOSURE * rc_cls
Closure for rc.
Definition pq.h:50
Description of a DB query parameter.
Description of a DB result cell.