1 /*-------------------------------------------------------------------------
2 *
3 * pg_backup_utils.c
4 * Utility routines shared by pg_dump and pg_restore
5 *
6 *
7 * Portions Copyright (c) 1996-2016, 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 */
20 const char *progname = NULL;
21
22 #define MAX_ON_EXIT_NICELY 20
23
24 static struct
25 {
26 on_exit_nicely_callback function;
27 void *arg;
28 } on_exit_nicely_list[MAX_ON_EXIT_NICELY];
29
30 static 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 */
39 void
set_dump_section(const char * arg,int * dumpSections)40 set_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 fprintf(stderr, _("%s: unrecognized section name: \"%s\"\n"),
55 progname, arg);
56 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
57 progname);
58 exit_nicely(1);
59 }
60 }
61
62
63 /*
64 * Write a printf-style message to stderr.
65 *
66 * The program name is prepended, if "progname" has been set.
67 * Also, if modulename isn't NULL, that's included too.
68 * Note that we'll try to translate the modulename and the fmt string.
69 */
70 void
write_msg(const char * modulename,const char * fmt,...)71 write_msg(const char *modulename, const char *fmt,...)
72 {
73 va_list ap;
74
75 va_start(ap, fmt);
76 vwrite_msg(modulename, fmt, ap);
77 va_end(ap);
78 }
79
80 /*
81 * As write_msg, but pass a va_list not variable arguments.
82 */
83 void
vwrite_msg(const char * modulename,const char * fmt,va_list ap)84 vwrite_msg(const char *modulename, const char *fmt, va_list ap)
85 {
86 if (progname)
87 {
88 if (modulename)
89 fprintf(stderr, "%s: [%s] ", progname, _(modulename));
90 else
91 fprintf(stderr, "%s: ", progname);
92 }
93 vfprintf(stderr, _(fmt), ap);
94 }
95
96 /*
97 * Fail and die, with a message to stderr. Parameters as for write_msg.
98 *
99 * Note that on_exit_nicely callbacks will get run.
100 */
101 void
exit_horribly(const char * modulename,const char * fmt,...)102 exit_horribly(const char *modulename, const char *fmt,...)
103 {
104 va_list ap;
105
106 va_start(ap, fmt);
107 vwrite_msg(modulename, fmt, ap);
108 va_end(ap);
109
110 exit_nicely(1);
111 }
112
113 /* Register a callback to be run when exit_nicely is invoked. */
114 void
on_exit_nicely(on_exit_nicely_callback function,void * arg)115 on_exit_nicely(on_exit_nicely_callback function, void *arg)
116 {
117 if (on_exit_nicely_index >= MAX_ON_EXIT_NICELY)
118 exit_horribly(NULL, "out of on_exit_nicely slots\n");
119 on_exit_nicely_list[on_exit_nicely_index].function = function;
120 on_exit_nicely_list[on_exit_nicely_index].arg = arg;
121 on_exit_nicely_index++;
122 }
123
124 /*
125 * Run accumulated on_exit_nicely callbacks in reverse order and then exit
126 * without printing any message.
127 *
128 * If running in a parallel worker thread on Windows, we only exit the thread,
129 * not the whole process.
130 *
131 * Note that in parallel operation on Windows, the callback(s) will be run
132 * by each thread since the list state is necessarily shared by all threads;
133 * each callback must contain logic to ensure it does only what's appropriate
134 * for its thread. On Unix, callbacks are also run by each process, but only
135 * for callbacks established before we fork off the child processes. (It'd
136 * be cleaner to reset the list after fork(), and let each child establish
137 * its own callbacks; but then the behavior would be completely inconsistent
138 * between Windows and Unix. For now, just be sure to establish callbacks
139 * before forking to avoid inconsistency.)
140 */
141 void
exit_nicely(int code)142 exit_nicely(int code)
143 {
144 int i;
145
146 for (i = on_exit_nicely_index - 1; i >= 0; i--)
147 (*on_exit_nicely_list[i].function) (code,
148 on_exit_nicely_list[i].arg);
149
150 #ifdef WIN32
151 if (parallel_init_done && GetCurrentThreadId() != mainThreadId)
152 _endthreadex(code);
153 #endif
154
155 exit(code);
156 }
157