PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
adminpack.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * adminpack.c
4  *
5  *
6  * Copyright (c) 2002-2017, PostgreSQL Global Development Group
7  *
8  * Author: Andreas Pflug <pgadmin@pse-consulting.de>
9  *
10  * IDENTIFICATION
11  * contrib/adminpack/adminpack.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include <sys/file.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 
21 #include "catalog/pg_type.h"
22 #include "funcapi.h"
23 #include "miscadmin.h"
24 #include "postmaster/syslogger.h"
25 #include "storage/fd.h"
26 #include "utils/builtins.h"
27 #include "utils/datetime.h"
28 
29 
30 #ifdef WIN32
31 
32 #ifdef rename
33 #undef rename
34 #endif
35 
36 #ifdef unlink
37 #undef unlink
38 #endif
39 #endif
40 
42 
47 
48 typedef struct
49 {
50  char *location;
53 
54 /*-----------------------
55  * some helper functions
56  */
57 
58 /*
59  * Convert a "text" filename argument to C string, and check it's allowable.
60  *
61  * Filename may be absolute or relative to the DataDir, but we only allow
62  * absolute paths that match DataDir or Log_directory.
63  */
64 static char *
66 {
67  char *filename = text_to_cstring(arg);
68 
69  canonicalize_path(filename); /* filename can change length here */
70 
71  if (is_absolute_path(filename))
72  {
73  /* Disallow '/a/b/data/..' */
74  if (path_contains_parent_reference(filename))
75  ereport(ERROR,
76  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
77  (errmsg("reference to parent directory (\"..\") not allowed"))));
78 
79  /*
80  * Allow absolute paths if within DataDir or Log_directory, even
81  * though Log_directory might be outside DataDir.
82  */
83  if (!path_is_prefix_of_path(DataDir, filename) &&
84  (!logAllowed || !is_absolute_path(Log_directory) ||
86  ereport(ERROR,
87  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
88  (errmsg("absolute path not allowed"))));
89  }
90  else if (!path_is_relative_and_below_cwd(filename))
91  ereport(ERROR,
92  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
93  (errmsg("path must be in or below the current directory"))));
94 
95  return filename;
96 }
97 
98 
99 /*
100  * check for superuser, bark if not.
101  */
102 static void
104 {
105  if (!superuser())
106  ereport(ERROR,
107  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
108  (errmsg("only superuser may access generic file functions"))));
109 }
110 
111 
112 
113 /* ------------------------------------
114  * generic file handling functions
115  */
116 
117 Datum
119 {
120  FILE *f;
121  char *filename;
122  text *data;
123  int64 count = 0;
124 
126 
127  filename = convert_and_check_filename(PG_GETARG_TEXT_P(0), false);
128  data = PG_GETARG_TEXT_P(1);
129 
130  if (!PG_GETARG_BOOL(2))
131  {
132  struct stat fst;
133 
134  if (stat(filename, &fst) >= 0)
135  ereport(ERROR,
136  (ERRCODE_DUPLICATE_FILE,
137  errmsg("file \"%s\" exists", filename)));
138 
139  f = fopen(filename, "wb");
140  }
141  else
142  f = fopen(filename, "ab");
143 
144  if (!f)
145  ereport(ERROR,
147  errmsg("could not open file \"%s\" for writing: %m",
148  filename)));
149 
150  if (VARSIZE(data) != 0)
151  {
152  count = fwrite(VARDATA(data), 1, VARSIZE(data) - VARHDRSZ, f);
153 
154  if (count != VARSIZE(data) - VARHDRSZ)
155  ereport(ERROR,
157  errmsg("could not write file \"%s\": %m", filename)));
158  }
159  fclose(f);
160 
161  PG_RETURN_INT64(count);
162 }
163 
164 
165 Datum
167 {
168  char *fn1,
169  *fn2,
170  *fn3;
171  int rc;
172 
174 
175  if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
176  PG_RETURN_NULL();
177 
180  if (PG_ARGISNULL(2))
181  fn3 = 0;
182  else
184 
185  if (access(fn1, W_OK) < 0)
186  {
189  errmsg("file \"%s\" is not accessible: %m", fn1)));
190 
191  PG_RETURN_BOOL(false);
192  }
193 
194  if (fn3 && access(fn2, W_OK) < 0)
195  {
198  errmsg("file \"%s\" is not accessible: %m", fn2)));
199 
200  PG_RETURN_BOOL(false);
201  }
202 
203  rc = access(fn3 ? fn3 : fn2, 2);
204  if (rc >= 0 || errno != ENOENT)
205  {
206  ereport(ERROR,
207  (ERRCODE_DUPLICATE_FILE,
208  errmsg("cannot rename to target file \"%s\"",
209  fn3 ? fn3 : fn2)));
210  }
211 
212  if (fn3)
213  {
214  if (rename(fn2, fn3) != 0)
215  {
216  ereport(ERROR,
218  errmsg("could not rename \"%s\" to \"%s\": %m",
219  fn2, fn3)));
220  }
221  if (rename(fn1, fn2) != 0)
222  {
225  errmsg("could not rename \"%s\" to \"%s\": %m",
226  fn1, fn2)));
227 
228  if (rename(fn3, fn2) != 0)
229  {
230  ereport(ERROR,
232  errmsg("could not rename \"%s\" back to \"%s\": %m",
233  fn3, fn2)));
234  }
235  else
236  {
237  ereport(ERROR,
238  (ERRCODE_UNDEFINED_FILE,
239  errmsg("renaming \"%s\" to \"%s\" was reverted",
240  fn2, fn3)));
241  }
242  }
243  }
244  else if (rename(fn1, fn2) != 0)
245  {
246  ereport(ERROR,
248  errmsg("could not rename \"%s\" to \"%s\": %m", fn1, fn2)));
249  }
250 
251  PG_RETURN_BOOL(true);
252 }
253 
254 
255 Datum
257 {
258  char *filename;
259 
261 
262  filename = convert_and_check_filename(PG_GETARG_TEXT_P(0), false);
263 
264  if (access(filename, W_OK) < 0)
265  {
266  if (errno == ENOENT)
267  PG_RETURN_BOOL(false);
268  else
269  ereport(ERROR,
271  errmsg("file \"%s\" is not accessible: %m", filename)));
272  }
273 
274  if (unlink(filename) < 0)
275  {
278  errmsg("could not unlink file \"%s\": %m", filename)));
279 
280  PG_RETURN_BOOL(false);
281  }
282  PG_RETURN_BOOL(true);
283 }
284 
285 
286 Datum
288 {
289  FuncCallContext *funcctx;
290  struct dirent *de;
291  directory_fctx *fctx;
292 
293  if (!superuser())
294  ereport(ERROR,
295  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
296  (errmsg("only superuser can list the log directory"))));
297 
298  if (strcmp(Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log") != 0)
299  ereport(ERROR,
300  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
301  (errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'"))));
302 
303  if (SRF_IS_FIRSTCALL())
304  {
305  MemoryContext oldcontext;
306  TupleDesc tupdesc;
307 
308  funcctx = SRF_FIRSTCALL_INIT();
309  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
310 
311  fctx = palloc(sizeof(directory_fctx));
312 
313  tupdesc = CreateTemplateTupleDesc(2, false);
314  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "starttime",
315  TIMESTAMPOID, -1, 0);
316  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "filename",
317  TEXTOID, -1, 0);
318 
319  funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
320 
321  fctx->location = pstrdup(Log_directory);
322  fctx->dirdesc = AllocateDir(fctx->location);
323 
324  if (!fctx->dirdesc)
325  ereport(ERROR,
327  errmsg("could not read directory \"%s\": %m",
328  fctx->location)));
329 
330  funcctx->user_fctx = fctx;
331  MemoryContextSwitchTo(oldcontext);
332  }
333 
334  funcctx = SRF_PERCALL_SETUP();
335  fctx = (directory_fctx *) funcctx->user_fctx;
336 
337  while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
338  {
339  char *values[2];
340  HeapTuple tuple;
341  char timestampbuf[32];
342  char *field[MAXDATEFIELDS];
343  char lowstr[MAXDATELEN + 1];
344  int dtype;
345  int nf,
346  ftype[MAXDATEFIELDS];
347  fsec_t fsec;
348  int tz = 0;
349  struct pg_tm date;
350 
351  /*
352  * Default format: postgresql-YYYY-MM-DD_HHMMSS.log
353  */
354  if (strlen(de->d_name) != 32
355  || strncmp(de->d_name, "postgresql-", 11) != 0
356  || de->d_name[21] != '_'
357  || strcmp(de->d_name + 28, ".log") != 0)
358  continue;
359 
360  /* extract timestamp portion of filename */
361  strcpy(timestampbuf, de->d_name + 11);
362  timestampbuf[17] = '\0';
363 
364  /* parse and decode expected timestamp to verify it's OK format */
365  if (ParseDateTime(timestampbuf, lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf))
366  continue;
367 
368  if (DecodeDateTime(field, ftype, nf, &dtype, &date, &fsec, &tz))
369  continue;
370 
371  /* Seems the timestamp is OK; prepare and return tuple */
372 
373  values[0] = timestampbuf;
374  values[1] = psprintf("%s/%s", fctx->location, de->d_name);
375 
376  tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
377 
378  SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
379  }
380 
381  FreeDir(fctx->dirdesc);
382  SRF_RETURN_DONE(funcctx);
383 }
#define MAXDATELEN
Definition: datetime.h:203
Datum pg_file_write(PG_FUNCTION_ARGS)
Definition: adminpack.c:118
#define VARDATA(PTR)
Definition: postgres.h:305
char * Log_directory
Definition: syslogger.c:66
#define TEXTOID
Definition: pg_type.h:324
#define VARSIZE(PTR)
Definition: postgres.h:306
#define PG_RETURN_INT64(x)
Definition: fmgr.h:311
static char * convert_and_check_filename(text *arg, bool logAllowed)
Definition: adminpack.c:65
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:285
bool path_is_prefix_of_path(const char *path1, const char *path2)
Definition: path.c:438
#define VARHDRSZ
Definition: c.h:441
char * pstrdup(const char *in)
Definition: mcxt.c:1165
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void canonicalize_path(char *path)
Definition: path.c:254
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:230
Definition: pgtime.h:25
Definition: dirent.h:9
bool path_contains_parent_reference(const char *path)
Definition: path.c:376
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:289
static void requireSuperuser(void)
Definition: adminpack.c:103
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:1115
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:291
int DecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp)
Definition: datetime.c:783
#define TIMESTAMPOID
Definition: pg_type.h:507
Definition: dirent.c:25
#define ERROR
Definition: elog.h:43
Datum pg_file_unlink(PG_FUNCTION_ARGS)
Definition: adminpack.c:256
DIR * dirdesc
Definition: adminpack.c:51
Datum pg_logdir_ls(PG_FUNCTION_ARGS)
Definition: adminpack.c:287
PG_FUNCTION_INFO_V1(pg_file_write)
AttInMetadata * attinmeta
Definition: funcapi.h:99
PG_MODULE_MAGIC
Definition: adminpack.c:41
int errcode_for_file_access(void)
Definition: elog.c:598
#define is_absolute_path(filename)
Definition: port.h:77
bool path_is_relative_and_below_cwd(const char *path)
Definition: path.c:405
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2284
int32 fsec_t
Definition: timestamp.h:41
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:493
int unlink(const char *filename)
#define ereport(elevel, rest)
Definition: elog.h:122
#define WARNING
Definition: elog.h:40
Datum pg_file_rename(PG_FUNCTION_ARGS)
Definition: adminpack.c:166
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:303
uintptr_t Datum
Definition: postgres.h:374
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:1068
#define PG_ARGISNULL(n)
Definition: fmgr.h:166
#define NULL
Definition: c.h:226
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2350
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:109
#define MAXDATEFIELDS
Definition: datetime.h:205
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:222
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:41
char * Log_filename
Definition: syslogger.c:67
char * location
Definition: adminpack.c:50
static Datum values[MAXATTR]
Definition: bootstrap.c:162
char * text_to_cstring(const text *t)
Definition: varlena.c:184
static char * filename
Definition: pg_dumpall.c:84
void * user_fctx
Definition: funcapi.h:90
void * palloc(Size size)
Definition: mcxt.c:891
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PG_GETARG_TEXT_P(n)
Definition: fmgr.h:269
void * arg
char * DataDir
Definition: globals.c:59
Definition: c.h:435
#define PG_FUNCTION_ARGS
Definition: fmgr.h:150
char d_name[MAX_PATH]
Definition: dirent.h:14
int ParseDateTime(const char *timestr, char *workbuf, size_t buflen, char **field, int *ftype, int maxfields, int *numfields)
Definition: datetime.c:562
int16 AttrNumber
Definition: attnum.h:21
#define PG_RETURN_NULL()
Definition: fmgr.h:289
int FreeDir(DIR *dir)
Definition: fd.c:2393
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:309
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:287