1 /*-------------------------------------------------------------------------
2  *
3  * archive.c
4  *	  Common WAL archive routines
5  *
6  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/common/archive.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #ifndef FRONTEND
17 #include "postgres.h"
18 #else
19 #include "postgres_fe.h"
20 #endif
21 
22 #include "common/archive.h"
23 #include "lib/stringinfo.h"
24 
25 /*
26  * BuildRestoreCommand
27  *
28  * Builds a restore command to retrieve a file from WAL archives, replacing
29  * the supported aliases with values supplied by the caller as defined by
30  * the GUC parameter restore_command: xlogpath for %p, xlogfname for %f and
31  * lastRestartPointFname for %r.
32  *
33  * The result is a palloc'd string for the restore command built.  The
34  * caller is responsible for freeing it.  If any of the required arguments
35  * is NULL and that the corresponding alias is found in the command given
36  * by the caller, then NULL is returned.
37  */
38 char *
BuildRestoreCommand(const char * restoreCommand,const char * xlogpath,const char * xlogfname,const char * lastRestartPointFname)39 BuildRestoreCommand(const char *restoreCommand,
40 					const char *xlogpath,
41 					const char *xlogfname,
42 					const char *lastRestartPointFname)
43 {
44 	StringInfoData result;
45 	const char *sp;
46 
47 	/*
48 	 * Build the command to be executed.
49 	 */
50 	initStringInfo(&result);
51 
52 	for (sp = restoreCommand; *sp; sp++)
53 	{
54 		if (*sp == '%')
55 		{
56 			switch (sp[1])
57 			{
58 				case 'p':
59 					{
60 						char	   *nativePath;
61 
62 						/* %p: relative path of target file */
63 						if (xlogpath == NULL)
64 						{
65 							pfree(result.data);
66 							return NULL;
67 						}
68 						sp++;
69 
70 						/*
71 						 * This needs to use a placeholder to not modify the
72 						 * input with the conversion done via
73 						 * make_native_path().
74 						 */
75 						nativePath = pstrdup(xlogpath);
76 						make_native_path(nativePath);
77 						appendStringInfoString(&result,
78 											   nativePath);
79 						pfree(nativePath);
80 						break;
81 					}
82 				case 'f':
83 					/* %f: filename of desired file */
84 					if (xlogfname == NULL)
85 					{
86 						pfree(result.data);
87 						return NULL;
88 					}
89 					sp++;
90 					appendStringInfoString(&result, xlogfname);
91 					break;
92 				case 'r':
93 					/* %r: filename of last restartpoint */
94 					if (lastRestartPointFname == NULL)
95 					{
96 						pfree(result.data);
97 						return NULL;
98 					}
99 					sp++;
100 					appendStringInfoString(&result,
101 										   lastRestartPointFname);
102 					break;
103 				case '%':
104 					/* convert %% to a single % */
105 					sp++;
106 					appendStringInfoChar(&result, *sp);
107 					break;
108 				default:
109 					/* otherwise treat the % as not special */
110 					appendStringInfoChar(&result, *sp);
111 					break;
112 			}
113 		}
114 		else
115 		{
116 			appendStringInfoChar(&result, *sp);
117 		}
118 	}
119 
120 	return result.data;
121 }
122