Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit b0d8f2d

Browse files
committed
Add SHELL_ERROR and SHELL_EXIT_CODE magic variables to psql.
These are set after a \! command or a backtick substitution. SHELL_ERROR is just "true" for error (nonzero exit status) or "false" for success, while SHELL_EXIT_CODE records the actual exit status following standard shell/system(3) conventions. Corey Huinker, reviewed by Maxim Orlov and myself Discussion: https://postgr.es/m/CADkLM=cWao2x2f+UDw15W1JkVFr_bsxfstw=NGea7r9m4j-7rQ@mail.gmail.com
1 parent 0f85db9 commit b0d8f2d

File tree

6 files changed

+88
-3
lines changed

6 files changed

+88
-3
lines changed

doc/src/sgml/ref/psql-ref.sgml

+28
Original file line numberDiff line numberDiff line change
@@ -4267,6 +4267,34 @@ bar
42674267
</listitem>
42684268
</varlistentry>
42694269

4270+
<varlistentry id="app-psql-variables-shell-error">
4271+
<term><varname>SHELL_ERROR</varname></term>
4272+
<listitem>
4273+
<para>
4274+
<literal>true</literal> if the last shell command
4275+
failed, <literal>false</literal> if it succeeded.
4276+
This applies to shell commands invoked via the <literal>\!</literal>
4277+
meta-command or backquote (<literal>`</literal>) expansion.
4278+
See also <varname>SHELL_EXIT_CODE</varname>.
4279+
</para>
4280+
</listitem>
4281+
</varlistentry>
4282+
4283+
<varlistentry id="app-psql-variables-shell-exit-code">
4284+
<term><varname>SHELL_EXIT_CODE</varname></term>
4285+
<listitem>
4286+
<para>
4287+
The exit status returned by the last shell command.
4288+
0&ndash;127 represent program exit codes, 128&ndash;255
4289+
indicate termination by a signal, and -1 indicates failure
4290+
to launch a program or to collect its exit status.
4291+
This applies to shell commands invoked via the <literal>\!</literal>
4292+
meta-command or backquote (<literal>`</literal>) expansion.
4293+
See also <varname>SHELL_ERROR</varname>.
4294+
</para>
4295+
</listitem>
4296+
</varlistentry>
4297+
42704298
<varlistentry id="app-psql-variables-show-all-results">
42714299
<term><varname>SHOW_ALL_RESULTS</varname></term>
42724300
<listitem>

src/bin/psql/command.c

+15
Original file line numberDiff line numberDiff line change
@@ -5041,6 +5041,21 @@ do_shell(const char *command)
50415041
else
50425042
result = system(command);
50435043

5044+
if (result == 0)
5045+
{
5046+
SetVariable(pset.vars, "SHELL_EXIT_CODE", "0");
5047+
SetVariable(pset.vars, "SHELL_ERROR", "false");
5048+
}
5049+
else
5050+
{
5051+
int exit_code = wait_result_to_exit_code(result);
5052+
char buf[32];
5053+
5054+
snprintf(buf, sizeof(buf), "%d", exit_code);
5055+
SetVariable(pset.vars, "SHELL_EXIT_CODE", buf);
5056+
SetVariable(pset.vars, "SHELL_ERROR", "true");
5057+
}
5058+
50445059
if (result == 127 || result == -1)
50455060
{
50465061
pg_log_error("\\!: failed");

src/bin/psql/help.c

+4
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,10 @@ helpVariables(unsigned short int pager)
451451
HELP0(" SERVER_VERSION_NAME\n"
452452
" SERVER_VERSION_NUM\n"
453453
" server's version (in short string or numeric format)\n");
454+
HELP0(" SHELL_ERROR\n"
455+
" true if the last shell command failed, false if it succeeded\n");
456+
HELP0(" SHELL_EXIT_CODE\n"
457+
" exit status of the last shell command\n");
454458
HELP0(" SHOW_ALL_RESULTS\n"
455459
" show all results of a combined query (\\;) instead of only the last\n");
456460
HELP0(" SHOW_CONTEXT\n"

src/bin/psql/psqlscanslash.l

+21-3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "postgres_fe.h"
2020

2121
#include "psqlscanslash.h"
22+
#include "settings.h"
23+
2224
#include "common/logging.h"
2325
#include "fe_utils/conditional.h"
2426

@@ -772,6 +774,7 @@ evaluate_backtick(PsqlScanState state)
772774
PQExpBufferData cmd_output;
773775
FILE *fd;
774776
bool error = false;
777+
int exit_code = 0;
775778
char buf[512];
776779
size_t result;
777780

@@ -783,6 +786,7 @@ evaluate_backtick(PsqlScanState state)
783786
{
784787
pg_log_error("%s: %m", cmd);
785788
error = true;
789+
exit_code = -1;
786790
}
787791

788792
if (!error)
@@ -800,10 +804,19 @@ evaluate_backtick(PsqlScanState state)
800804
} while (!feof(fd));
801805
}
802806

803-
if (fd && pclose(fd) == -1)
807+
if (fd)
804808
{
805-
pg_log_error("%s: %m", cmd);
806-
error = true;
809+
/*
810+
* Although pclose's result always sets SHELL_EXIT_CODE, we
811+
* historically have abandoned the backtick substitution only if it
812+
* returns -1.
813+
*/
814+
exit_code = pclose(fd);
815+
if (exit_code == -1)
816+
{
817+
pg_log_error("%s: %m", cmd);
818+
error = true;
819+
}
807820
}
808821

809822
if (PQExpBufferDataBroken(cmd_output))
@@ -826,5 +839,10 @@ evaluate_backtick(PsqlScanState state)
826839
appendBinaryPQExpBuffer(output_buf, cmd_output.data, cmd_output.len);
827840
}
828841

842+
/* And finally, set the shell error variables */
843+
snprintf(buf, sizeof(buf), "%d", wait_result_to_exit_code(exit_code));
844+
SetVariable(pset.vars, "SHELL_EXIT_CODE", buf);
845+
SetVariable(pset.vars, "SHELL_ERROR", (exit_code == 0) ? "false" : "true");
846+
829847
termPQExpBuffer(&cmd_output);
830848
}

src/common/wait_error.c

+19
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,22 @@ wait_result_is_any_signal(int exit_status, bool include_command_not_found)
127127
return true;
128128
return false;
129129
}
130+
131+
/*
132+
* Return the shell exit code (normally 0 to 255) that corresponds to the
133+
* given wait status. The argument is a wait status as returned by wait(2)
134+
* or waitpid(2), which also applies to pclose(3) and system(3). To support
135+
* the latter two cases, we pass through "-1" unchanged.
136+
*/
137+
int
138+
wait_result_to_exit_code(int exit_status)
139+
{
140+
if (exit_status == -1)
141+
return -1; /* failure of pclose() or system() */
142+
if (WIFEXITED(exit_status))
143+
return WEXITSTATUS(exit_status);
144+
if (WIFSIGNALED(exit_status))
145+
return 128 + WTERMSIG(exit_status);
146+
/* On many systems, this is unreachable */
147+
return -1;
148+
}

src/include/port.h

+1
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,7 @@ extern char *escape_single_quotes_ascii(const char *src);
495495
extern char *wait_result_to_str(int exitstatus);
496496
extern bool wait_result_is_signal(int exit_status, int signum);
497497
extern bool wait_result_is_any_signal(int exit_status, bool include_command_not_found);
498+
extern int wait_result_to_exit_code(int exit_status);
498499

499500
/*
500501
* Interfaces that we assume all Unix system have. We retain individual macros

0 commit comments

Comments
 (0)