Commit a43ea120 authored by Tom Lane's avatar Tom Lane

Code & docs review for server instrumentation patch. File timestamps

should surely be timestamptz not timestamp; fix some but not all of the
holes in check_and_make_absolute(); other minor cleanup.  Also put in
the missed catversion bump.
parent cb29f669
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.278 2005/08/12 15:57:48 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.279 2005/08/12 18:23:53 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -9072,13 +9072,13 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9072,13 +9072,13 @@ SELECT set_config('log_statement_stats', 'off', false);
<para> <para>
The functions shown in <xref The functions shown in <xref
linkend="functions-admin-signal-table"> sends control signals to linkend="functions-admin-signal-table"> send control signals to
other server processes. Use of this function is restricted other server processes. Use of these functions is restricted
to superusers. to superusers.
</para> </para>
<table id="functions-admin-signal-table"> <table id="functions-admin-signal-table">
<title>Backend Signalling Functions</title> <title>Server Signalling Functions</title>
<tgroup cols="3"> <tgroup cols="3">
<thead> <thead>
<row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry> <row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry>
...@@ -9088,7 +9088,7 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9088,7 +9088,7 @@ SELECT set_config('log_statement_stats', 'off', false);
<tbody> <tbody>
<row> <row>
<entry> <entry>
<literal><function>pg_cancel_backend</function>(<parameter>pid</parameter>)</literal> <literal><function>pg_cancel_backend</function>(<parameter>pid</parameter> <type>int</>)</literal>
</entry> </entry>
<entry><type>int</type></entry> <entry><type>int</type></entry>
<entry>Cancel a backend's current query</entry> <entry>Cancel a backend's current query</entry>
...@@ -9098,7 +9098,7 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9098,7 +9098,7 @@ SELECT set_config('log_statement_stats', 'off', false);
<literal><function>pg_reload_conf</function>()</literal> <literal><function>pg_reload_conf</function>()</literal>
</entry> </entry>
<entry><type>int</type></entry> <entry><type>int</type></entry>
<entry>Causes server processes to reload their configuration files</entry> <entry>Cause server processes to reload their configuration files</entry>
</row> </row>
</tbody> </tbody>
</tgroup> </tgroup>
...@@ -9113,8 +9113,8 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9113,8 +9113,8 @@ SELECT set_config('log_statement_stats', 'off', false);
</para> </para>
<para> <para>
<function>pg_reload_conf</> sends a SIGHUP signal to the <function>pg_reload_conf</> sends a SIGHUP signal to the
postmaster, causing the reload of the configuration files postmaster, causing reload of the configuration files
in all backend processes. in all server processes.
</para> </para>
<indexterm zone="functions-admin"> <indexterm zone="functions-admin">
...@@ -9144,7 +9144,7 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9144,7 +9144,7 @@ SELECT set_config('log_statement_stats', 'off', false);
<tbody> <tbody>
<row> <row>
<entry> <entry>
<literal><function>pg_start_backup</function>(<parameter>label_text</parameter>)</literal> <literal><function>pg_start_backup</function>(<parameter>label</> <type>text</>)</literal>
</entry> </entry>
<entry><type>text</type></entry> <entry><type>text</type></entry>
<entry>Set up for performing on-line backup</entry> <entry>Set up for performing on-line backup</entry>
...@@ -9219,48 +9219,48 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9219,48 +9219,48 @@ SELECT set_config('log_statement_stats', 'off', false);
<tbody> <tbody>
<row> <row>
<entry><function>pg_column_size</function>(<parameter>any</parameter>)</entry> <entry><function>pg_column_size</function>(<type>any</type>)</entry>
<entry><type>integer</type></entry> <entry><type>integer</type></entry>
<entry>Number of bytes used to store a particular value (possibly compressed)</entry> <entry>Number of bytes used to store a particular value (possibly compressed)</entry>
</row> </row>
<row> <row>
<entry> <entry>
<literal><function>pg_tablespace_size</function>(<parameter>oid</parameter>)</literal> <literal><function>pg_tablespace_size</function>(<type>oid</type>)</literal>
</entry> </entry>
<entry><type>bigint</type></entry> <entry><type>bigint</type></entry>
<entry>Total disk space used by the tablespace with the specified OID</entry> <entry>Total disk space used by the tablespace with the specified OID</entry>
</row> </row>
<row> <row>
<entry> <entry>
<literal><function>pg_tablespace_size</function>(<parameter>name</parameter>)</literal> <literal><function>pg_tablespace_size</function>(<type>name</type>)</literal>
</entry> </entry>
<entry><type>bigint</type></entry> <entry><type>bigint</type></entry>
<entry>Total disk space used by the tablespace with the specified name</entry> <entry>Total disk space used by the tablespace with the specified name</entry>
</row> </row>
<row> <row>
<entry> <entry>
<literal><function>pg_database_size</function>(<parameter>oid</parameter>)</literal> <literal><function>pg_database_size</function>(<type>oid</type>)</literal>
</entry> </entry>
<entry><type>bigint</type></entry> <entry><type>bigint</type></entry>
<entry>Total disk space used by the database with the specified OID</entry> <entry>Total disk space used by the database with the specified OID</entry>
</row> </row>
<row> <row>
<entry> <entry>
<literal><function>pg_database_size</function>(<parameter>name</parameter>)</literal> <literal><function>pg_database_size</function>(<type>name</type>)</literal>
</entry> </entry>
<entry><type>bigint</type></entry> <entry><type>bigint</type></entry>
<entry>Total disk space used by the database with the specified name</entry> <entry>Total disk space used by the database with the specified name</entry>
</row> </row>
<row> <row>
<entry> <entry>
<literal><function>pg_relation_size</function>(<parameter>oid</parameter>)</literal> <literal><function>pg_relation_size</function>(<type>oid</type>)</literal>
</entry> </entry>
<entry><type>bigint</type></entry> <entry><type>bigint</type></entry>
<entry>Disk space used by the table or index with the specified OID</entry> <entry>Disk space used by the table or index with the specified OID</entry>
</row> </row>
<row> <row>
<entry> <entry>
<literal><function>pg_relation_size</function>(<parameter>text</parameter>)</literal> <literal><function>pg_relation_size</function>(<type>text</type>)</literal>
</entry> </entry>
<entry><type>bigint</type></entry> <entry><type>bigint</type></entry>
<entry>Disk space used by the table or index with the specified name. <entry>Disk space used by the table or index with the specified name.
...@@ -9268,7 +9268,7 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9268,7 +9268,7 @@ SELECT set_config('log_statement_stats', 'off', false);
</row> </row>
<row> <row>
<entry> <entry>
<literal><function>pg_complete_relation_size</function>(<parameter>oid</parameter>)</literal> <literal><function>pg_complete_relation_size</function>(<type>oid</type>)</literal>
</entry> </entry>
<entry><type>bigint</type></entry> <entry><type>bigint</type></entry>
<entry>Total disk space used by the table with the specified OID, <entry>Total disk space used by the table with the specified OID,
...@@ -9276,7 +9276,7 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9276,7 +9276,7 @@ SELECT set_config('log_statement_stats', 'off', false);
</row> </row>
<row> <row>
<entry> <entry>
<literal><function>pg_complete_relation_size</function>(<parameter>text</parameter>)</literal> <literal><function>pg_complete_relation_size</function>(<type>text</type>)</literal>
</entry> </entry>
<entry><type>bigint</type></entry> <entry><type>bigint</type></entry>
<entry>Total disk space used by the table with the specified name, <entry>Total disk space used by the table with the specified name,
...@@ -9285,7 +9285,7 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9285,7 +9285,7 @@ SELECT set_config('log_statement_stats', 'off', false);
</row> </row>
<row> <row>
<entry> <entry>
<literal><function>pg_size_pretty</function>(<parameter>bigint</parameter>)</literal> <literal><function>pg_size_pretty</function>(<type>bigint</type>)</literal>
</entry> </entry>
<entry><type>text</type></entry> <entry><type>text</type></entry>
<entry>Converts a size in bytes into a human-readable format with size units</entry> <entry>Converts a size in bytes into a human-readable format with size units</entry>
...@@ -9325,11 +9325,11 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9325,11 +9325,11 @@ SELECT set_config('log_statement_stats', 'off', false);
<para> <para>
The functions shown in <xref The functions shown in <xref
linkend="functions-admin-genfile"> provide native file access to linkend="functions-admin-genfile"> provide native file access to
files on the machine hosting the server. Only files relative to files on the machine hosting the server. Only files within the
the cluster directory are allowed, and the <varname>log_directory</>, database cluster directory and the <varname>log_directory</> may be
because the log file directory might be stored outside the accessed. Use a relative path for files within the cluster directory,
cluster directory. Use of these functions is restricted to and a path matching the <varname>log_directory</> configuration setting
superusers. for log files. Use of these functions is restricted to superusers.
</para> </para>
<table id="functions-admin-genfile"> <table id="functions-admin-genfile">
...@@ -9343,17 +9343,17 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9343,17 +9343,17 @@ SELECT set_config('log_statement_stats', 'off', false);
<tbody> <tbody>
<row> <row>
<entry> <entry>
<literal><function>pg_file_length</function>(<parameter>filename_text</parameter>)</literal> <literal><function>pg_file_length</function>(<parameter>filename</> <type>text</>)</literal>
<indexterm zone="functions-admin"> <indexterm zone="functions-admin">
<primary>pg_file_length</primary> <primary>pg_file_length</primary>
</indexterm> </indexterm>
</entry> </entry>
<entry><type>int8</type></entry> <entry><type>int8</type></entry>
<entry>Returns the file length</entry> <entry>Return the file length</entry>
</row> </row>
<row> <row>
<entry> <entry>
<literal><function>pg_ls_dir</function>(<parameter>dirname_text</parameter>,<parameter>fullpath_bool</parameter>)</literal> <literal><function>pg_ls_dir</function>(<parameter>dirname</> <type>text</>)</literal>
<indexterm zone="functions-admin"> <indexterm zone="functions-admin">
<primary>pg_ls_dir</primary> <primary>pg_ls_dir</primary>
</indexterm> </indexterm>
...@@ -9363,18 +9363,17 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9363,18 +9363,17 @@ SELECT set_config('log_statement_stats', 'off', false);
</row> </row>
<row> <row>
<entry> <entry>
<literal><function>pg_read_file</function>(<parameter>filename_text</parameter>, <literal><function>pg_read_file</function>(<parameter>filename</> <type>text</>, <parameter>offset</> <type>int8</>, <parameter>length</> <type>int8</>)</literal>
<parameter>offset_int8</parameter>,<parameter>length_int8</parameter>)</literal>
</entry> </entry>
<entry><type>text</type></entry> <entry><type>text</type></entry>
<entry>Returns the contents of a text file</entry> <entry>Return the contents of a text file</entry>
</row> </row>
<row> <row>
<entry> <entry>
<literal><function>pg_stat_file</function>(<parameter>filename_text</parameter>)</literal> <literal><function>pg_stat_file</function>(<parameter>filename</> <type>text</>)</literal>
</entry> </entry>
<entry><type>record</type></entry> <entry><type>record</type></entry>
<entry>Returns information about the file</entry> <entry>Return information about the file</entry>
</row> </row>
</tbody> </tbody>
</tgroup> </tgroup>
...@@ -9385,8 +9384,9 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9385,8 +9384,9 @@ SELECT set_config('log_statement_stats', 'off', false);
</indexterm> </indexterm>
<para> <para>
<function>pg_read_file()</> returns part of a textfile, starting <function>pg_read_file()</> returns part of a textfile, starting
at the given offset, returning length bytes. If offset is negative, at the given offset, returning at most length bytes (less if the
it is treated relative to the end of the file. end of file is reached first). If offset is negative,
it is relative to the end of the file.
</para> </para>
<indexterm zone="functions-admin"> <indexterm zone="functions-admin">
...@@ -9396,18 +9396,25 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9396,18 +9396,25 @@ SELECT set_config('log_statement_stats', 'off', false);
<function>pg_stat_file()</> returns a record containing the <function>pg_stat_file()</> returns a record containing the
length, last accessed timestamp, last modified timestamp, length, last accessed timestamp, last modified timestamp,
creation timestamp, and a flag indicating if it is a directory. creation timestamp, and a flag indicating if it is a directory.
Use it like this:
<programlisting>
SELECT *
FROM pg_stat_file('filename')
AS s(length int8, atime timestamptz, mtime timestamptz,
ctime timestamptz, isdir bool);
</programlisting>
</para> </para>
<para> <para>
The function shown in <xref The function shown in <xref
linkend="functions-admin-logfile"> forces the server linkend="functions-admin-logfile"> forces the server
logfile to be rotated if <varname>redirect_stderr</> logfile to be rotated. This works only when <varname>redirect_stderr</>
is used for logging. Use of this functions is restricted is used for logging. Use of this function is restricted
to superusers. to superusers.
</para> </para>
<table id="functions-admin-logfile"> <table id="functions-admin-logfile">
<title>Backend Logfile Functions</title> <title>Server Logfile Functions</title>
<tgroup cols="3"> <tgroup cols="3">
<thead> <thead>
<row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry> <row><entry>Name</entry> <entry>Return Type</entry> <entry>Description</entry>
...@@ -9423,7 +9430,7 @@ SELECT set_config('log_statement_stats', 'off', false); ...@@ -9423,7 +9430,7 @@ SELECT set_config('log_statement_stats', 'off', false);
</indexterm> </indexterm>
</entry> </entry>
<entry><type>int</type></entry> <entry><type>int</type></entry>
<entry>Rotate logfile</entry> <entry>Rotate server's logfile</entry>
</row> </row>
</tbody> </tbody>
</tgroup> </tgroup>
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.463 2005/08/12 03:23:51 momjian Exp $ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.464 2005/08/12 18:23:53 tgl Exp $
* *
* NOTES * NOTES
* *
...@@ -3382,9 +3382,8 @@ sigusr1_handler(SIGNAL_ARGS) ...@@ -3382,9 +3382,8 @@ sigusr1_handler(SIGNAL_ARGS)
} }
} }
if (PgArchPID != 0 && Shutdown == NoShutdown) if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER) &&
{ PgArchPID != 0 && Shutdown == NoShutdown)
if (CheckPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER))
{ {
/* /*
* Send SIGUSR1 to archiver process, to wake it up and begin * Send SIGUSR1 to archiver process, to wake it up and begin
...@@ -3392,10 +3391,13 @@ sigusr1_handler(SIGNAL_ARGS) ...@@ -3392,10 +3391,13 @@ sigusr1_handler(SIGNAL_ARGS)
*/ */
kill(PgArchPID, SIGUSR1); kill(PgArchPID, SIGUSR1);
} }
}
if (CheckPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE) && SysLoggerPID != 0) if (CheckPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE) &&
SysLoggerPID != 0)
{
/* Tell syslogger to rotate logfile */
kill(SysLoggerPID, SIGUSR1); kill(SysLoggerPID, SIGUSR1);
}
PG_SETMASK(&UnBlockSig); PG_SETMASK(&UnBlockSig);
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* genfile.c * genfile.c
* Functions for direct access to files
* *
* *
* Copyright (c) 2004, PostgreSQL Global Development Group * Copyright (c) 2004-2005, PostgreSQL Global Development Group
* *
* Author: Andreas Pflug <pgadmin@pse-consulting.de> * Author: Andreas Pflug <pgadmin@pse-consulting.de>
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/genfile.c,v 1.1 2005/08/12 03:24:08 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/genfile.c,v 1.2 2005/08/12 18:23:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -19,13 +20,15 @@ ...@@ -19,13 +20,15 @@
#include <unistd.h> #include <unistd.h>
#include <dirent.h> #include <dirent.h>
#include "utils/builtins.h" #include "access/heapam.h"
#include "miscadmin.h"
#include "storage/fd.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "funcapi.h" #include "funcapi.h"
#include "miscadmin.h"
#include "postmaster/syslogger.h"
#include "storage/fd.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
extern char *Log_directory;
typedef struct typedef struct
{ {
...@@ -33,13 +36,16 @@ typedef struct ...@@ -33,13 +36,16 @@ typedef struct
DIR *dirdesc; DIR *dirdesc;
} directory_fctx; } directory_fctx;
/* /*
* Return an absolute path. Argument may be absolute or * Validate a path and convert to absolute form.
* relative to the DataDir. *
* Argument may be absolute or relative to the DataDir (but we only allow
* absolute paths that match Log_directory).
*/ */
static char *check_and_make_absolute(text *arg) static char *
check_and_make_absolute(text *arg)
{ {
int datadir_len = strlen(DataDir);
int filename_len = VARSIZE(arg) - VARHDRSZ; int filename_len = VARSIZE(arg) - VARHDRSZ;
char *filename = palloc(filename_len + 1); char *filename = palloc(filename_len + 1);
...@@ -52,16 +58,21 @@ static char *check_and_make_absolute(text *arg) ...@@ -52,16 +58,21 @@ static char *check_and_make_absolute(text *arg)
/* /*
* Prevent reference to the parent directory. * Prevent reference to the parent directory.
* "..a.." is a valid file name though. * "..a.." is a valid file name though.
*
* XXX this is BROKEN because it fails to prevent "C:.." on Windows.
* Need access to "skip_drive" functionality to do it right. (There
* is no actual security hole because we'll prepend the DataDir below,
* resulting in a just-plain-broken path, but we should give the right
* error message instead.)
*/ */
if (strcmp(filename, "..") == 0 || /* beginning */ if (strcmp(filename, "..") == 0 || /* whole */
strncmp(filename, "../", 3) == 0 || /* beginning */
strcmp(filename, "/..") == 0 || /* beginning */
strncmp(filename, "../", 3) == 0 || /* beginning */ strncmp(filename, "../", 3) == 0 || /* beginning */
strstr(filename, "/../") != NULL || /* middle */ strstr(filename, "/../") != NULL || /* middle */
strncmp(filename + filename_len - 3, "/..", 3) == 0) /* end */ (filename_len >= 3 &&
strcmp(filename + filename_len - 3, "/..") == 0)) /* end */
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("Reference to a parent directory (\"..\") not allowed")))); (errmsg("reference to parent directory (\"..\") not allowed"))));
if (is_absolute_path(filename)) if (is_absolute_path(filename))
{ {
...@@ -74,12 +85,12 @@ static char *check_and_make_absolute(text *arg) ...@@ -74,12 +85,12 @@ static char *check_and_make_absolute(text *arg)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("Absolute paths not allowed")))); (errmsg("absolute path not allowed"))));
return NULL; return NULL; /* keep compiler quiet */
} }
else else
{ {
char *absname = palloc(datadir_len + filename_len + 2); char *absname = palloc(strlen(DataDir) + filename_len + 2);
sprintf(absname, "%s/%s", DataDir, filename); sprintf(absname, "%s/%s", DataDir, filename);
pfree(filename); pfree(filename);
return absname; return absname;
...@@ -87,11 +98,16 @@ static char *check_and_make_absolute(text *arg) ...@@ -87,11 +98,16 @@ static char *check_and_make_absolute(text *arg)
} }
Datum pg_read_file(PG_FUNCTION_ARGS) /*
* Read a section of a file, returning it as text
*/
Datum
pg_read_file(PG_FUNCTION_ARGS)
{ {
int64 bytes_to_read = PG_GETARG_INT64(2); text *filename_t = PG_GETARG_TEXT_P(0);
int64 seek_offset = PG_GETARG_INT64(1); int64 seek_offset = PG_GETARG_INT64(1);
char *buf = 0; int64 bytes_to_read = PG_GETARG_INT64(2);
char *buf;
size_t nbytes; size_t nbytes;
FILE *file; FILE *file;
char *filename; char *filename;
...@@ -101,107 +117,108 @@ Datum pg_read_file(PG_FUNCTION_ARGS) ...@@ -101,107 +117,108 @@ Datum pg_read_file(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser to read files")))); (errmsg("must be superuser to read files"))));
filename = check_and_make_absolute(PG_GETARG_TEXT_P(0)); filename = check_and_make_absolute(filename_t);
if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL) if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
{
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open file %s for reading: %m", filename))); errmsg("could not open file \"%s\" for reading: %m",
PG_RETURN_NULL(); filename)));
}
if (fseeko(file, (off_t)seek_offset, if (fseeko(file, (off_t) seek_offset,
(seek_offset >= 0) ? SEEK_SET : SEEK_END) != 0) (seek_offset >= 0) ? SEEK_SET : SEEK_END) != 0)
{
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not seek in file %s: %m", filename))); errmsg("could not seek in file \"%s\": %m", filename)));
PG_RETURN_NULL();
}
if (bytes_to_read < 0) if (bytes_to_read < 0)
{
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("length cannot be negative"))); errmsg("requested length cannot be negative")));
}
/* not sure why anyone thought that int64 length was a good idea */
if (bytes_to_read > (MaxAllocSize - VARHDRSZ))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("requested length too large")));
buf = palloc(bytes_to_read + VARHDRSZ); buf = palloc((Size) bytes_to_read + VARHDRSZ);
nbytes = fread(VARDATA(buf), 1, bytes_to_read, file); nbytes = fread(VARDATA(buf), 1, (size_t) bytes_to_read, file);
if (nbytes < 0) if (nbytes < 0)
{
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not read file %s: %m", filename))); errmsg("could not read file \"%s\": %m", filename)));
PG_RETURN_NULL();
}
VARATT_SIZEP(buf) = nbytes + VARHDRSZ; VARATT_SIZEP(buf) = nbytes + VARHDRSZ;
pfree(filename);
FreeFile(file); FreeFile(file);
pfree(filename);
PG_RETURN_TEXT_P(buf); PG_RETURN_TEXT_P(buf);
} }
/*
Datum pg_stat_file(PG_FUNCTION_ARGS) * stat a file
*/
Datum
pg_stat_file(PG_FUNCTION_ARGS)
{ {
AttInMetadata *attinmeta; text *filename_t = PG_GETARG_TEXT_P(0);
char *filename = check_and_make_absolute(PG_GETARG_TEXT_P(0)); char *filename;
struct stat fst; struct stat fst;
char lenbuf[30], cbuf[30], abuf[30], mbuf[30], dirbuf[2]; Datum values[5];
char *values[5] = {lenbuf, cbuf, abuf, mbuf, dirbuf}; bool isnull[5];
pg_time_t timestamp;
HeapTuple tuple; HeapTuple tuple;
TupleDesc tupdesc = CreateTemplateTupleDesc(5, false); TupleDesc tupdesc;
if (!superuser()) if (!superuser())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("must be superuser to get file information")))); (errmsg("must be superuser to get file information"))));
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "length", INT8OID, -1, 0); filename = check_and_make_absolute(filename_t);
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "atime", TIMESTAMPOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "mtime", TIMESTAMPOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "ctime", TIMESTAMPOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 5, "isdir", BOOLOID, -1, 0);
attinmeta = TupleDescGetAttInMetadata(tupdesc);
if (stat(filename, &fst) < 0) if (stat(filename, &fst) < 0)
{
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not stat file %s: %m", filename))); errmsg("could not stat file \"%s\": %m", filename)));
PG_RETURN_NULL();
} tupdesc = CreateTemplateTupleDesc(5, false);
else TupleDescInitEntry(tupdesc, (AttrNumber) 1,
{ "length", INT8OID, -1, 0);
snprintf(lenbuf, 30, INT64_FORMAT, (int64)fst.st_size); TupleDescInitEntry(tupdesc, (AttrNumber) 2,
"atime", TIMESTAMPTZOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 3,
"mtime", TIMESTAMPTZOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 4,
"ctime", TIMESTAMPTZOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 5,
"isdir", BOOLOID, -1, 0);
BlessTupleDesc(tupdesc);
values[0] = Int64GetDatum((int64) fst.st_size);
values[1] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_atime));
values[2] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_mtime));
values[3] = TimestampTzGetDatum(time_t_to_timestamptz(fst.st_ctime));
values[4] = BoolGetDatum(fst.st_mode & S_IFDIR);
memset(isnull, false, sizeof(isnull));
tuple = heap_form_tuple(tupdesc, values, isnull);
timestamp = fst.st_atime;
pg_strftime(abuf, 30, "%F %T", pg_localtime(&timestamp, global_timezone));
timestamp = fst.st_mtime;
pg_strftime(mbuf, 30, "%F %T", pg_localtime(&timestamp, global_timezone));
timestamp = fst.st_ctime;
pg_strftime(cbuf, 30, "%F %T", pg_localtime(&timestamp, global_timezone));
if (fst.st_mode & S_IFDIR)
strcpy(dirbuf, "t");
else
strcpy(dirbuf, "f");
tuple = BuildTupleFromCStrings(attinmeta, values);
pfree(filename); pfree(filename);
PG_RETURN_DATUM(HeapTupleGetDatum(tuple)); PG_RETURN_DATUM(HeapTupleGetDatum(tuple));
}
} }
Datum pg_ls_dir(PG_FUNCTION_ARGS) /*
* List a directory (returns the filenames only)
*/
Datum
pg_ls_dir(PG_FUNCTION_ARGS)
{ {
FuncCallContext *funcctx; FuncCallContext *funcctx;
struct dirent *de; struct dirent *de;
...@@ -227,7 +244,8 @@ Datum pg_ls_dir(PG_FUNCTION_ARGS) ...@@ -227,7 +244,8 @@ Datum pg_ls_dir(PG_FUNCTION_ARGS)
if (!fctx->dirdesc) if (!fctx->dirdesc)
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("%s is not browsable: %m", fctx->location))); errmsg("could not open directory \"%s\": %m",
fctx->location)));
funcctx->user_fctx = fctx; funcctx->user_fctx = fctx;
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
...@@ -236,17 +254,16 @@ Datum pg_ls_dir(PG_FUNCTION_ARGS) ...@@ -236,17 +254,16 @@ Datum pg_ls_dir(PG_FUNCTION_ARGS)
funcctx = SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
fctx = (directory_fctx*) funcctx->user_fctx; fctx = (directory_fctx*) funcctx->user_fctx;
if (!fctx->dirdesc) /* not a readable directory */
SRF_RETURN_DONE(funcctx);
while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL) while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
{ {
int len = strlen(de->d_name); int len = strlen(de->d_name);
text *result = palloc(len + VARHDRSZ); text *result;
if (strcmp(de->d_name, ".") == 0 || strcmp(de->d_name, "..") == 0) if (strcmp(de->d_name, ".") == 0 ||
strcmp(de->d_name, "..") == 0)
continue; continue;
result = palloc(len + VARHDRSZ);
VARATT_SIZEP(result) = len + VARHDRSZ; VARATT_SIZEP(result) = len + VARHDRSZ;
memcpy(VARDATA(result), de->d_name, len); memcpy(VARDATA(result), de->d_name, len);
...@@ -254,5 +271,6 @@ Datum pg_ls_dir(PG_FUNCTION_ARGS) ...@@ -254,5 +271,6 @@ Datum pg_ls_dir(PG_FUNCTION_ARGS)
} }
FreeDir(fctx->dirdesc); FreeDir(fctx->dirdesc);
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/misc.c,v 1.46 2005/08/12 03:24:08 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/misc.c,v 1.47 2005/08/12 18:23:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,26 +18,19 @@ ...@@ -18,26 +18,19 @@
#include <signal.h> #include <signal.h>
#include <dirent.h> #include <dirent.h>
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h" #include "commands/dbcommands.h"
#include "funcapi.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/procarray.h" #include "postmaster/syslogger.h"
#include "storage/pmsignal.h"
#include "storage/fd.h" #include "storage/fd.h"
#include "storage/pmsignal.h"
#include "storage/procarray.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/elog.h"
#include "funcapi.h"
#include "catalog/pg_type.h"
#include "catalog/pg_tablespace.h"
#include "postmaster/syslogger.h"
#define atooid(x) ((Oid) strtoul((x), NULL, 10)) #define atooid(x) ((Oid) strtoul((x), NULL, 10))
typedef struct
{
char *location;
DIR *dirdesc;
} directory_fctx;
/* /*
* Check if data is Null * Check if data is Null
...@@ -150,15 +143,15 @@ pg_rotate_logfile(PG_FUNCTION_ARGS) ...@@ -150,15 +143,15 @@ pg_rotate_logfile(PG_FUNCTION_ARGS)
if (!Redirect_stderr) if (!Redirect_stderr)
{ {
ereport(NOTICE, ereport(WARNING,
(errcode(ERRCODE_WARNING), (errmsg("rotation not possible because log redirection not active")));
errmsg("no logfile configured; rotation not supported")));
PG_RETURN_INT32(0); PG_RETURN_INT32(0);
} }
SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE); SendPostmasterSignal(PMSIGNAL_ROTATE_LOGFILE);
PG_RETURN_INT32(0); PG_RETURN_INT32(1);
} }
#ifdef NOT_USED #ifdef NOT_USED
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.147 2005/07/30 18:20:44 momjian Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/timestamp.c,v 1.148 2005/08/12 18:23:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -939,7 +939,7 @@ GetCurrentTimestamp(void) ...@@ -939,7 +939,7 @@ GetCurrentTimestamp(void)
gettimeofday(&tp, NULL); gettimeofday(&tp, NULL);
result = tp.tv_sec - result = (TimestampTz) tp.tv_sec -
((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY); ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
...@@ -951,6 +951,29 @@ GetCurrentTimestamp(void) ...@@ -951,6 +951,29 @@ GetCurrentTimestamp(void)
return result; return result;
} }
/*
* Convert a time_t to TimestampTz.
*
* We do not use time_t internally in Postgres, but this is provided for use
* by functions that need to interpret, say, a stat(2) result.
*/
TimestampTz
time_t_to_timestamptz(time_t tm)
{
TimestampTz result;
result = (TimestampTz) tm -
((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY);
#ifdef HAVE_INT64_TIMESTAMP
result *= USECS_PER_SEC;
#endif
return result;
}
void void
dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec) dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
{ {
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.296 2005/08/11 21:11:47 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.297 2005/08/12 18:23:55 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200508111 #define CATALOG_VERSION_NO 200508121
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.381 2005/08/12 03:24:22 momjian Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.382 2005/08/12 18:23:55 tgl Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -3058,12 +3058,12 @@ DESCR("Rotate log file"); ...@@ -3058,12 +3058,12 @@ DESCR("Rotate log file");
DATA(insert OID = 2623 ( pg_stat_file PGNSP PGUID 12 f f t f v 1 2249 "25" _null_ _null_ _null_ pg_stat_file - _null_ )); DATA(insert OID = 2623 ( pg_stat_file PGNSP PGUID 12 f f t f v 1 2249 "25" _null_ _null_ _null_ pg_stat_file - _null_ ));
DESCR("Return file information"); DESCR("Return file information");
DATA(insert OID = 2624 ( pg_file_length PGNSP PGUID 14 f f t f v 1 20 "25" _null_ _null_ _null_ "SELECT len FROM pg_stat_file($1) AS s(len int8, c timestamp, a timestamp, m timestamp, i bool)" - _null_ )); DATA(insert OID = 2624 ( pg_file_length PGNSP PGUID 14 f f t f v 1 20 "25" _null_ _null_ _null_ "SELECT len FROM pg_stat_file($1) AS s(len int8, a timestamptz, m timestamptz, c timestamptz, i bool)" - _null_ ));
DESCR("Return file length"); DESCR("Return file length");
DATA(insert OID = 2625 ( pg_read_file PGNSP PGUID 12 f f t f v 3 25 "25 20 20" _null_ _null_ _null_ pg_read_file - _null_ )); DATA(insert OID = 2625 ( pg_read_file PGNSP PGUID 12 f f t f v 3 25 "25 20 20" _null_ _null_ _null_ pg_read_file - _null_ ));
DESCR("Read text from a file"); DESCR("Read text from a file");
DATA(insert OID = 2626 ( pg_ls_dir PGNSP PGUID 12 f f t t v 1 25 "25" _null_ _null_ _null_ pg_ls_dir - _null_ )); DATA(insert OID = 2626 ( pg_ls_dir PGNSP PGUID 12 f f t t v 1 25 "25" _null_ _null_ _null_ pg_ls_dir - _null_ ));
DESCR("List all file in a directory"); DESCR("List all files in a directory");
/* Aggregates (moved here from pg_aggregate for 7.3) */ /* Aggregates (moved here from pg_aggregate for 7.3) */
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.53 2005/07/22 05:08:26 momjian Exp $ * $PostgreSQL: pgsql/src/include/utils/timestamp.h,v 1.54 2005/08/12 18:23:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -292,6 +292,8 @@ extern Datum pgsql_postmaster_start_time(PG_FUNCTION_ARGS); ...@@ -292,6 +292,8 @@ extern Datum pgsql_postmaster_start_time(PG_FUNCTION_ARGS);
extern TimestampTz GetCurrentTimestamp(void); extern TimestampTz GetCurrentTimestamp(void);
extern TimestampTz time_t_to_timestamptz(time_t tm);
extern int tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *dt); extern int tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *dt);
extern int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, extern int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm,
fsec_t *fsec, char **tzn, pg_tz *attimezone); fsec_t *fsec, char **tzn, pg_tz *attimezone);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment