PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
adminpack.c File Reference
#include "postgres.h"
#include <sys/file.h>
#include <sys/stat.h>
#include <unistd.h>
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "postmaster/syslogger.h"
#include "storage/fd.h"
#include "utils/builtins.h"
#include "utils/datetime.h"
Include dependency graph for adminpack.c:

Go to the source code of this file.

Data Structures

struct  directory_fctx
 

Functions

 PG_FUNCTION_INFO_V1 (pg_file_write)
 
 PG_FUNCTION_INFO_V1 (pg_file_rename)
 
 PG_FUNCTION_INFO_V1 (pg_file_unlink)
 
 PG_FUNCTION_INFO_V1 (pg_logdir_ls)
 
static char * convert_and_check_filename (text *arg, bool logAllowed)
 
static void requireSuperuser (void)
 
Datum pg_file_write (PG_FUNCTION_ARGS)
 
Datum pg_file_rename (PG_FUNCTION_ARGS)
 
Datum pg_file_unlink (PG_FUNCTION_ARGS)
 
Datum pg_logdir_ls (PG_FUNCTION_ARGS)
 

Variables

 PG_MODULE_MAGIC
 

Function Documentation

static char* convert_and_check_filename ( text arg,
bool  logAllowed 
)
static

Definition at line 65 of file adminpack.c.

References canonicalize_path(), DataDir, ereport, errcode(), errmsg(), ERROR, filename, is_absolute_path, Log_directory, path_contains_parent_reference(), path_is_prefix_of_path(), path_is_relative_and_below_cwd(), and text_to_cstring().

Referenced by pg_file_rename(), pg_file_unlink(), and pg_file_write().

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 }
char * Log_directory
Definition: syslogger.c:66
bool path_is_prefix_of_path(const char *path1, const char *path2)
Definition: path.c:438
void canonicalize_path(char *path)
Definition: path.c:254
int errcode(int sqlerrcode)
Definition: elog.c:575
bool path_contains_parent_reference(const char *path)
Definition: path.c:376
#define ERROR
Definition: elog.h:43
#define is_absolute_path(filename)
Definition: port.h:77
bool path_is_relative_and_below_cwd(const char *path)
Definition: path.c:405
#define ereport(elevel, rest)
Definition: elog.h:122
char * text_to_cstring(const text *t)
Definition: varlena.c:184
static char * filename
Definition: pg_dumpall.c:87
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * DataDir
Definition: globals.c:59
Datum pg_file_rename ( PG_FUNCTION_ARGS  )

Definition at line 161 of file adminpack.c.

References convert_and_check_filename(), ereport, errcode_for_file_access(), errmsg(), ERROR, PG_ARGISNULL, PG_GETARG_TEXT_PP, PG_RETURN_BOOL, PG_RETURN_NULL, requireSuperuser(), and WARNING.

162 {
163  char *fn1,
164  *fn2,
165  *fn3;
166  int rc;
167 
169 
170  if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
171  PG_RETURN_NULL();
172 
175  if (PG_ARGISNULL(2))
176  fn3 = 0;
177  else
179 
180  if (access(fn1, W_OK) < 0)
181  {
184  errmsg("file \"%s\" is not accessible: %m", fn1)));
185 
186  PG_RETURN_BOOL(false);
187  }
188 
189  if (fn3 && access(fn2, W_OK) < 0)
190  {
193  errmsg("file \"%s\" is not accessible: %m", fn2)));
194 
195  PG_RETURN_BOOL(false);
196  }
197 
198  rc = access(fn3 ? fn3 : fn2, 2);
199  if (rc >= 0 || errno != ENOENT)
200  {
201  ereport(ERROR,
202  (ERRCODE_DUPLICATE_FILE,
203  errmsg("cannot rename to target file \"%s\"",
204  fn3 ? fn3 : fn2)));
205  }
206 
207  if (fn3)
208  {
209  if (rename(fn2, fn3) != 0)
210  {
211  ereport(ERROR,
213  errmsg("could not rename \"%s\" to \"%s\": %m",
214  fn2, fn3)));
215  }
216  if (rename(fn1, fn2) != 0)
217  {
220  errmsg("could not rename \"%s\" to \"%s\": %m",
221  fn1, fn2)));
222 
223  if (rename(fn3, fn2) != 0)
224  {
225  ereport(ERROR,
227  errmsg("could not rename \"%s\" back to \"%s\": %m",
228  fn3, fn2)));
229  }
230  else
231  {
232  ereport(ERROR,
233  (ERRCODE_UNDEFINED_FILE,
234  errmsg("renaming \"%s\" to \"%s\" was reverted",
235  fn2, fn3)));
236  }
237  }
238  }
239  else if (rename(fn1, fn2) != 0)
240  {
241  ereport(ERROR,
243  errmsg("could not rename \"%s\" to \"%s\": %m", fn1, fn2)));
244  }
245 
246  PG_RETURN_BOOL(true);
247 }
static char * convert_and_check_filename(text *arg, bool logAllowed)
Definition: adminpack.c:65
static void requireSuperuser(void)
Definition: adminpack.c:103
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:265
#define ERROR
Definition: elog.h:43
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
#define WARNING
Definition: elog.h:40
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:311
#define PG_ARGISNULL(n)
Definition: fmgr.h:166
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PG_RETURN_NULL()
Definition: fmgr.h:297
Datum pg_file_unlink ( PG_FUNCTION_ARGS  )

Definition at line 251 of file adminpack.c.

References convert_and_check_filename(), ereport, errcode_for_file_access(), errmsg(), ERROR, filename, PG_GETARG_TEXT_PP, PG_RETURN_BOOL, requireSuperuser(), unlink(), and WARNING.

252 {
253  char *filename;
254 
256 
257  filename = convert_and_check_filename(PG_GETARG_TEXT_PP(0), false);
258 
259  if (access(filename, W_OK) < 0)
260  {
261  if (errno == ENOENT)
262  PG_RETURN_BOOL(false);
263  else
264  ereport(ERROR,
266  errmsg("file \"%s\" is not accessible: %m", filename)));
267  }
268 
269  if (unlink(filename) < 0)
270  {
273  errmsg("could not unlink file \"%s\": %m", filename)));
274 
275  PG_RETURN_BOOL(false);
276  }
277  PG_RETURN_BOOL(true);
278 }
static char * convert_and_check_filename(text *arg, bool logAllowed)
Definition: adminpack.c:65
static void requireSuperuser(void)
Definition: adminpack.c:103
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:265
#define ERROR
Definition: elog.h:43
int errcode_for_file_access(void)
Definition: elog.c:598
int unlink(const char *filename)
#define ereport(elevel, rest)
Definition: elog.h:122
#define WARNING
Definition: elog.h:40
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:311
static char * filename
Definition: pg_dumpall.c:87
int errmsg(const char *fmt,...)
Definition: elog.c:797
Datum pg_file_write ( PG_FUNCTION_ARGS  )

Definition at line 118 of file adminpack.c.

References AllocateFile(), convert_and_check_filename(), ereport, errcode_for_file_access(), errmsg(), ERROR, filename, FreeFile(), PG_GETARG_BOOL, PG_GETARG_TEXT_PP, PG_RETURN_INT64, requireSuperuser(), VARDATA_ANY, and VARSIZE_ANY_EXHDR.

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_PP(0), false);
128  data = PG_GETARG_TEXT_PP(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 = AllocateFile(filename, "wb");
140  }
141  else
142  f = AllocateFile(filename, "ab");
143 
144  if (!f)
145  ereport(ERROR,
147  errmsg("could not open file \"%s\" for writing: %m",
148  filename)));
149 
150  count = fwrite(VARDATA_ANY(data), 1, VARSIZE_ANY_EXHDR(data), f);
151  if (count != VARSIZE_ANY_EXHDR(data) || FreeFile(f))
152  ereport(ERROR,
154  errmsg("could not write file \"%s\": %m", filename)));
155 
156  PG_RETURN_INT64(count);
157 }
#define VARDATA_ANY(PTR)
Definition: postgres.h:347
#define PG_RETURN_INT64(x)
Definition: fmgr.h:319
static char * convert_and_check_filename(text *arg, bool logAllowed)
Definition: adminpack.c:65
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:231
static void requireSuperuser(void)
Definition: adminpack.c:103
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:265
#define ERROR
Definition: elog.h:43
int errcode_for_file_access(void)
Definition: elog.c:598
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2057
#define ereport(elevel, rest)
Definition: elog.h:122
int FreeFile(FILE *file)
Definition: fd.c:2240
static char * filename
Definition: pg_dumpall.c:87
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:340
int errmsg(const char *fmt,...)
Definition: elog.c:797
Definition: c.h:439
PG_FUNCTION_INFO_V1 ( pg_file_write  )
PG_FUNCTION_INFO_V1 ( pg_file_rename  )
PG_FUNCTION_INFO_V1 ( pg_file_unlink  )
PG_FUNCTION_INFO_V1 ( pg_logdir_ls  )
Datum pg_logdir_ls ( PG_FUNCTION_ARGS  )

Definition at line 282 of file adminpack.c.

References AllocateDir(), FuncCallContext::attinmeta, BuildTupleFromCStrings(), CreateTemplateTupleDesc(), dirent::d_name, DecodeDateTime(), directory_fctx::dirdesc, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, FreeDir(), HeapTupleGetDatum, directory_fctx::location, Log_directory, Log_filename, MAXDATEFIELDS, MAXDATELEN, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, NULL, palloc(), ParseDateTime(), psprintf(), pstrdup(), ReadDir(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, superuser(), TEXTOID, TIMESTAMPOID, TupleDescGetAttInMetadata(), TupleDescInitEntry(), FuncCallContext::user_fctx, and values.

283 {
284  FuncCallContext *funcctx;
285  struct dirent *de;
286  directory_fctx *fctx;
287 
288  if (!superuser())
289  ereport(ERROR,
290  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
291  (errmsg("only superuser can list the log directory"))));
292 
293  if (strcmp(Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log") != 0)
294  ereport(ERROR,
295  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
296  (errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'"))));
297 
298  if (SRF_IS_FIRSTCALL())
299  {
300  MemoryContext oldcontext;
301  TupleDesc tupdesc;
302 
303  funcctx = SRF_FIRSTCALL_INIT();
304  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
305 
306  fctx = palloc(sizeof(directory_fctx));
307 
308  tupdesc = CreateTemplateTupleDesc(2, false);
309  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "starttime",
310  TIMESTAMPOID, -1, 0);
311  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "filename",
312  TEXTOID, -1, 0);
313 
314  funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
315 
316  fctx->location = pstrdup(Log_directory);
317  fctx->dirdesc = AllocateDir(fctx->location);
318 
319  if (!fctx->dirdesc)
320  ereport(ERROR,
322  errmsg("could not read directory \"%s\": %m",
323  fctx->location)));
324 
325  funcctx->user_fctx = fctx;
326  MemoryContextSwitchTo(oldcontext);
327  }
328 
329  funcctx = SRF_PERCALL_SETUP();
330  fctx = (directory_fctx *) funcctx->user_fctx;
331 
332  while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
333  {
334  char *values[2];
335  HeapTuple tuple;
336  char timestampbuf[32];
337  char *field[MAXDATEFIELDS];
338  char lowstr[MAXDATELEN + 1];
339  int dtype;
340  int nf,
341  ftype[MAXDATEFIELDS];
342  fsec_t fsec;
343  int tz = 0;
344  struct pg_tm date;
345 
346  /*
347  * Default format: postgresql-YYYY-MM-DD_HHMMSS.log
348  */
349  if (strlen(de->d_name) != 32
350  || strncmp(de->d_name, "postgresql-", 11) != 0
351  || de->d_name[21] != '_'
352  || strcmp(de->d_name + 28, ".log") != 0)
353  continue;
354 
355  /* extract timestamp portion of filename */
356  strcpy(timestampbuf, de->d_name + 11);
357  timestampbuf[17] = '\0';
358 
359  /* parse and decode expected timestamp to verify it's OK format */
360  if (ParseDateTime(timestampbuf, lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf))
361  continue;
362 
363  if (DecodeDateTime(field, ftype, nf, &dtype, &date, &fsec, &tz))
364  continue;
365 
366  /* Seems the timestamp is OK; prepare and return tuple */
367 
368  values[0] = timestampbuf;
369  values[1] = psprintf("%s/%s", fctx->location, de->d_name);
370 
371  tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
372 
373  SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
374  }
375 
376  FreeDir(fctx->dirdesc);
377  SRF_RETURN_DONE(funcctx);
378 }
#define MAXDATELEN
Definition: datetime.h:203
char * Log_directory
Definition: syslogger.c:66
#define TEXTOID
Definition: pg_type.h:324
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:285
char * pstrdup(const char *in)
Definition: mcxt.c:1077
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
long date
Definition: pgtypes_date.h:8
Definition: pgtime.h:25
Definition: dirent.h:9
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:289
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:511
#define ERROR
Definition: elog.h:43
DIR * dirdesc
Definition: adminpack.c:51
AttInMetadata * attinmeta
Definition: funcapi.h:99
int errcode_for_file_access(void)
Definition: elog.c:598
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2298
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
#define ereport(elevel, rest)
Definition: elog.h:122
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:1068
#define NULL
Definition: c.h:229
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2364
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
void * user_fctx
Definition: funcapi.h:90
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
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
int FreeDir(DIR *dir)
Definition: fd.c:2407
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:309
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:287
static void requireSuperuser ( void  )
static

Definition at line 103 of file adminpack.c.

References ereport, errcode(), errmsg(), ERROR, and superuser().

Referenced by pg_file_rename(), pg_file_unlink(), and pg_file_write().

104 {
105  if (!superuser())
106  ereport(ERROR,
107  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
108  (errmsg("only superuser may access generic file functions"))));
109 }
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
int errmsg(const char *fmt,...)
Definition: elog.c:797

Variable Documentation

PG_MODULE_MAGIC

Definition at line 41 of file adminpack.c.