]> granicus.if.org Git - postgresql/blob - contrib/pg_upgrade/controldata.c
f4252af4edca2c5f7c2297d472e526bafefb481d
[postgresql] / contrib / pg_upgrade / controldata.c
1 /*
2  *      controldata.c
3  *
4  *      controldata functions
5  *
6  *      Copyright (c) 2010-2013, PostgreSQL Global Development Group
7  *      contrib/pg_upgrade/controldata.c
8  */
9
10 #include "postgres.h"
11
12 #include "pg_upgrade.h"
13
14 #include <ctype.h>
15
16 /*
17  * get_control_data()
18  *
19  * gets pg_control information in "ctrl". Assumes that bindir and
20  * datadir are valid absolute paths to postgresql bin and pgdata
21  * directories respectively *and* pg_resetxlog is version compatible
22  * with datadir. The main purpose of this function is to get pg_control
23  * data in a version independent manner.
24  *
25  * The approach taken here is to invoke pg_resetxlog with -n option
26  * and then pipe its output. With little string parsing we get the
27  * pg_control data.  pg_resetxlog cannot be run while the server is running
28  * so we use pg_controldata;  pg_controldata doesn't provide all the fields
29  * we need to actually perform the upgrade, but it provides enough for
30  * check mode.  We do not implement pg_resetxlog -n because it is hard to
31  * return valid xid data for a running server.
32  */
33 void
34 get_control_data(ClusterInfo *cluster, bool live_check)
35 {
36         char            cmd[MAXPGPATH];
37         char            bufin[MAX_STRING];
38         FILE       *output;
39         char       *p;
40         bool            got_xid = false;
41         bool            got_oid = false;
42         bool            got_nextxlogfile = false;
43         bool            got_multi = false;
44         bool            got_mxoff = false;
45         bool            got_oldestmulti = false;
46         bool            got_log_id = false;
47         bool            got_log_seg = false;
48         bool            got_tli = false;
49         bool            got_align = false;
50         bool            got_blocksz = false;
51         bool            got_largesz = false;
52         bool            got_walsz = false;
53         bool            got_walseg = false;
54         bool            got_ident = false;
55         bool            got_index = false;
56         bool            got_toast = false;
57         bool            got_date_is_int = false;
58         bool            got_float8_pass_by_value = false;
59         char       *lc_collate = NULL;
60         char       *lc_ctype = NULL;
61         char       *lc_monetary = NULL;
62         char       *lc_numeric = NULL;
63         char       *lc_time = NULL;
64         char       *lang = NULL;
65         char       *language = NULL;
66         char       *lc_all = NULL;
67         char       *lc_messages = NULL;
68         uint32          logid = 0;
69         uint32          segno = 0;
70         uint32          tli = 0;
71
72
73         /*
74          * Because we test the pg_resetxlog output as strings, it has to be in
75          * English.  Copied from pg_regress.c.
76          */
77         if (getenv("LC_COLLATE"))
78                 lc_collate = pg_strdup(getenv("LC_COLLATE"));
79         if (getenv("LC_CTYPE"))
80                 lc_ctype = pg_strdup(getenv("LC_CTYPE"));
81         if (getenv("LC_MONETARY"))
82                 lc_monetary = pg_strdup(getenv("LC_MONETARY"));
83         if (getenv("LC_NUMERIC"))
84                 lc_numeric = pg_strdup(getenv("LC_NUMERIC"));
85         if (getenv("LC_TIME"))
86                 lc_time = pg_strdup(getenv("LC_TIME"));
87         if (getenv("LANG"))
88                 lang = pg_strdup(getenv("LANG"));
89         if (getenv("LANGUAGE"))
90                 language = pg_strdup(getenv("LANGUAGE"));
91         if (getenv("LC_ALL"))
92                 lc_all = pg_strdup(getenv("LC_ALL"));
93         if (getenv("LC_MESSAGES"))
94                 lc_messages = pg_strdup(getenv("LC_MESSAGES"));
95
96         pg_putenv("LC_COLLATE", NULL);
97         pg_putenv("LC_CTYPE", NULL);
98         pg_putenv("LC_MONETARY", NULL);
99         pg_putenv("LC_NUMERIC", NULL);
100         pg_putenv("LC_TIME", NULL);
101         pg_putenv("LANG",
102 #ifndef WIN32
103                           NULL);
104 #else
105         /* On Windows the default locale cannot be English, so force it */
106                           "en");
107 #endif
108         pg_putenv("LANGUAGE", NULL);
109         pg_putenv("LC_ALL", NULL);
110         pg_putenv("LC_MESSAGES", "C");
111
112         snprintf(cmd, sizeof(cmd), SYSTEMQUOTE "\"%s/%s \"%s\"" SYSTEMQUOTE,
113                          cluster->bindir,
114                          live_check ? "pg_controldata\"" : "pg_resetxlog\" -n",
115                          cluster->pgdata);
116         fflush(stdout);
117         fflush(stderr);
118
119         if ((output = popen(cmd, "r")) == NULL)
120                 pg_log(PG_FATAL, "Could not get control data using %s: %s\n",
121                            cmd, getErrorText(errno));
122
123         /* Only pre-8.4 has these so if they are not set below we will check later */
124         cluster->controldata.lc_collate = NULL;
125         cluster->controldata.lc_ctype = NULL;
126
127         /* Only in <= 8.3 */
128         if (GET_MAJOR_VERSION(cluster->major_version) <= 803)
129         {
130                 cluster->controldata.float8_pass_by_value = false;
131                 got_float8_pass_by_value = true;
132         }
133
134         /* we have the result of cmd in "output". so parse it line by line now */
135         while (fgets(bufin, sizeof(bufin), output))
136         {
137                 pg_log(PG_VERBOSE, "%s", bufin);
138
139 #ifdef WIN32
140
141                 /*
142                  * Due to an installer bug, LANG=C doesn't work for PG 8.3.3, but does
143                  * work 8.2.6 and 8.3.7, so check for non-ASCII output and suggest a
144                  * minor upgrade.
145                  */
146                 if (GET_MAJOR_VERSION(cluster->major_version) <= 803)
147                 {
148                         for (p = bufin; *p; p++)
149                                 if (!isascii(*p))
150                                         pg_log(PG_FATAL,
151                                                    "The 8.3 cluster's pg_controldata is incapable of outputting ASCII, even\n"
152                                                    "with LANG=C.  You must upgrade this cluster to a newer version of PostgreSQL\n"
153                                                    "8.3 to fix this bug.  PostgreSQL 8.3.7 and later are known to work properly.\n");
154                 }
155 #endif
156
157                 if ((p = strstr(bufin, "pg_control version number:")) != NULL)
158                 {
159                         p = strchr(p, ':');
160
161                         if (p == NULL || strlen(p) <= 1)
162                                 pg_log(PG_FATAL, "%d: pg_resetxlog problem\n", __LINE__);
163
164                         p++;                            /* removing ':' char */
165                         cluster->controldata.ctrl_ver = str2uint(p);
166                 }
167                 else if ((p = strstr(bufin, "Catalog version number:")) != NULL)
168                 {
169                         p = strchr(p, ':');
170
171                         if (p == NULL || strlen(p) <= 1)
172                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
173
174                         p++;                            /* removing ':' char */
175                         cluster->controldata.cat_ver = str2uint(p);
176                 }
177                 else if ((p = strstr(bufin, "First log segment after reset:")) != NULL)
178                 {
179                         /* Skip the colon and any whitespace after it */
180                         p = strchr(p, ':');
181                         if (p == NULL || strlen(p) <= 1)
182                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
183                         p = strpbrk(p, "01234567890ABCDEF");
184                         if (p == NULL || strlen(p) <= 1)
185                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
186
187                         /* Make sure it looks like a valid WAL file name */
188                         if (strspn(p, "0123456789ABCDEF") != 24)
189                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
190
191                         strlcpy(cluster->controldata.nextxlogfile, p, 25);
192                         got_nextxlogfile = true;
193                 }
194                 else if ((p = strstr(bufin, "First log file ID after reset:")) != NULL)
195                 {
196                         p = strchr(p, ':');
197
198                         if (p == NULL || strlen(p) <= 1)
199                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
200
201                         p++;                            /* removing ':' char */
202                         logid = str2uint(p);
203                         got_log_id = true;
204                 }
205                 else if ((p = strstr(bufin, "First log file segment after reset:")) != NULL)
206                 {
207                         p = strchr(p, ':');
208
209                         if (p == NULL || strlen(p) <= 1)
210                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
211
212                         p++;                            /* removing ':' char */
213                         segno = str2uint(p);
214                         got_log_seg = true;
215                 }
216                 else if ((p = strstr(bufin, "Latest checkpoint's TimeLineID:")) != NULL)
217                 {
218                         p = strchr(p, ':');
219
220                         if (p == NULL || strlen(p) <= 1)
221                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
222
223                         p++;                            /* removing ':' char */
224                         cluster->controldata.chkpnt_tli = str2uint(p);
225                         got_tli = true;
226                 }
227                 else if ((p = strstr(bufin, "Latest checkpoint's NextXID:")) != NULL)
228                 {
229                         char       *op = strchr(p, '/');
230
231                         if (op == NULL)
232                                 op = strchr(p, ':');
233
234                         if (op == NULL || strlen(op) <= 1)
235                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
236
237                         op++;                           /* removing ':' char */
238                         cluster->controldata.chkpnt_nxtxid = str2uint(op);
239                         got_xid = true;
240                 }
241                 else if ((p = strstr(bufin, "Latest checkpoint's NextOID:")) != NULL)
242                 {
243                         p = strchr(p, ':');
244
245                         if (p == NULL || strlen(p) <= 1)
246                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
247
248                         p++;                            /* removing ':' char */
249                         cluster->controldata.chkpnt_nxtoid = str2uint(p);
250                         got_oid = true;
251                 }
252                 else if ((p = strstr(bufin, "Latest checkpoint's NextMultiXactId:")) != NULL)
253                 {
254                         p = strchr(p, ':');
255
256                         if (p == NULL || strlen(p) <= 1)
257                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
258
259                         p++;                            /* removing ':' char */
260                         cluster->controldata.chkpnt_nxtmulti = str2uint(p);
261                         got_multi = true;
262                 }
263                 else if ((p = strstr(bufin, "Latest checkpoint's oldestMultiXid:")) != NULL)
264                 {
265                         p = strchr(p, ':');
266
267                         if (p == NULL || strlen(p) <= 1)
268                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
269
270                         p++;                            /* removing ':' char */
271                         cluster->controldata.chkpnt_oldstMulti = str2uint(p);
272                         got_oldestmulti = true;
273                 }
274                 else if ((p = strstr(bufin, "Latest checkpoint's NextMultiOffset:")) != NULL)
275                 {
276                         p = strchr(p, ':');
277
278                         if (p == NULL || strlen(p) <= 1)
279                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
280
281                         p++;                            /* removing ':' char */
282                         cluster->controldata.chkpnt_nxtmxoff = str2uint(p);
283                         got_mxoff = true;
284                 }
285                 else if ((p = strstr(bufin, "Maximum data alignment:")) != NULL)
286                 {
287                         p = strchr(p, ':');
288
289                         if (p == NULL || strlen(p) <= 1)
290                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
291
292                         p++;                            /* removing ':' char */
293                         cluster->controldata.align = str2uint(p);
294                         got_align = true;
295                 }
296                 else if ((p = strstr(bufin, "Database block size:")) != NULL)
297                 {
298                         p = strchr(p, ':');
299
300                         if (p == NULL || strlen(p) <= 1)
301                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
302
303                         p++;                            /* removing ':' char */
304                         cluster->controldata.blocksz = str2uint(p);
305                         got_blocksz = true;
306                 }
307                 else if ((p = strstr(bufin, "Blocks per segment of large relation:")) != NULL)
308                 {
309                         p = strchr(p, ':');
310
311                         if (p == NULL || strlen(p) <= 1)
312                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
313
314                         p++;                            /* removing ':' char */
315                         cluster->controldata.largesz = str2uint(p);
316                         got_largesz = true;
317                 }
318                 else if ((p = strstr(bufin, "WAL block size:")) != NULL)
319                 {
320                         p = strchr(p, ':');
321
322                         if (p == NULL || strlen(p) <= 1)
323                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
324
325                         p++;                            /* removing ':' char */
326                         cluster->controldata.walsz = str2uint(p);
327                         got_walsz = true;
328                 }
329                 else if ((p = strstr(bufin, "Bytes per WAL segment:")) != NULL)
330                 {
331                         p = strchr(p, ':');
332
333                         if (p == NULL || strlen(p) <= 1)
334                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
335
336                         p++;                            /* removing ':' char */
337                         cluster->controldata.walseg = str2uint(p);
338                         got_walseg = true;
339                 }
340                 else if ((p = strstr(bufin, "Maximum length of identifiers:")) != NULL)
341                 {
342                         p = strchr(p, ':');
343
344                         if (p == NULL || strlen(p) <= 1)
345                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
346
347                         p++;                            /* removing ':' char */
348                         cluster->controldata.ident = str2uint(p);
349                         got_ident = true;
350                 }
351                 else if ((p = strstr(bufin, "Maximum columns in an index:")) != NULL)
352                 {
353                         p = strchr(p, ':');
354
355                         if (p == NULL || strlen(p) <= 1)
356                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
357
358                         p++;                            /* removing ':' char */
359                         cluster->controldata.index = str2uint(p);
360                         got_index = true;
361                 }
362                 else if ((p = strstr(bufin, "Maximum size of a TOAST chunk:")) != NULL)
363                 {
364                         p = strchr(p, ':');
365
366                         if (p == NULL || strlen(p) <= 1)
367                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
368
369                         p++;                            /* removing ':' char */
370                         cluster->controldata.toast = str2uint(p);
371                         got_toast = true;
372                 }
373                 else if ((p = strstr(bufin, "Date/time type storage:")) != NULL)
374                 {
375                         p = strchr(p, ':');
376
377                         if (p == NULL || strlen(p) <= 1)
378                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
379
380                         p++;                            /* removing ':' char */
381                         cluster->controldata.date_is_int = strstr(p, "64-bit integers") != NULL;
382                         got_date_is_int = true;
383                 }
384                 else if ((p = strstr(bufin, "Float8 argument passing:")) != NULL)
385                 {
386                         p = strchr(p, ':');
387
388                         if (p == NULL || strlen(p) <= 1)
389                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
390
391                         p++;                            /* removing ':' char */
392                         /* used later for contrib check */
393                         cluster->controldata.float8_pass_by_value = strstr(p, "by value") != NULL;
394                         got_float8_pass_by_value = true;
395                 }
396                 /* In pre-8.4 only */
397                 else if ((p = strstr(bufin, "LC_COLLATE:")) != NULL)
398                 {
399                         p = strchr(p, ':');
400
401                         if (p == NULL || strlen(p) <= 1)
402                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
403
404                         p++;                            /* removing ':' char */
405                         /* skip leading spaces and remove trailing newline */
406                         p += strspn(p, " ");
407                         if (strlen(p) > 0 && *(p + strlen(p) - 1) == '\n')
408                                 *(p + strlen(p) - 1) = '\0';
409                         cluster->controldata.lc_collate = pg_strdup(p);
410                 }
411                 /* In pre-8.4 only */
412                 else if ((p = strstr(bufin, "LC_CTYPE:")) != NULL)
413                 {
414                         p = strchr(p, ':');
415
416                         if (p == NULL || strlen(p) <= 1)
417                                 pg_log(PG_FATAL, "%d: controldata retrieval problem\n", __LINE__);
418
419                         p++;                            /* removing ':' char */
420                         /* skip leading spaces and remove trailing newline */
421                         p += strspn(p, " ");
422                         if (strlen(p) > 0 && *(p + strlen(p) - 1) == '\n')
423                                 *(p + strlen(p) - 1) = '\0';
424                         cluster->controldata.lc_ctype = pg_strdup(p);
425                 }
426         }
427
428         if (output)
429                 pclose(output);
430
431         /*
432          * Restore environment variables
433          */
434         pg_putenv("LC_COLLATE", lc_collate);
435         pg_putenv("LC_CTYPE", lc_ctype);
436         pg_putenv("LC_MONETARY", lc_monetary);
437         pg_putenv("LC_NUMERIC", lc_numeric);
438         pg_putenv("LC_TIME", lc_time);
439         pg_putenv("LANG", lang);
440         pg_putenv("LANGUAGE", language);
441         pg_putenv("LC_ALL", lc_all);
442         pg_putenv("LC_MESSAGES", lc_messages);
443
444         pg_free(lc_collate);
445         pg_free(lc_ctype);
446         pg_free(lc_monetary);
447         pg_free(lc_numeric);
448         pg_free(lc_time);
449         pg_free(lang);
450         pg_free(language);
451         pg_free(lc_all);
452         pg_free(lc_messages);
453
454         /*
455          * Before 9.3, pg_resetxlog reported the xlogid and segno of the first
456          * log file after reset as separate lines. Starting with 9.3, it reports
457          * the WAL file name. If the old cluster is older than 9.3, we construct
458          * the WAL file name from the xlogid and segno.
459          */
460         if (GET_MAJOR_VERSION(cluster->major_version) <= 902)
461         {
462                 if (got_log_id && got_log_seg)
463                 {
464                         snprintf(cluster->controldata.nextxlogfile, 25, "%08X%08X%08X",
465                                          tli, logid, segno);
466                         got_nextxlogfile = true;
467                 }
468         }
469
470         /* verify that we got all the mandatory pg_control data */
471         if (!got_xid || !got_oid ||
472                 !got_multi || !got_mxoff || !got_oldestmulti ||
473                 (!live_check && !got_nextxlogfile) ||
474                 !got_tli ||
475                 !got_align || !got_blocksz || !got_largesz || !got_walsz ||
476                 !got_walseg || !got_ident || !got_index || !got_toast ||
477                 !got_date_is_int || !got_float8_pass_by_value)
478         {
479                 pg_log(PG_REPORT,
480                         "The %s cluster lacks some required control information:\n",
481                         CLUSTER_NAME(cluster));
482
483                 if (!got_xid)
484                         pg_log(PG_REPORT, "  checkpoint next XID\n");
485
486                 if (!got_oid)
487                         pg_log(PG_REPORT, "  latest checkpoint next OID\n");
488
489                 if (!got_multi)
490                         pg_log(PG_REPORT, "  latest checkpoint next MultiXactId\n");
491
492                 if (!got_mxoff)
493                         pg_log(PG_REPORT, "  latest checkpoint next MultiXactOffset\n");
494
495                 if (!got_oldestmulti)
496                         pg_log(PG_REPORT, "  latest checkpoint oldest MultiXactId\n");
497
498                 if (!live_check && !got_nextxlogfile)
499                         pg_log(PG_REPORT, "  first WAL segment after reset\n");
500
501                 if (!got_tli)
502                         pg_log(PG_REPORT, "  latest checkpoint timeline ID\n");
503
504                 if (!got_align)
505                         pg_log(PG_REPORT, "  maximum alignment\n");
506
507                 if (!got_blocksz)
508                         pg_log(PG_REPORT, "  block size\n");
509
510                 if (!got_largesz)
511                         pg_log(PG_REPORT, "  large relation segment size\n");
512
513                 if (!got_walsz)
514                         pg_log(PG_REPORT, "  WAL block size\n");
515
516                 if (!got_walseg)
517                         pg_log(PG_REPORT, "  WAL segment size\n");
518
519                 if (!got_ident)
520                         pg_log(PG_REPORT, "  maximum identifier length\n");
521
522                 if (!got_index)
523                         pg_log(PG_REPORT, "  maximum number of indexed columns\n");
524
525                 if (!got_toast)
526                         pg_log(PG_REPORT, "  maximum TOAST chunk size\n");
527
528                 if (!got_date_is_int)
529                         pg_log(PG_REPORT, "  dates/times are integers?\n");
530
531                 /* value added in Postgres 8.4 */
532                 if (!got_float8_pass_by_value)
533                         pg_log(PG_REPORT, "  float8 argument passing method\n");
534
535                 pg_log(PG_FATAL,
536                            "Cannot continue without required control information, terminating\n");
537         }
538 }
539
540
541 /*
542  * check_control_data()
543  *
544  * check to make sure the control data settings are compatible
545  */
546 void
547 check_control_data(ControlData *oldctrl,
548                                    ControlData *newctrl)
549 {
550         if (oldctrl->align == 0 || oldctrl->align != newctrl->align)
551                 pg_log(PG_FATAL,
552                            "old and new pg_controldata alignments are invalid or do not match\n"
553                            "Likely one cluster is a 32-bit install, the other 64-bit\n");
554
555         if (oldctrl->blocksz == 0 || oldctrl->blocksz != newctrl->blocksz)
556                 pg_log(PG_FATAL,
557                            "old and new pg_controldata block sizes are invalid or do not match\n");
558
559         if (oldctrl->largesz == 0 || oldctrl->largesz != newctrl->largesz)
560                 pg_log(PG_FATAL,
561                            "old and new pg_controldata maximum relation segement sizes are invalid or do not match\n");
562
563         if (oldctrl->walsz == 0 || oldctrl->walsz != newctrl->walsz)
564                 pg_log(PG_FATAL,
565                            "old and new pg_controldata WAL block sizes are invalid or do not match\n");
566
567         if (oldctrl->walseg == 0 || oldctrl->walseg != newctrl->walseg)
568                 pg_log(PG_FATAL,
569                            "old and new pg_controldata WAL segment sizes are invalid or do not match\n");
570
571         if (oldctrl->ident == 0 || oldctrl->ident != newctrl->ident)
572                 pg_log(PG_FATAL,
573                            "old and new pg_controldata maximum identifier lengths are invalid or do not match\n");
574
575         if (oldctrl->index == 0 || oldctrl->index != newctrl->index)
576                 pg_log(PG_FATAL,
577                            "old and new pg_controldata maximum indexed columns are invalid or do not match\n");
578
579         if (oldctrl->toast == 0 || oldctrl->toast != newctrl->toast)
580                 pg_log(PG_FATAL,
581                            "old and new pg_controldata maximum TOAST chunk sizes are invalid or do not match\n");
582
583         if (oldctrl->date_is_int != newctrl->date_is_int)
584         {
585                 pg_log(PG_WARNING,
586                            "\nOld and new pg_controldata date/time storage types do not match.\n");
587
588                 /*
589                  * This is a common 8.3 -> 8.4 upgrade problem, so we are more verbose
590                  */
591                 pg_log(PG_FATAL,
592                         "You will need to rebuild the new server with configure option\n"
593                            "--disable-integer-datetimes or get server binaries built with those\n"
594                            "options.\n");
595         }
596 }
597
598
599 void
600 disable_old_cluster(void)
601 {
602         char            old_path[MAXPGPATH],
603                                 new_path[MAXPGPATH];
604
605         /* rename pg_control so old server cannot be accidentally started */
606         prep_status("Adding \".old\" suffix to old global/pg_control");
607
608         snprintf(old_path, sizeof(old_path), "%s/global/pg_control", old_cluster.pgdata);
609         snprintf(new_path, sizeof(new_path), "%s/global/pg_control.old", old_cluster.pgdata);
610         if (pg_mv_file(old_path, new_path) != 0)
611                 pg_log(PG_FATAL, "Unable to rename %s to %s.\n", old_path, new_path);
612         check_ok();
613
614         pg_log(PG_REPORT, "\n"
615                    "If you want to start the old cluster, you will need to remove\n"
616                    "the \".old\" suffix from %s/global/pg_control.old.\n"
617                  "Because \"link\" mode was used, the old cluster cannot be safely\n"
618         "started once the new cluster has been started.\n\n", old_cluster.pgdata);
619 }