mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
Add pg_ls_logdir() and pg_ls_waldir() functions.
These functions are intended to be used by monitoring tools, and, unlike pg_ls_dir(), access to them can be granted to non-superusers, so that those monitoring tools can observe the principle of least privilege. Dave Page, revised by me, and also reviewed a bit by Thomas Munro. Discussion: http://postgr.es/m/CA+OCxow-X=D2fWdKy+HP+vQ1LtrgbsYQ=CshzZBqyFT5jOYrFw@mail.gmail.com
This commit is contained in:
@ -21,6 +21,7 @@
|
||||
#include <dirent.h>
|
||||
|
||||
#include "access/htup_details.h"
|
||||
#include "access/xlog_internal.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "funcapi.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
@ -473,3 +474,96 @@ pg_ls_dir_1arg(PG_FUNCTION_ARGS)
|
||||
{
|
||||
return pg_ls_dir(fcinfo);
|
||||
}
|
||||
|
||||
/* Generic function to return a directory listing of files */
|
||||
static Datum
|
||||
pg_ls_dir_files(FunctionCallInfo fcinfo, char *dir)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
struct dirent *de;
|
||||
directory_fctx *fctx;
|
||||
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
MemoryContext oldcontext;
|
||||
TupleDesc tupdesc;
|
||||
|
||||
funcctx = SRF_FIRSTCALL_INIT();
|
||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||
|
||||
fctx = palloc(sizeof(directory_fctx));
|
||||
|
||||
tupdesc = CreateTemplateTupleDesc(3, false);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
|
||||
TEXTOID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "size",
|
||||
INT8OID, -1, 0);
|
||||
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "modification",
|
||||
TIMESTAMPTZOID, -1, 0);
|
||||
funcctx->tuple_desc = BlessTupleDesc(tupdesc);
|
||||
|
||||
fctx->location = pstrdup(dir);
|
||||
fctx->dirdesc = AllocateDir(fctx->location);
|
||||
|
||||
if (!fctx->dirdesc)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read directory \"%s\": %m",
|
||||
fctx->location)));
|
||||
|
||||
funcctx->user_fctx = fctx;
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
}
|
||||
|
||||
funcctx = SRF_PERCALL_SETUP();
|
||||
fctx = (directory_fctx *) funcctx->user_fctx;
|
||||
|
||||
while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
|
||||
{
|
||||
Datum values[3];
|
||||
bool nulls[3];
|
||||
char path[MAXPGPATH];
|
||||
struct stat attrib;
|
||||
HeapTuple tuple;
|
||||
|
||||
/* Skip hidden files */
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
/* Get the file info */
|
||||
snprintf(path, MAXPGPATH, "%s/%s", fctx->location, de->d_name);
|
||||
if (stat(path, &attrib) < 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not stat directory \"%s\": %m", dir)));
|
||||
|
||||
/* Ignore anything but regular files */
|
||||
if (!S_ISREG(attrib.st_mode))
|
||||
continue;
|
||||
|
||||
values[0] = CStringGetTextDatum(de->d_name);
|
||||
values[1] = Int64GetDatum((int64) attrib.st_size);
|
||||
values[2] = TimestampTzGetDatum(time_t_to_timestamptz(attrib.st_mtime));
|
||||
memset(nulls, 0, sizeof(nulls));
|
||||
|
||||
tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
|
||||
SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
|
||||
}
|
||||
|
||||
FreeDir(fctx->dirdesc);
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
|
||||
/* Function to return the list of files in the log directory */
|
||||
Datum
|
||||
pg_ls_logdir(PG_FUNCTION_ARGS)
|
||||
{
|
||||
return pg_ls_dir_files(fcinfo, Log_directory);
|
||||
}
|
||||
|
||||
/* Function to return the list of files in the WAL directory */
|
||||
Datum
|
||||
pg_ls_waldir(PG_FUNCTION_ARGS)
|
||||
{
|
||||
return pg_ls_dir_files(fcinfo, XLOGDIR);
|
||||
}
|
||||
|
Reference in New Issue
Block a user