Force a checkpoint in CREATE DATABASE before starting to copy the files,
[PostgreSQL.git] / src / bin / pg_dump / pg_dumpall.c
blobb00fb5ae95bd5239e8302699c084636c8879f3b7
1 /*-------------------------------------------------------------------------
3 * pg_dumpall.c
5 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
9 * $PostgreSQL$
11 *-------------------------------------------------------------------------
14 #include "postgres_fe.h"
16 #include <time.h>
17 #include <unistd.h>
19 #ifdef ENABLE_NLS
20 #include <locale.h>
21 #endif
23 #include "getopt_long.h"
25 #ifndef HAVE_INT_OPTRESET
26 int optreset;
27 #endif
29 #include "dumputils.h"
32 /* version string we expect back from pg_dump */
33 #define PGDUMP_VERSIONSTR "pg_dump (PostgreSQL) " PG_VERSION "\n"
36 static const char *progname;
38 static void help(void);
40 static void dumpRoles(PGconn *conn);
41 static void dumpRoleMembership(PGconn *conn);
42 static void dumpGroups(PGconn *conn);
43 static void dumpTablespaces(PGconn *conn);
44 static void dumpCreateDB(PGconn *conn);
45 static void dumpDatabaseConfig(PGconn *conn, const char *dbname);
46 static void dumpUserConfig(PGconn *conn, const char *username);
47 static void makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
48 const char *type, const char *name);
49 static void dumpDatabases(PGconn *conn);
50 static void dumpTimestamp(char *msg);
52 static int runPgDump(const char *dbname);
53 static PGconn *connectDatabase(const char *dbname, const char *pghost, const char *pgport,
54 const char *pguser, bool require_password, bool fail_on_error);
55 static PGresult *executeQuery(PGconn *conn, const char *query);
56 static void executeCommand(PGconn *conn, const char *query);
58 static char pg_dump_bin[MAXPGPATH];
59 static PQExpBuffer pgdumpopts;
60 static bool output_clean = false;
61 static bool skip_acls = false;
62 static bool verbose = false;
64 static int disable_dollar_quoting = 0;
65 static int disable_triggers = 0;
66 static int no_tablespaces = 0;
67 static int use_setsessauth = 0;
68 static int server_version;
70 static FILE *OPF;
71 static char *filename = NULL;
73 int
74 main(int argc, char *argv[])
76 char *pghost = NULL;
77 char *pgport = NULL;
78 char *pguser = NULL;
79 char *pgdb = NULL;
80 bool force_password = false;
81 bool data_only = false;
82 bool globals_only = false;
83 bool roles_only = false;
84 bool tablespaces_only = false;
85 bool schema_only = false;
86 PGconn *conn;
87 int encoding;
88 const char *std_strings;
89 int c,
90 ret;
92 static struct option long_options[] = {
93 {"data-only", no_argument, NULL, 'a'},
94 {"clean", no_argument, NULL, 'c'},
95 {"inserts", no_argument, NULL, 'd'},
96 {"attribute-inserts", no_argument, NULL, 'D'},
97 {"column-inserts", no_argument, NULL, 'D'},
98 {"file", required_argument, NULL, 'f'},
99 {"globals-only", no_argument, NULL, 'g'},
100 {"host", required_argument, NULL, 'h'},
101 {"ignore-version", no_argument, NULL, 'i'},
102 {"database", required_argument, NULL, 'l'},
103 {"oids", no_argument, NULL, 'o'},
104 {"no-owner", no_argument, NULL, 'O'},
105 {"port", required_argument, NULL, 'p'},
106 {"roles-only", no_argument, NULL, 'r'},
107 {"schema-only", no_argument, NULL, 's'},
108 {"superuser", required_argument, NULL, 'S'},
109 {"tablespaces-only", no_argument, NULL, 't'},
110 {"username", required_argument, NULL, 'U'},
111 {"verbose", no_argument, NULL, 'v'},
112 {"password", no_argument, NULL, 'W'},
113 {"no-privileges", no_argument, NULL, 'x'},
114 {"no-acl", no_argument, NULL, 'x'},
117 * the following options don't have an equivalent short option letter
119 {"disable-dollar-quoting", no_argument, &disable_dollar_quoting, 1},
120 {"disable-triggers", no_argument, &disable_triggers, 1},
121 {"no-tablespaces", no_argument, &no_tablespaces, 1},
122 {"use-set-session-authorization", no_argument, &use_setsessauth, 1},
123 {"lock-wait-timeout", required_argument, NULL, 2},
125 {NULL, 0, NULL, 0}
128 int optindex;
130 set_pglocale_pgservice(argv[0], "pg_dump");
132 progname = get_progname(argv[0]);
134 if (argc > 1)
136 if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
138 help();
139 exit(0);
141 if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
143 puts("pg_dumpall (PostgreSQL) " PG_VERSION);
144 exit(0);
148 if ((ret = find_other_exec(argv[0], "pg_dump", PGDUMP_VERSIONSTR,
149 pg_dump_bin)) < 0)
151 char full_path[MAXPGPATH];
153 if (find_my_exec(argv[0], full_path) < 0)
154 strlcpy(full_path, progname, sizeof(full_path));
156 if (ret == -1)
157 fprintf(stderr,
158 _("The program \"pg_dump\" is needed by %s "
159 "but was not found in the\n"
160 "same directory as \"%s\".\n"
161 "Check your installation.\n"),
162 progname, full_path);
163 else
164 fprintf(stderr,
165 _("The program \"pg_dump\" was found by \"%s\"\n"
166 "but was not the same version as %s.\n"
167 "Check your installation.\n"),
168 full_path, progname);
169 exit(1);
172 pgdumpopts = createPQExpBuffer();
174 while ((c = getopt_long(argc, argv, "acdDf:gh:il:oOp:rsS:tU:vWxX:", long_options, &optindex)) != -1)
176 switch (c)
178 case 'a':
179 data_only = true;
180 appendPQExpBuffer(pgdumpopts, " -a");
181 break;
183 case 'c':
184 output_clean = true;
185 break;
187 case 'd':
188 case 'D':
189 appendPQExpBuffer(pgdumpopts, " -%c", c);
190 break;
192 case 'f':
193 filename = optarg;
194 #ifndef WIN32
195 appendPQExpBuffer(pgdumpopts, " -f '%s'", filename);
196 #else
197 appendPQExpBuffer(pgdumpopts, " -f \"%s\"", filename);
198 #endif
200 break;
202 case 'g':
203 globals_only = true;
204 break;
206 case 'h':
207 pghost = optarg;
208 #ifndef WIN32
209 appendPQExpBuffer(pgdumpopts, " -h '%s'", pghost);
210 #else
211 appendPQExpBuffer(pgdumpopts, " -h \"%s\"", pghost);
212 #endif
214 break;
216 case 'i':
217 /* ignored, deprecated option */
218 break;
220 case 'l':
221 pgdb = optarg;
222 break;
224 case 'o':
225 appendPQExpBuffer(pgdumpopts, " -o");
226 break;
228 case 'O':
229 appendPQExpBuffer(pgdumpopts, " -O");
230 break;
232 case 'p':
233 pgport = optarg;
234 #ifndef WIN32
235 appendPQExpBuffer(pgdumpopts, " -p '%s'", pgport);
236 #else
237 appendPQExpBuffer(pgdumpopts, " -p \"%s\"", pgport);
238 #endif
239 break;
241 case 'r':
242 roles_only = true;
243 break;
245 case 's':
246 schema_only = true;
247 appendPQExpBuffer(pgdumpopts, " -s");
248 break;
250 case 'S':
251 #ifndef WIN32
252 appendPQExpBuffer(pgdumpopts, " -S '%s'", optarg);
253 #else
254 appendPQExpBuffer(pgdumpopts, " -S \"%s\"", optarg);
255 #endif
256 break;
258 case 't':
259 tablespaces_only = true;
260 break;
262 case 'U':
263 pguser = optarg;
264 #ifndef WIN32
265 appendPQExpBuffer(pgdumpopts, " -U '%s'", pguser);
266 #else
267 appendPQExpBuffer(pgdumpopts, " -U \"%s\"", pguser);
268 #endif
269 break;
271 case 'v':
272 verbose = true;
273 appendPQExpBuffer(pgdumpopts, " -v");
274 break;
276 case 'W':
277 force_password = true;
278 appendPQExpBuffer(pgdumpopts, " -W");
279 break;
281 case 'x':
282 skip_acls = true;
283 appendPQExpBuffer(pgdumpopts, " -x");
284 break;
286 case 'X':
287 /* -X is a deprecated alternative to long options */
288 if (strcmp(optarg, "disable-dollar-quoting") == 0)
289 disable_dollar_quoting = 1;
290 else if (strcmp(optarg, "disable-triggers") == 0)
291 disable_triggers = 1;
292 else if (strcmp(optarg, "no-tablespaces") == 0)
293 no_tablespaces = 1;
294 else if (strcmp(optarg, "use-set-session-authorization") == 0)
295 use_setsessauth = 1;
296 else
298 fprintf(stderr,
299 _("%s: invalid -X option -- %s\n"),
300 progname, optarg);
301 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
302 exit(1);
304 break;
306 case 0:
307 break;
309 case 2:
310 appendPQExpBuffer(pgdumpopts, " --lock-wait-timeout=");
311 appendPQExpBuffer(pgdumpopts, optarg);
312 break;
314 default:
315 fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
316 exit(1);
320 /* Add long options to the pg_dump argument list */
321 if (disable_dollar_quoting)
322 appendPQExpBuffer(pgdumpopts, " --disable-dollar-quoting");
323 if (disable_triggers)
324 appendPQExpBuffer(pgdumpopts, " --disable-triggers");
325 if (no_tablespaces)
326 appendPQExpBuffer(pgdumpopts, " --no-tablespaces");
327 if (use_setsessauth)
328 appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization");
330 if (optind < argc)
332 fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
333 progname, argv[optind]);
334 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
335 progname);
336 exit(1);
339 /* Make sure the user hasn't specified a mix of globals-only options */
340 if (globals_only && roles_only)
342 fprintf(stderr, _("%s: options -g/--globals-only and -r/--roles-only cannot be used together\n"),
343 progname);
344 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
345 progname);
346 exit(1);
349 if (globals_only && tablespaces_only)
351 fprintf(stderr, _("%s: options -g/--globals-only and -t/--tablespaces-only cannot be used together\n"),
352 progname);
353 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
354 progname);
355 exit(1);
358 if (roles_only && tablespaces_only)
360 fprintf(stderr, _("%s: options -r/--roles-only and -t/--tablespaces-only cannot be used together\n"),
361 progname);
362 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
363 progname);
364 exit(1);
368 * If there was a database specified on the command line, use that,
369 * otherwise try to connect to database "postgres", and failing that
370 * "template1". "postgres" is the preferred choice for 8.1 and later
371 * servers, but it usually will not exist on older ones.
373 if (pgdb)
375 conn = connectDatabase(pgdb, pghost, pgport, pguser,
376 force_password, false);
378 if (!conn)
380 fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
381 progname, pgdb);
382 exit(1);
385 else
387 conn = connectDatabase("postgres", pghost, pgport, pguser,
388 force_password, false);
389 if (!conn)
390 conn = connectDatabase("template1", pghost, pgport, pguser,
391 force_password, true);
393 if (!conn)
395 fprintf(stderr, _("%s: could not connect to databases \"postgres\" or \"template1\"\n"
396 "Please specify an alternative database.\n"),
397 progname);
398 fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
399 progname);
400 exit(1);
405 * Open the output file if required, otherwise use stdout
407 if (filename)
409 OPF = fopen(filename, PG_BINARY_W);
410 if (!OPF)
412 fprintf(stderr, _("%s: could not open the output file \"%s\": %s\n"),
413 progname, filename, strerror(errno));
414 exit(1);
417 else
418 OPF = stdout;
421 * Get the active encoding and the standard_conforming_strings setting, so
422 * we know how to escape strings.
424 encoding = PQclientEncoding(conn);
425 std_strings = PQparameterStatus(conn, "standard_conforming_strings");
426 if (!std_strings)
427 std_strings = "off";
429 fprintf(OPF, "--\n-- PostgreSQL database cluster dump\n--\n\n");
430 if (verbose)
431 dumpTimestamp("Started on");
433 fprintf(OPF, "\\connect postgres\n\n");
435 if (!data_only)
437 /* Replicate encoding and std_strings in output */
438 fprintf(OPF, "SET client_encoding = '%s';\n",
439 pg_encoding_to_char(encoding));
440 fprintf(OPF, "SET standard_conforming_strings = %s;\n", std_strings);
441 if (strcmp(std_strings, "off") == 0)
442 fprintf(OPF, "SET escape_string_warning = 'off';\n");
443 fprintf(OPF, "\n");
445 if (!tablespaces_only)
447 /* Dump roles (users) */
448 dumpRoles(conn);
450 /* Dump role memberships --- need different method for pre-8.1 */
451 if (server_version >= 80100)
452 dumpRoleMembership(conn);
453 else
454 dumpGroups(conn);
457 if (!roles_only && !no_tablespaces)
459 /* Dump tablespaces */
460 if (server_version >= 80000)
461 dumpTablespaces(conn);
464 /* Dump CREATE DATABASE commands */
465 if (!globals_only && !roles_only && !tablespaces_only)
466 dumpCreateDB(conn);
469 if (!globals_only && !roles_only && !tablespaces_only)
470 dumpDatabases(conn);
472 PQfinish(conn);
474 if (verbose)
475 dumpTimestamp("Completed on");
476 fprintf(OPF, "--\n-- PostgreSQL database cluster dump complete\n--\n\n");
478 if (filename)
479 fclose(OPF);
481 exit(0);
486 static void
487 help(void)
489 printf(_("%s extracts a PostgreSQL database cluster into an SQL script file.\n\n"), progname);
490 printf(_("Usage:\n"));
491 printf(_(" %s [OPTION]...\n"), progname);
493 printf(_("\nGeneral options:\n"));
494 printf(_(" -f, --file=FILENAME output file name\n"));
495 printf(_(" --help show this help, then exit\n"));
496 printf(_(" --version output version information, then exit\n"));
497 printf(_(" --lock-wait-timeout=TIMEOUT\n"
498 " fail after waiting TIMEOUT for a table lock\n"));
499 printf(_("\nOptions controlling the output content:\n"));
500 printf(_(" -a, --data-only dump only the data, not the schema\n"));
501 printf(_(" -c, --clean clean (drop) databases prior to create\n"));
502 printf(_(" -d, --inserts dump data as INSERT, rather than COPY, commands\n"));
503 printf(_(" -D, --column-inserts dump data as INSERT commands with column names\n"));
504 printf(_(" -g, --globals-only dump only global objects, no databases\n"));
505 printf(_(" -o, --oids include OIDs in dump\n"));
506 printf(_(" -O, --no-owner skip restoration of object ownership\n"));
507 printf(_(" -r, --roles-only dump only roles, no databases or tablespaces\n"));
508 printf(_(" -s, --schema-only dump only the schema, no data\n"));
509 printf(_(" -S, --superuser=NAME specify the superuser user name to use in the dump\n"));
510 printf(_(" -t, --tablespaces-only dump only tablespaces, no databases or roles\n"));
511 printf(_(" -x, --no-privileges do not dump privileges (grant/revoke)\n"));
512 printf(_(" --disable-dollar-quoting\n"
513 " disable dollar quoting, use SQL standard quoting\n"));
514 printf(_(" --disable-triggers disable triggers during data-only restore\n"));
515 printf(_(" --no-tablespaces do not dump tablespace assignments\n"));
516 printf(_(" --use-set-session-authorization\n"
517 " use SESSION AUTHORIZATION commands instead of\n"
518 " OWNER TO commands\n"));
520 printf(_("\nConnection options:\n"));
521 printf(_(" -h, --host=HOSTNAME database server host or socket directory\n"));
522 printf(_(" -l, --database=DBNAME specify an alternative default database\n"));
523 printf(_(" -p, --port=PORT database server port number\n"));
524 printf(_(" -U, --username=NAME connect as specified database user\n"));
525 printf(_(" -W, --password force password prompt (should happen automatically)\n"));
527 printf(_("\nThe SQL script will be written to the standard output.\n\n"));
528 printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
534 * Dump roles
536 static void
537 dumpRoles(PGconn *conn)
539 PQExpBuffer buf = createPQExpBuffer();
540 PGresult *res;
541 int i_rolname,
542 i_rolsuper,
543 i_rolinherit,
544 i_rolcreaterole,
545 i_rolcreatedb,
546 i_rolcatupdate,
547 i_rolcanlogin,
548 i_rolconnlimit,
549 i_rolpassword,
550 i_rolvaliduntil,
551 i_rolcomment;
552 int i;
554 /* note: rolconfig is dumped later */
555 if (server_version >= 80200)
556 printfPQExpBuffer(buf,
557 "SELECT rolname, rolsuper, rolinherit, "
558 "rolcreaterole, rolcreatedb, rolcatupdate, "
559 "rolcanlogin, rolconnlimit, rolpassword, "
560 "rolvaliduntil, "
561 "pg_catalog.shobj_description(oid, 'pg_authid') as rolcomment "
562 "FROM pg_authid "
563 "ORDER BY 1");
564 else if (server_version >= 80100)
565 printfPQExpBuffer(buf,
566 "SELECT rolname, rolsuper, rolinherit, "
567 "rolcreaterole, rolcreatedb, rolcatupdate, "
568 "rolcanlogin, rolconnlimit, rolpassword, "
569 "rolvaliduntil, null as rolcomment "
570 "FROM pg_authid "
571 "ORDER BY 1");
572 else
573 printfPQExpBuffer(buf,
574 "SELECT usename as rolname, "
575 "usesuper as rolsuper, "
576 "true as rolinherit, "
577 "usesuper as rolcreaterole, "
578 "usecreatedb as rolcreatedb, "
579 "usecatupd as rolcatupdate, "
580 "true as rolcanlogin, "
581 "-1 as rolconnlimit, "
582 "passwd as rolpassword, "
583 "valuntil as rolvaliduntil, "
584 "null as rolcomment "
585 "FROM pg_shadow "
586 "UNION ALL "
587 "SELECT groname as rolname, "
588 "false as rolsuper, "
589 "true as rolinherit, "
590 "false as rolcreaterole, "
591 "false as rolcreatedb, "
592 "false as rolcatupdate, "
593 "false as rolcanlogin, "
594 "-1 as rolconnlimit, "
595 "null::text as rolpassword, "
596 "null::abstime as rolvaliduntil, "
597 "null as rolcomment "
598 "FROM pg_group "
599 "WHERE NOT EXISTS (SELECT 1 FROM pg_shadow "
600 " WHERE usename = groname) "
601 "ORDER BY 1");
603 res = executeQuery(conn, buf->data);
605 i_rolname = PQfnumber(res, "rolname");
606 i_rolsuper = PQfnumber(res, "rolsuper");
607 i_rolinherit = PQfnumber(res, "rolinherit");
608 i_rolcreaterole = PQfnumber(res, "rolcreaterole");
609 i_rolcreatedb = PQfnumber(res, "rolcreatedb");
610 i_rolcatupdate = PQfnumber(res, "rolcatupdate");
611 i_rolcanlogin = PQfnumber(res, "rolcanlogin");
612 i_rolconnlimit = PQfnumber(res, "rolconnlimit");
613 i_rolpassword = PQfnumber(res, "rolpassword");
614 i_rolvaliduntil = PQfnumber(res, "rolvaliduntil");
615 i_rolcomment = PQfnumber(res, "rolcomment");
617 if (PQntuples(res) > 0)
618 fprintf(OPF, "--\n-- Roles\n--\n\n");
620 for (i = 0; i < PQntuples(res); i++)
622 const char *rolename;
624 rolename = PQgetvalue(res, i, i_rolname);
626 resetPQExpBuffer(buf);
628 if (output_clean)
629 appendPQExpBuffer(buf, "DROP ROLE %s;\n", fmtId(rolename));
632 * We dump CREATE ROLE followed by ALTER ROLE to ensure that the role
633 * will acquire the right properties even if it already exists. (The
634 * above DROP may therefore seem redundant, but it isn't really,
635 * because this technique doesn't get rid of role memberships.)
637 appendPQExpBuffer(buf, "CREATE ROLE %s;\n", fmtId(rolename));
638 appendPQExpBuffer(buf, "ALTER ROLE %s WITH", fmtId(rolename));
640 if (strcmp(PQgetvalue(res, i, i_rolsuper), "t") == 0)
641 appendPQExpBuffer(buf, " SUPERUSER");
642 else
643 appendPQExpBuffer(buf, " NOSUPERUSER");
645 if (strcmp(PQgetvalue(res, i, i_rolinherit), "t") == 0)
646 appendPQExpBuffer(buf, " INHERIT");
647 else
648 appendPQExpBuffer(buf, " NOINHERIT");
650 if (strcmp(PQgetvalue(res, i, i_rolcreaterole), "t") == 0)
651 appendPQExpBuffer(buf, " CREATEROLE");
652 else
653 appendPQExpBuffer(buf, " NOCREATEROLE");
655 if (strcmp(PQgetvalue(res, i, i_rolcreatedb), "t") == 0)
656 appendPQExpBuffer(buf, " CREATEDB");
657 else
658 appendPQExpBuffer(buf, " NOCREATEDB");
660 if (strcmp(PQgetvalue(res, i, i_rolcanlogin), "t") == 0)
661 appendPQExpBuffer(buf, " LOGIN");
662 else
663 appendPQExpBuffer(buf, " NOLOGIN");
665 if (strcmp(PQgetvalue(res, i, i_rolconnlimit), "-1") != 0)
666 appendPQExpBuffer(buf, " CONNECTION LIMIT %s",
667 PQgetvalue(res, i, i_rolconnlimit));
669 if (!PQgetisnull(res, i, i_rolpassword))
671 appendPQExpBuffer(buf, " PASSWORD ");
672 appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolpassword), conn);
675 if (!PQgetisnull(res, i, i_rolvaliduntil))
676 appendPQExpBuffer(buf, " VALID UNTIL '%s'",
677 PQgetvalue(res, i, i_rolvaliduntil));
679 appendPQExpBuffer(buf, ";\n");
681 if (!PQgetisnull(res, i, i_rolcomment))
683 appendPQExpBuffer(buf, "COMMENT ON ROLE %s IS ", fmtId(rolename));
684 appendStringLiteralConn(buf, PQgetvalue(res, i, i_rolcomment), conn);
685 appendPQExpBuffer(buf, ";\n");
688 fprintf(OPF, "%s", buf->data);
690 if (server_version >= 70300)
691 dumpUserConfig(conn, rolename);
694 PQclear(res);
696 fprintf(OPF, "\n\n");
698 destroyPQExpBuffer(buf);
703 * Dump role memberships. This code is used for 8.1 and later servers.
705 * Note: we expect dumpRoles already created all the roles, but there is
706 * no membership yet.
708 static void
709 dumpRoleMembership(PGconn *conn)
711 PGresult *res;
712 int i;
714 res = executeQuery(conn, "SELECT ur.rolname AS roleid, "
715 "um.rolname AS member, "
716 "a.admin_option, "
717 "ug.rolname AS grantor "
718 "FROM pg_auth_members a "
719 "LEFT JOIN pg_authid ur on ur.oid = a.roleid "
720 "LEFT JOIN pg_authid um on um.oid = a.member "
721 "LEFT JOIN pg_authid ug on ug.oid = a.grantor "
722 "ORDER BY 1,2,3");
724 if (PQntuples(res) > 0)
725 fprintf(OPF, "--\n-- Role memberships\n--\n\n");
727 for (i = 0; i < PQntuples(res); i++)
729 char *roleid = PQgetvalue(res, i, 0);
730 char *member = PQgetvalue(res, i, 1);
731 char *option = PQgetvalue(res, i, 2);
733 fprintf(OPF, "GRANT %s", fmtId(roleid));
734 fprintf(OPF, " TO %s", fmtId(member));
735 if (*option == 't')
736 fprintf(OPF, " WITH ADMIN OPTION");
739 * We don't track the grantor very carefully in the backend, so cope
740 * with the possibility that it has been dropped.
742 if (!PQgetisnull(res, i, 3))
744 char *grantor = PQgetvalue(res, i, 3);
746 fprintf(OPF, " GRANTED BY %s", fmtId(grantor));
748 fprintf(OPF, ";\n");
751 PQclear(res);
753 fprintf(OPF, "\n\n");
757 * Dump group memberships from a pre-8.1 server. It's annoying that we
758 * can't share any useful amount of code with the post-8.1 case, but
759 * the catalog representations are too different.
761 * Note: we expect dumpRoles already created all the roles, but there is
762 * no membership yet.
764 static void
765 dumpGroups(PGconn *conn)
767 PQExpBuffer buf = createPQExpBuffer();
768 PGresult *res;
769 int i;
771 res = executeQuery(conn,
772 "SELECT groname, grolist FROM pg_group ORDER BY 1");
774 if (PQntuples(res) > 0)
775 fprintf(OPF, "--\n-- Role memberships\n--\n\n");
777 for (i = 0; i < PQntuples(res); i++)
779 char *groname = PQgetvalue(res, i, 0);
780 char *grolist = PQgetvalue(res, i, 1);
781 PGresult *res2;
782 int j;
785 * Array representation is {1,2,3} ... convert to (1,2,3)
787 if (strlen(grolist) < 3)
788 continue;
790 grolist = strdup(grolist);
791 grolist[0] = '(';
792 grolist[strlen(grolist) - 1] = ')';
793 printfPQExpBuffer(buf,
794 "SELECT usename FROM pg_shadow "
795 "WHERE usesysid IN %s ORDER BY 1",
796 grolist);
797 free(grolist);
799 res2 = executeQuery(conn, buf->data);
801 for (j = 0; j < PQntuples(res2); j++)
803 char *usename = PQgetvalue(res2, j, 0);
806 * Don't try to grant a role to itself; can happen if old
807 * installation has identically named user and group.
809 if (strcmp(groname, usename) == 0)
810 continue;
812 fprintf(OPF, "GRANT %s", fmtId(groname));
813 fprintf(OPF, " TO %s;\n", fmtId(usename));
816 PQclear(res2);
819 PQclear(res);
820 destroyPQExpBuffer(buf);
822 fprintf(OPF, "\n\n");
826 * Dump tablespaces.
828 static void
829 dumpTablespaces(PGconn *conn)
831 PGresult *res;
832 int i;
835 * Get all tablespaces except built-in ones (which we assume are named
836 * pg_xxx)
838 if (server_version >= 80200)
839 res = executeQuery(conn, "SELECT spcname, "
840 "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
841 "spclocation, spcacl, "
842 "pg_catalog.shobj_description(oid, 'pg_tablespace') "
843 "FROM pg_catalog.pg_tablespace "
844 "WHERE spcname !~ '^pg_' "
845 "ORDER BY 1");
846 else
847 res = executeQuery(conn, "SELECT spcname, "
848 "pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
849 "spclocation, spcacl, "
850 "null "
851 "FROM pg_catalog.pg_tablespace "
852 "WHERE spcname !~ '^pg_' "
853 "ORDER BY 1");
855 if (PQntuples(res) > 0)
856 fprintf(OPF, "--\n-- Tablespaces\n--\n\n");
858 for (i = 0; i < PQntuples(res); i++)
860 PQExpBuffer buf = createPQExpBuffer();
861 char *spcname = PQgetvalue(res, i, 0);
862 char *spcowner = PQgetvalue(res, i, 1);
863 char *spclocation = PQgetvalue(res, i, 2);
864 char *spcacl = PQgetvalue(res, i, 3);
865 char *spccomment = PQgetvalue(res, i, 4);
866 char *fspcname;
868 /* needed for buildACLCommands() */
869 fspcname = strdup(fmtId(spcname));
871 if (output_clean)
872 appendPQExpBuffer(buf, "DROP TABLESPACE %s;\n", fspcname);
874 appendPQExpBuffer(buf, "CREATE TABLESPACE %s", fspcname);
875 appendPQExpBuffer(buf, " OWNER %s", fmtId(spcowner));
877 appendPQExpBuffer(buf, " LOCATION ");
878 appendStringLiteralConn(buf, spclocation, conn);
879 appendPQExpBuffer(buf, ";\n");
881 if (!skip_acls &&
882 !buildACLCommands(fspcname, "TABLESPACE", spcacl, spcowner,
883 server_version, buf))
885 fprintf(stderr, _("%s: could not parse ACL list (%s) for tablespace \"%s\"\n"),
886 progname, spcacl, fspcname);
887 PQfinish(conn);
888 exit(1);
891 if (spccomment && strlen(spccomment))
893 appendPQExpBuffer(buf, "COMMENT ON TABLESPACE %s IS ", fspcname);
894 appendStringLiteralConn(buf, spccomment, conn);
895 appendPQExpBuffer(buf, ";\n");
898 fprintf(OPF, "%s", buf->data);
900 free(fspcname);
901 destroyPQExpBuffer(buf);
904 PQclear(res);
905 fprintf(OPF, "\n\n");
909 * Dump commands to create each database.
911 * To minimize the number of reconnections (and possibly ensuing
912 * password prompts) required by the output script, we emit all CREATE
913 * DATABASE commands during the initial phase of the script, and then
914 * run pg_dump for each database to dump the contents of that
915 * database. We skip databases marked not datallowconn, since we'd be
916 * unable to connect to them anyway (and besides, we don't want to
917 * dump template0).
919 static void
920 dumpCreateDB(PGconn *conn)
922 PQExpBuffer buf = createPQExpBuffer();
923 PGresult *res;
924 int i;
926 fprintf(OPF, "--\n-- Database creation\n--\n\n");
928 if (server_version >= 80400)
929 res = executeQuery(conn,
930 "SELECT datname, "
931 "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
932 "pg_encoding_to_char(d.encoding), "
933 "datcollate, datctype, "
934 "datistemplate, datacl, datconnlimit, "
935 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
936 "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
937 "WHERE datallowconn ORDER BY 1");
938 else if (server_version >= 80100)
939 res = executeQuery(conn,
940 "SELECT datname, "
941 "coalesce(rolname, (select rolname from pg_authid where oid=(select datdba from pg_database where datname='template0'))), "
942 "pg_encoding_to_char(d.encoding), "
943 "null::text AS datcollate, null::text AS datctype, "
944 "datistemplate, datacl, datconnlimit, "
945 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
946 "FROM pg_database d LEFT JOIN pg_authid u ON (datdba = u.oid) "
947 "WHERE datallowconn ORDER BY 1");
948 else if (server_version >= 80000)
949 res = executeQuery(conn,
950 "SELECT datname, "
951 "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
952 "pg_encoding_to_char(d.encoding), "
953 "null::text AS datcollate, null::text AS datctype, "
954 "datistemplate, datacl, -1 as datconnlimit, "
955 "(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
956 "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
957 "WHERE datallowconn ORDER BY 1");
958 else if (server_version >= 70300)
959 res = executeQuery(conn,
960 "SELECT datname, "
961 "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
962 "pg_encoding_to_char(d.encoding), "
963 "null::text AS datcollate, null::text AS datctype, "
964 "datistemplate, datacl, -1 as datconnlimit, "
965 "'pg_default' AS dattablespace "
966 "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
967 "WHERE datallowconn ORDER BY 1");
968 else if (server_version >= 70100)
969 res = executeQuery(conn,
970 "SELECT datname, "
971 "coalesce("
972 "(select usename from pg_shadow where usesysid=datdba), "
973 "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
974 "pg_encoding_to_char(d.encoding), "
975 "null::text AS datcollate, null::text AS datctype, "
976 "datistemplate, '' as datacl, -1 as datconnlimit, "
977 "'pg_default' AS dattablespace "
978 "FROM pg_database d "
979 "WHERE datallowconn ORDER BY 1");
980 else
983 * Note: 7.0 fails to cope with sub-select in COALESCE, so just deal
984 * with getting a NULL by not printing any OWNER clause.
986 res = executeQuery(conn,
987 "SELECT datname, "
988 "(select usename from pg_shadow where usesysid=datdba), "
989 "pg_encoding_to_char(d.encoding), "
990 "null::text AS datcollate, null::text AS datctype, "
991 "'f' as datistemplate, "
992 "'' as datacl, -1 as datconnlimit, "
993 "'pg_default' AS dattablespace "
994 "FROM pg_database d "
995 "ORDER BY 1");
998 for (i = 0; i < PQntuples(res); i++)
1000 char *dbname = PQgetvalue(res, i, 0);
1001 char *dbowner = PQgetvalue(res, i, 1);
1002 char *dbencoding = PQgetvalue(res, i, 2);
1003 char *dbcollate = PQgetvalue(res, i, 3);
1004 char *dbctype = PQgetvalue(res, i, 4);
1005 char *dbistemplate = PQgetvalue(res, i, 5);
1006 char *dbacl = PQgetvalue(res, i, 6);
1007 char *dbconnlimit = PQgetvalue(res, i, 7);
1008 char *dbtablespace = PQgetvalue(res, i, 8);
1009 char *fdbname;
1011 fdbname = strdup(fmtId(dbname));
1013 resetPQExpBuffer(buf);
1016 * Skip the CREATE DATABASE commands for "template1" and "postgres",
1017 * since they are presumably already there in the destination cluster.
1018 * We do want to emit their ACLs and config options if any, however.
1020 if (strcmp(dbname, "template1") != 0 &&
1021 strcmp(dbname, "postgres") != 0)
1023 if (output_clean)
1024 appendPQExpBuffer(buf, "DROP DATABASE %s;\n", fdbname);
1026 appendPQExpBuffer(buf, "CREATE DATABASE %s", fdbname);
1028 appendPQExpBuffer(buf, " WITH TEMPLATE = template0");
1030 if (strlen(dbowner) != 0)
1031 appendPQExpBuffer(buf, " OWNER = %s", fmtId(dbowner));
1033 appendPQExpBuffer(buf, " ENCODING = ");
1034 appendStringLiteralConn(buf, dbencoding, conn);
1036 if (strlen(dbcollate) != 0)
1038 appendPQExpBuffer(buf, " COLLATE = ");
1039 appendStringLiteralConn(buf, dbcollate, conn);
1042 if (strlen(dbctype) != 0)
1044 appendPQExpBuffer(buf, " CTYPE = ");
1045 appendStringLiteralConn(buf, dbctype, conn);
1049 * Output tablespace if it isn't the default. For default, it
1050 * uses the default from the template database. If tablespace is
1051 * specified and tablespace creation failed earlier, (e.g. no such
1052 * directory), the database creation will fail too. One solution
1053 * would be to use 'SET default_tablespace' like we do in pg_dump
1054 * for setting non-default database locations.
1056 if (strcmp(dbtablespace, "pg_default") != 0 && !no_tablespaces)
1057 appendPQExpBuffer(buf, " TABLESPACE = %s",
1058 fmtId(dbtablespace));
1060 if (strcmp(dbconnlimit, "-1") != 0)
1061 appendPQExpBuffer(buf, " CONNECTION LIMIT = %s",
1062 dbconnlimit);
1064 appendPQExpBuffer(buf, ";\n");
1066 if (strcmp(dbistemplate, "t") == 0)
1068 appendPQExpBuffer(buf, "UPDATE pg_database SET datistemplate = 't' WHERE datname = ");
1069 appendStringLiteralConn(buf, dbname, conn);
1070 appendPQExpBuffer(buf, ";\n");
1074 if (!skip_acls &&
1075 !buildACLCommands(fdbname, "DATABASE", dbacl, dbowner,
1076 server_version, buf))
1078 fprintf(stderr, _("%s: could not parse ACL list (%s) for database \"%s\"\n"),
1079 progname, dbacl, fdbname);
1080 PQfinish(conn);
1081 exit(1);
1084 fprintf(OPF, "%s", buf->data);
1086 if (server_version >= 70300)
1087 dumpDatabaseConfig(conn, dbname);
1089 free(fdbname);
1092 PQclear(res);
1093 destroyPQExpBuffer(buf);
1095 fprintf(OPF, "\n\n");
1101 * Dump database-specific configuration
1103 static void
1104 dumpDatabaseConfig(PGconn *conn, const char *dbname)
1106 PQExpBuffer buf = createPQExpBuffer();
1107 int count = 1;
1109 for (;;)
1111 PGresult *res;
1113 printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE datname = ", count);
1114 appendStringLiteralConn(buf, dbname, conn);
1115 appendPQExpBuffer(buf, ";");
1117 res = executeQuery(conn, buf->data);
1118 if (!PQgetisnull(res, 0, 0))
1120 makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
1121 "DATABASE", dbname);
1122 PQclear(res);
1123 count++;
1125 else
1127 PQclear(res);
1128 break;
1132 destroyPQExpBuffer(buf);
1138 * Dump user-specific configuration
1140 static void
1141 dumpUserConfig(PGconn *conn, const char *username)
1143 PQExpBuffer buf = createPQExpBuffer();
1144 int count = 1;
1146 for (;;)
1148 PGresult *res;
1150 if (server_version >= 80100)
1151 printfPQExpBuffer(buf, "SELECT rolconfig[%d] FROM pg_authid WHERE rolname = ", count);
1152 else
1153 printfPQExpBuffer(buf, "SELECT useconfig[%d] FROM pg_shadow WHERE usename = ", count);
1154 appendStringLiteralConn(buf, username, conn);
1156 res = executeQuery(conn, buf->data);
1157 if (PQntuples(res) == 1 &&
1158 !PQgetisnull(res, 0, 0))
1160 makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
1161 "ROLE", username);
1162 PQclear(res);
1163 count++;
1165 else
1167 PQclear(res);
1168 break;
1172 destroyPQExpBuffer(buf);
1178 * Helper function for dumpXXXConfig().
1180 static void
1181 makeAlterConfigCommand(PGconn *conn, const char *arrayitem,
1182 const char *type, const char *name)
1184 char *pos;
1185 char *mine;
1186 PQExpBuffer buf = createPQExpBuffer();
1188 mine = strdup(arrayitem);
1189 pos = strchr(mine, '=');
1190 if (pos == NULL)
1191 return;
1193 *pos = 0;
1194 appendPQExpBuffer(buf, "ALTER %s %s ", type, fmtId(name));
1195 appendPQExpBuffer(buf, "SET %s TO ", fmtId(mine));
1198 * Some GUC variable names are 'LIST' type and hence must not be quoted.
1200 if (pg_strcasecmp(mine, "DateStyle") == 0
1201 || pg_strcasecmp(mine, "search_path") == 0)
1202 appendPQExpBuffer(buf, "%s", pos + 1);
1203 else
1204 appendStringLiteralConn(buf, pos + 1, conn);
1205 appendPQExpBuffer(buf, ";\n");
1207 fprintf(OPF, "%s", buf->data);
1208 destroyPQExpBuffer(buf);
1209 free(mine);
1215 * Dump contents of databases.
1217 static void
1218 dumpDatabases(PGconn *conn)
1220 PGresult *res;
1221 int i;
1223 if (server_version >= 70100)
1224 res = executeQuery(conn, "SELECT datname FROM pg_database WHERE datallowconn ORDER BY 1");
1225 else
1226 res = executeQuery(conn, "SELECT datname FROM pg_database ORDER BY 1");
1228 for (i = 0; i < PQntuples(res); i++)
1230 int ret;
1232 char *dbname = PQgetvalue(res, i, 0);
1234 if (verbose)
1235 fprintf(stderr, _("%s: dumping database \"%s\"...\n"), progname, dbname);
1237 fprintf(OPF, "\\connect %s\n\n", fmtId(dbname));
1239 if (filename)
1240 fclose(OPF);
1242 ret = runPgDump(dbname);
1243 if (ret != 0)
1245 fprintf(stderr, _("%s: pg_dump failed on database \"%s\", exiting\n"), progname, dbname);
1246 exit(1);
1249 if (filename)
1251 OPF = fopen(filename, PG_BINARY_A);
1252 if (!OPF)
1254 fprintf(stderr, _("%s: could not re-open the output file \"%s\": %s\n"),
1255 progname, filename, strerror(errno));
1256 exit(1);
1262 PQclear(res);
1268 * Run pg_dump on dbname.
1270 static int
1271 runPgDump(const char *dbname)
1273 PQExpBuffer cmd = createPQExpBuffer();
1274 const char *p;
1275 int ret;
1278 * Win32 has to use double-quotes for args, rather than single quotes.
1279 * Strangely enough, this is the only place we pass a database name on the
1280 * command line, except "postgres" which doesn't need quoting.
1282 * If we have a filename, use the undocumented plain-append pg_dump
1283 * format.
1285 if (filename)
1287 #ifndef WIN32
1288 appendPQExpBuffer(cmd, SYSTEMQUOTE"\"%s\" %s -Fa '", pg_dump_bin,
1289 #else
1290 appendPQExpBuffer(cmd, SYSTEMQUOTE"\"%s\" %s -Fa \"", pg_dump_bin,
1291 #endif
1292 pgdumpopts->data);
1294 else
1296 #ifndef WIN32
1297 appendPQExpBuffer(cmd, SYSTEMQUOTE "\"%s\" %s -Fp '", pg_dump_bin,
1298 #else
1299 appendPQExpBuffer(cmd, SYSTEMQUOTE "\"%s\" %s -Fp \"", pg_dump_bin,
1300 #endif
1301 pgdumpopts->data);
1305 /* Shell quoting is not quite like SQL quoting, so can't use fmtId */
1306 for (p = dbname; *p; p++)
1308 #ifndef WIN32
1309 if (*p == '\'')
1310 appendPQExpBuffer(cmd, "'\"'\"'");
1311 #else
1312 if (*p == '"')
1313 appendPQExpBuffer(cmd, "\\\"");
1314 #endif
1315 else
1316 appendPQExpBufferChar(cmd, *p);
1319 #ifndef WIN32
1320 appendPQExpBufferChar(cmd, '\'');
1321 #else
1322 appendPQExpBufferChar(cmd, '"');
1323 #endif
1325 appendPQExpBuffer(cmd, "%s", SYSTEMQUOTE);
1327 if (verbose)
1328 fprintf(stderr, _("%s: running \"%s\"\n"), progname, cmd->data);
1330 fflush(stdout);
1331 fflush(stderr);
1333 ret = system(cmd->data);
1335 destroyPQExpBuffer(cmd);
1337 return ret;
1343 * Make a database connection with the given parameters. An
1344 * interactive password prompt is automatically issued if required.
1346 * If fail_on_error is false, we return NULL without printing any message
1347 * on failure, but preserve any prompted password for the next try.
1349 static PGconn *
1350 connectDatabase(const char *dbname, const char *pghost, const char *pgport,
1351 const char *pguser, bool require_password, bool fail_on_error)
1353 PGconn *conn;
1354 bool new_pass;
1355 const char *remoteversion_str;
1356 int my_version;
1357 static char *password = NULL;
1359 if (require_password && !password)
1360 password = simple_prompt("Password: ", 100, false);
1363 * Start the connection. Loop until we have a password if requested by
1364 * backend.
1368 new_pass = false;
1369 conn = PQsetdbLogin(pghost, pgport, NULL, NULL, dbname, pguser, password);
1371 if (!conn)
1373 fprintf(stderr, _("%s: could not connect to database \"%s\"\n"),
1374 progname, dbname);
1375 exit(1);
1378 if (PQstatus(conn) == CONNECTION_BAD &&
1379 PQconnectionNeedsPassword(conn) &&
1380 password == NULL &&
1381 !feof(stdin))
1383 PQfinish(conn);
1384 password = simple_prompt("Password: ", 100, false);
1385 new_pass = true;
1387 } while (new_pass);
1389 /* check to see that the backend connection was successfully made */
1390 if (PQstatus(conn) == CONNECTION_BAD)
1392 if (fail_on_error)
1394 fprintf(stderr,
1395 _("%s: could not connect to database \"%s\": %s\n"),
1396 progname, dbname, PQerrorMessage(conn));
1397 exit(1);
1399 else
1401 PQfinish(conn);
1402 return NULL;
1406 remoteversion_str = PQparameterStatus(conn, "server_version");
1407 if (!remoteversion_str)
1409 fprintf(stderr, _("%s: could not get server version\n"), progname);
1410 exit(1);
1412 server_version = parse_version(remoteversion_str);
1413 if (server_version < 0)
1415 fprintf(stderr, _("%s: could not parse server version \"%s\"\n"),
1416 progname, remoteversion_str);
1417 exit(1);
1420 my_version = parse_version(PG_VERSION);
1421 if (my_version < 0)
1423 fprintf(stderr, _("%s: could not parse version \"%s\"\n"),
1424 progname, PG_VERSION);
1425 exit(1);
1429 * We allow the server to be back to 7.0, and up to any minor release
1430 * of our own major version. (See also version check in pg_dump.c.)
1432 if (my_version != server_version
1433 && (server_version < 70000 ||
1434 (server_version / 100) > (my_version / 100)))
1436 fprintf(stderr, _("server version: %s; %s version: %s\n"),
1437 remoteversion_str, progname, PG_VERSION);
1438 fprintf(stderr, _("aborting because of server version mismatch\n"));
1439 exit(1);
1443 * On 7.3 and later, make sure we are not fooled by non-system schemas in
1444 * the search path.
1446 if (server_version >= 70300)
1447 executeCommand(conn, "SET search_path = pg_catalog");
1449 return conn;
1454 * Run a query, return the results, exit program on failure.
1456 static PGresult *
1457 executeQuery(PGconn *conn, const char *query)
1459 PGresult *res;
1461 if (verbose)
1462 fprintf(stderr, _("%s: executing %s\n"), progname, query);
1464 res = PQexec(conn, query);
1465 if (!res ||
1466 PQresultStatus(res) != PGRES_TUPLES_OK)
1468 fprintf(stderr, _("%s: query failed: %s"),
1469 progname, PQerrorMessage(conn));
1470 fprintf(stderr, _("%s: query was: %s\n"),
1471 progname, query);
1472 PQfinish(conn);
1473 exit(1);
1476 return res;
1480 * As above for a SQL command (which returns nothing).
1482 static void
1483 executeCommand(PGconn *conn, const char *query)
1485 PGresult *res;
1487 if (verbose)
1488 fprintf(stderr, _("%s: executing %s\n"), progname, query);
1490 res = PQexec(conn, query);
1491 if (!res ||
1492 PQresultStatus(res) != PGRES_COMMAND_OK)
1494 fprintf(stderr, _("%s: query failed: %s"),
1495 progname, PQerrorMessage(conn));
1496 fprintf(stderr, _("%s: query was: %s\n"),
1497 progname, query);
1498 PQfinish(conn);
1499 exit(1);
1502 PQclear(res);
1507 * dumpTimestamp
1509 static void
1510 dumpTimestamp(char *msg)
1512 char buf[256];
1513 time_t now = time(NULL);
1516 * We don't print the timezone on Win32, because the names are long and
1517 * localized, which means they may contain characters in various random
1518 * encodings; this has been seen to cause encoding errors when reading the
1519 * dump script.
1521 if (strftime(buf, sizeof(buf),
1522 #ifndef WIN32
1523 "%Y-%m-%d %H:%M:%S %Z",
1524 #else
1525 "%Y-%m-%d %H:%M:%S",
1526 #endif
1527 localtime(&now)) != 0)
1528 fprintf(OPF, "-- %s %s\n\n", msg, buf);