Add pg_ls_logdir() and pg_ls_waldir() functions.
authorRobert Haas
Thu, 16 Mar 2017 19:05:02 +0000 (15:05 -0400)
committerRobert Haas
Thu, 16 Mar 2017 19:05:02 +0000 (15:05 -0400)
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

doc/src/sgml/func.sgml
src/backend/catalog/system_views.sql
src/backend/utils/adt/genfile.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h

index a521912317b36faa8358e52f468efc92416714ff..9518fa20388afe58b44509ccc3363854085527e6 100644 (file)
@@ -19646,7 +19646,8 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
     database cluster directory and the log_directory can be
     accessed.  Use a relative path for files in the cluster directory,
     and a path matching the log_directory configuration setting
-    for log files.  Use of these functions is restricted to superusers.
+    for log files.  Use of these functions is restricted to superusers
+    except where stated otherwise.
    
 
    
@@ -19667,6 +19668,26 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
         List the contents of a directory.
        
       
+      
+       
+        pg_ls_logdir()
+       
+       setof record
+       
+        List the name, size, and last modification time of files in the log
+        directory.  Access may be granted to non-superuser roles.
+       
+      
+      
+       
+        pg_ls_waldir()
+       
+       setof record
+       
+        List the name, size, and last modification time of files in the WAL
+        directory.  Access may be granted to non-superuser roles.
+       
+      
       
        
         pg_read_file(filename text [, offset bigint, length bigint [, missing_ok boolean] ])
@@ -19699,7 +19720,7 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
    
 
    
-    All of these functions take an optional missing_ok parameter,
+    Some of these functions take an optional missing_ok parameter,
     which specifies the behavior when the file or directory does not exist.
     If true, the function returns NULL (except
     pg_ls_dir, which returns an empty result set). If
@@ -19719,6 +19740,26 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
     empty directory from an non-existent directory.
    
 
+   
+    pg_ls_logdir
+   
+   
+    pg_ls_logdir returns the name, size, and last modified time
+    (mtime) of each file in the log directory. By default, only superusers
+    can use this function, but access may be granted to others using
+    GRANT.
+   
+
+   
+    pg_ls_waldir
+   
+   
+    pg_ls_waldir returns the name, size, and last modified time
+    (mtime) of each file in the write ahead log (WAL) directory. By
+    default only superusers can use this function, but access may be granted
+    to others using GRANT.
+   
+
    
     pg_read_file
    
index 0bce20914e0174ed322013a4f5e367dee3ede498..b6552da4b03eaf531cf68ea1e8f7b605a4ba3c87 100644 (file)
@@ -1102,3 +1102,6 @@ REVOKE EXECUTE ON FUNCTION pg_stat_reset() FROM public;
 REVOKE EXECUTE ON FUNCTION pg_stat_reset_shared(text) FROM public;
 REVOKE EXECUTE ON FUNCTION pg_stat_reset_single_table_counters(oid) FROM public;
 REVOKE EXECUTE ON FUNCTION pg_stat_reset_single_function_counters(oid) FROM public;
+
+REVOKE EXECUTE ON FUNCTION pg_ls_logdir() FROM public;
+REVOKE EXECUTE ON FUNCTION pg_ls_waldir() FROM public;
index 2147936dd8a91d026c567108a4bbb6bd89190151..8d0a236e6d5bc339408bf7e645c4158bc34d22b5 100644 (file)
@@ -21,6 +21,7 @@
 #include 
 
 #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);
+}
index b24e3953a1d99ee0513fd6eefc3ee95522d26d6b..b4f1b9a6c2aa788e35d4634beefd3b65087286ef 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201703151
+#define CATALOG_VERSION_NO 201703161
 
 #endif
index 3d5d8660718a7311e9ab3dc6b536f8936c1e6a06..836d6ff0b2069f95f5e51f421ef4480da4741473 100644 (file)
@@ -5398,6 +5398,12 @@ DESCR("pg_controldata init state information as a function");
 DATA(insert OID = 3445 ( pg_import_system_collations PGNSP PGUID 12 100 0 0 0 f f f f t f v r 2 0 2278 "16 4089" _null_ _null_ "{if_not_exists,schema}" _null_ _null_ pg_import_system_collations _null_ _null_ _null_ ));
 DESCR("import collations from operating system");
 
+/* system management/monitoring related functions */
+DATA(insert OID = 3353 (  pg_ls_logdir               PGNSP PGUID 12 10 20 0 0 f f f f t t v s 0 0 2249 "" "{25,20,1184}" "{o,o,o}" "{name,size,modification}" _null_ _null_ pg_ls_logdir _null_ _null_ _null_ ));
+DESCR("list files in the log directory");
+DATA(insert OID = 3354 (  pg_ls_waldir               PGNSP PGUID 12 10 20 0 0 f f f f t t v s 0 0 2249 "" "{25,20,1184}" "{o,o,o}" "{name,size,modification}" _null_ _null_ pg_ls_waldir _null_ _null_ _null_ ));
+DESCR("list of files in the WAL directory");
+
 /*
  * Symbolic values for provolatile column: these indicate whether the result
  * of a function is dependent *only* on the values of its explicit arguments,