1/*-------------------------------------------------------------------------
2 *
3 * pg_backup_utils.c
4 * Utility routines shared by pg_dump and pg_restore
5 *
6 *
7 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
9 *
10 * src/bin/pg_dump/pg_backup_utils.c
11 *
12 *-------------------------------------------------------------------------
13 */
14#include "postgres_fe.h"
15
16#include "parallel.h"
17#include "pg_backup_utils.h"
18
19/* Globals exported by this file */
20const char *progname = NULL;
21
22#define MAX_ON_EXIT_NICELY 20
23
24static struct
25{
26 on_exit_nicely_callback function;
27 void *arg;
28} on_exit_nicely_list[MAX_ON_EXIT_NICELY];
29
30static int on_exit_nicely_index;
31
32/*
33 * Parse a --section=foo command line argument.
34 *
35 * Set or update the bitmask in *dumpSections according to arg.
36 * dumpSections is initialised as DUMP_UNSECTIONED by pg_dump and
37 * pg_restore so they can know if this has even been called.
38 */
39void
40set_dump_section(const char *arg, int *dumpSections)
41{
42 /* if this is the first call, clear all the bits */
43 if (*dumpSections == DUMP_UNSECTIONED)
44 *dumpSections = 0;
45
46 if (strcmp(arg, "pre-data") == 0)
47 *dumpSections |= DUMP_PRE_DATA;
48 else if (strcmp(arg, "data") == 0)
49 *dumpSections |= DUMP_DATA;
50 else if (strcmp(arg, "post-data") == 0)
51 *dumpSections |= DUMP_POST_DATA;
52 else
53 {
54 pg_log_error("unrecognized section name: \"%s\"", arg);
55 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
56 progname);
57 exit_nicely(1);
58 }
59}
60
61
62/* Register a callback to be run when exit_nicely is invoked. */
63void
64on_exit_nicely(on_exit_nicely_callback function, void *arg)
65{
66 if (on_exit_nicely_index >= MAX_ON_EXIT_NICELY)
67 {
68 pg_log_fatal("out of on_exit_nicely slots");
69 exit_nicely(1);
70 }
71 on_exit_nicely_list[on_exit_nicely_index].function = function;
72 on_exit_nicely_list[on_exit_nicely_index].arg = arg;
73 on_exit_nicely_index++;
74}
75
76/*
77 * Run accumulated on_exit_nicely callbacks in reverse order and then exit
78 * without printing any message.
79 *
80 * If running in a parallel worker thread on Windows, we only exit the thread,
81 * not the whole process.
82 *
83 * Note that in parallel operation on Windows, the callback(s) will be run
84 * by each thread since the list state is necessarily shared by all threads;
85 * each callback must contain logic to ensure it does only what's appropriate
86 * for its thread. On Unix, callbacks are also run by each process, but only
87 * for callbacks established before we fork off the child processes. (It'd
88 * be cleaner to reset the list after fork(), and let each child establish
89 * its own callbacks; but then the behavior would be completely inconsistent
90 * between Windows and Unix. For now, just be sure to establish callbacks
91 * before forking to avoid inconsistency.)
92 */
93void
94exit_nicely(int code)
95{
96 int i;
97
98 for (i = on_exit_nicely_index - 1; i >= 0; i--)
99 on_exit_nicely_list[i].function(code,
100 on_exit_nicely_list[i].arg);
101
102#ifdef WIN32
103 if (parallel_init_done && GetCurrentThreadId() != mainThreadId)
104 _endthreadex(code);
105#endif
106
107 exit(code);
108}
109