]> granicus.if.org Git - postgresql/blob - src/bin/psql/command.c
Add an officially exported libpq function to encrypt passwords, and
[postgresql] / src / bin / psql / command.c
1 /*
2  * psql - the PostgreSQL interactive terminal
3  *
4  * Copyright (c) 2000-2005, PostgreSQL Global Development Group
5  *
6  * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.157 2005/12/23 01:16:38 tgl Exp $
7  */
8 #include "postgres_fe.h"
9 #include "command.h"
10
11 #ifdef WIN32_CLIENT_ONLY                /* needed for BCC */
12 #undef mkdir
13 #endif
14
15 #include <ctype.h>
16 #ifdef HAVE_PWD_H
17 #include <pwd.h>
18 #endif
19 #ifndef WIN32
20 #include <sys/types.h>                  /* for umask() */
21 #include <sys/stat.h>                   /* for stat() */
22 #include <fcntl.h>                              /* open() flags */
23 #include <unistd.h>                             /* for geteuid(), getpid(), stat() */
24 #else
25 #include <win32.h>
26 #include <io.h>
27 #include <fcntl.h>
28 #include <direct.h>
29 #ifndef WIN32_CLIENT_ONLY
30 #include <sys/types.h>                  /* for umask() */
31 #include <sys/stat.h>                   /* for stat() */
32 #endif
33 #endif
34
35 #include "libpq-fe.h"
36 #include "pqexpbuffer.h"
37 #include "dumputils.h"
38
39 #include "common.h"
40 #include "copy.h"
41 #include "describe.h"
42 #include "help.h"
43 #include "input.h"
44 #include "large_obj.h"
45 #include "mainloop.h"
46 #include "print.h"
47 #include "psqlscan.h"
48 #include "settings.h"
49 #include "variables.h"
50 #include "mb/pg_wchar.h"
51
52
53 /* functions for use in this file */
54 static backslashResult exec_command(const char *cmd,
55                          PsqlScanState scan_state,
56                          PQExpBuffer query_buf);
57 static bool do_edit(const char *filename_arg, PQExpBuffer query_buf);
58 static bool do_connect(const char *new_dbname, const char *new_user);
59 static bool do_shell(const char *command);
60
61
62 /*----------
63  * HandleSlashCmds:
64  *
65  * Handles all the different commands that start with '\',
66  * ordinarily called by MainLoop().
67  *
68  * scan_state is a lexer working state that is set to continue scanning
69  * just after the '\'.  The lexer is advanced past the command and all
70  * arguments on return.
71  *
72  * 'query_buf' contains the query-so-far, which may be modified by
73  * execution of the backslash command (for example, \r clears it).
74  * query_buf can be NULL if there is no query so far.
75  *
76  * Returns a status code indicating what action is desired, see command.h.
77  *----------
78  */
79
80 backslashResult
81 HandleSlashCmds(PsqlScanState scan_state,
82                                 PQExpBuffer query_buf)
83 {
84         backslashResult status = PSQL_CMD_SKIP_LINE;
85         char       *cmd;
86         char       *arg;
87
88         psql_assert(scan_state);
89
90         /* Parse off the command name */
91         cmd = psql_scan_slash_command(scan_state);
92
93         /* And try to execute it */
94         status = exec_command(cmd, scan_state, query_buf);
95
96         if (status == PSQL_CMD_UNKNOWN && strlen(cmd) > 1)
97         {
98                 /*
99                  * If the command was not recognized, try to parse it as a one-letter
100                  * command with immediately following argument (a still-supported, but
101                  * no longer encouraged, syntax).
102                  */
103                 char            new_cmd[2];
104
105                 /* don't change cmd until we know it's okay */
106                 new_cmd[0] = cmd[0];
107                 new_cmd[1] = '\0';
108
109                 psql_scan_slash_pushback(scan_state, cmd + 1);
110
111                 status = exec_command(new_cmd, scan_state, query_buf);
112
113                 if (status != PSQL_CMD_UNKNOWN)
114                 {
115                         /* adjust cmd for possible messages below */
116                         cmd[1] = '\0';
117                 }
118         }
119
120         if (status == PSQL_CMD_UNKNOWN)
121         {
122                 if (pset.cur_cmd_interactive)
123                         fprintf(stderr, _("Invalid command \\%s. Try \\? for help.\n"), cmd);
124                 else
125                         psql_error("invalid command \\%s\n", cmd);
126                 status = PSQL_CMD_ERROR;
127         }
128
129         if (status != PSQL_CMD_ERROR)
130         {
131                 /* eat any remaining arguments after a valid command */
132                 /* note we suppress evaluation of backticks here */
133                 while ((arg = psql_scan_slash_option(scan_state,
134                                                                                          OT_VERBATIM, NULL, false)))
135                 {
136                         psql_error("\\%s: extra argument \"%s\" ignored\n", cmd, arg);
137                         free(arg);
138                 }
139         }
140         else
141         {
142                 /* silently throw away rest of line after an erroneous command */
143                 while ((arg = psql_scan_slash_option(scan_state,
144                                                                                          OT_WHOLE_LINE, NULL, false)))
145                         free(arg);
146         }
147
148         /* if there is a trailing \\, swallow it */
149         psql_scan_slash_command_end(scan_state);
150
151         free(cmd);
152
153         return status;
154 }
155
156 /*
157  * Subroutine to actually try to execute a backslash command.
158  */
159 static backslashResult
160 exec_command(const char *cmd,
161                          PsqlScanState scan_state,
162                          PQExpBuffer query_buf)
163 {
164         bool            success = true; /* indicate here if the command ran ok or
165                                                                  * failed */
166         bool            quiet = QUIET();
167         backslashResult status = PSQL_CMD_SKIP_LINE;
168
169         /*
170          * \a -- toggle field alignment This makes little sense but we keep it
171          * around.
172          */
173         if (strcmp(cmd, "a") == 0)
174         {
175                 if (pset.popt.topt.format != PRINT_ALIGNED)
176                         success = do_pset("format", "aligned", &pset.popt, quiet);
177                 else
178                         success = do_pset("format", "unaligned", &pset.popt, quiet);
179         }
180
181         /* \C -- override table title (formerly change HTML caption) */
182         else if (strcmp(cmd, "C") == 0)
183         {
184                 char       *opt = psql_scan_slash_option(scan_state,
185                                                                                                  OT_NORMAL, NULL, true);
186
187                 success = do_pset("title", opt, &pset.popt, quiet);
188                 free(opt);
189         }
190
191         /*----------
192          * \c or \connect -- connect to new database or as different user
193          *
194          * \c foo bar  connect to db "foo" as user "bar"
195          * \c foo [-]  connect to db "foo" as current user
196          * \c - bar    connect to current db as user "bar"
197          * \c              connect to default db as default user
198          *----------
199          */
200         else if (strcmp(cmd, "c") == 0 || strcmp(cmd, "connect") == 0)
201         {
202                 char       *opt1,
203                                    *opt2;
204                 char            opt1q,
205                                         opt2q;
206
207                 /*
208                  * Ideally we should treat the arguments as SQL identifiers.  But for
209                  * backwards compatibility with 7.2 and older pg_dump files, we have
210                  * to take unquoted arguments verbatim (don't downcase them). For now,
211                  * double-quoted arguments may be stripped of double quotes (as if SQL
212                  * identifiers).  By 7.4 or so, pg_dump files can be expected to
213                  * double-quote all mixed-case \connect arguments, and then we can get
214                  * rid of OT_SQLIDHACK.
215                  */
216                 opt1 = psql_scan_slash_option(scan_state,
217                                                                           OT_SQLIDHACK, &opt1q, true);
218                 opt2 = psql_scan_slash_option(scan_state,
219                                                                           OT_SQLIDHACK, &opt2q, true);
220
221                 if (opt2)
222                         /* gave username */
223                         success = do_connect(!opt1q && (strcmp(opt1, "-") == 0 || strcmp(opt1, "") == 0) ? "" : opt1,
224                                                                  !opt2q && (strcmp(opt2, "-") == 0 || strcmp(opt2, "") == 0) ? "" : opt2);
225                 else if (opt1)
226                         /* gave database name */
227                         success = do_connect(!opt1q && (strcmp(opt1, "-") == 0 || strcmp(opt1, "") == 0) ? "" : opt1, "");
228                 else
229                         /* connect to default db as default user */
230                         success = do_connect(NULL, NULL);
231
232                 free(opt1);
233                 free(opt2);
234         }
235
236         /* \cd */
237         else if (strcmp(cmd, "cd") == 0)
238         {
239                 char       *opt = psql_scan_slash_option(scan_state,
240                                                                                                  OT_NORMAL, NULL, true);
241                 char       *dir;
242
243                 if (opt)
244                         dir = opt;
245                 else
246                 {
247 #ifndef WIN32
248                         struct passwd *pw;
249
250                         pw = getpwuid(geteuid());
251                         if (!pw)
252                         {
253                                 psql_error("could not get home directory: %s\n", strerror(errno));
254                                 exit(EXIT_FAILURE);
255                         }
256                         dir = pw->pw_dir;
257 #else                                                   /* WIN32 */
258
259                         /*
260                          * On Windows, 'cd' without arguments prints the current
261                          * directory, so if someone wants to code this here instead...
262                          */
263                         dir = "/";
264 #endif   /* WIN32 */
265                 }
266
267                 if (chdir(dir) == -1)
268                 {
269                         psql_error("\\%s: could not change directory to \"%s\": %s\n",
270                                            cmd, dir, strerror(errno));
271                         success = false;
272                 }
273
274                 if (pset.dirname)
275                         pfree(pset.dirname);
276                 pset.dirname = pg_strdup(dir);
277                 canonicalize_path(pset.dirname);
278
279                 if (opt)
280                         free(opt);
281         }
282
283         /* \copy */
284         else if (pg_strcasecmp(cmd, "copy") == 0)
285         {
286                 char       *opt = psql_scan_slash_option(scan_state,
287                                                                                                  OT_WHOLE_LINE, NULL, false);
288
289                 success = do_copy(opt);
290                 free(opt);
291         }
292
293         /* \copyright */
294         else if (strcmp(cmd, "copyright") == 0)
295                 print_copyright();
296
297         /* \d* commands */
298         else if (cmd[0] == 'd')
299         {
300                 char       *pattern;
301                 bool            show_verbose;
302
303                 /* We don't do SQLID reduction on the pattern yet */
304                 pattern = psql_scan_slash_option(scan_state,
305                                                                                  OT_NORMAL, NULL, true);
306
307                 show_verbose = strchr(cmd, '+') ? true : false;
308
309                 switch (cmd[1])
310                 {
311                         case '\0':
312                         case '+':
313                                 if (pattern)
314                                         success = describeTableDetails(pattern, show_verbose);
315                                 else
316                                         /* standard listing of interesting things */
317                                         success = listTables("tvs", NULL, show_verbose);
318                                 break;
319                         case 'a':
320                                 success = describeAggregates(pattern, show_verbose);
321                                 break;
322                         case 'b':
323                                 success = describeTablespaces(pattern, show_verbose);
324                                 break;
325                         case 'c':
326                                 success = listConversions(pattern);
327                                 break;
328                         case 'C':
329                                 success = listCasts(pattern);
330                                 break;
331                         case 'd':
332                                 success = objectDescription(pattern);
333                                 break;
334                         case 'D':
335                                 success = listDomains(pattern);
336                                 break;
337                         case 'f':
338                                 success = describeFunctions(pattern, show_verbose);
339                                 break;
340                         case 'g':
341                                 /* no longer distinct from \du */
342                                 success = describeRoles(pattern);
343                                 break;
344                         case 'l':
345                                 success = do_lo_list();
346                                 break;
347                         case 'n':
348                                 success = listSchemas(pattern, show_verbose);
349                                 break;
350                         case 'o':
351                                 success = describeOperators(pattern);
352                                 break;
353                         case 'p':
354                                 success = permissionsList(pattern);
355                                 break;
356                         case 'T':
357                                 success = describeTypes(pattern, show_verbose);
358                                 break;
359                         case 't':
360                         case 'v':
361                         case 'i':
362                         case 's':
363                         case 'S':
364                                 success = listTables(&cmd[1], pattern, show_verbose);
365                                 break;
366                         case 'u':
367                                 success = describeRoles(pattern);
368                                 break;
369
370                         default:
371                                 status = PSQL_CMD_UNKNOWN;
372                 }
373
374                 if (pattern)
375                         free(pattern);
376         }
377
378
379         /*
380          * \e or \edit -- edit the current query buffer (or a file and make it the
381          * query buffer
382          */
383         else if (strcmp(cmd, "e") == 0 || strcmp(cmd, "edit") == 0)
384         {
385                 char       *fname;
386
387                 if (!query_buf)
388                 {
389                         psql_error("no query buffer\n");
390                         status = PSQL_CMD_ERROR;
391                 }
392                 else
393                 {
394                         fname = psql_scan_slash_option(scan_state,
395                                                                                    OT_NORMAL, NULL, true);
396                         expand_tilde(&fname);
397                         if (fname)
398                                 canonicalize_path(fname);
399                         status = do_edit(fname, query_buf) ? PSQL_CMD_NEWEDIT : PSQL_CMD_ERROR;
400                         free(fname);
401                 }
402         }
403
404         /* \echo and \qecho */
405         else if (strcmp(cmd, "echo") == 0 || strcmp(cmd, "qecho") == 0)
406         {
407                 char       *value;
408                 char            quoted;
409                 bool            no_newline = false;
410                 bool            first = true;
411                 FILE       *fout;
412
413                 if (strcmp(cmd, "qecho") == 0)
414                         fout = pset.queryFout;
415                 else
416                         fout = stdout;
417
418                 while ((value = psql_scan_slash_option(scan_state,
419                                                                                            OT_NORMAL, &quoted, false)))
420                 {
421                         if (!quoted && strcmp(value, "-n") == 0)
422                                 no_newline = true;
423                         else
424                         {
425                                 if (first)
426                                         first = false;
427                                 else
428                                         fputc(' ', fout);
429                                 fputs(value, fout);
430                         }
431                         free(value);
432                 }
433                 if (!no_newline)
434                         fputs("\n", fout);
435         }
436
437         /* \encoding -- set/show client side encoding */
438         else if (strcmp(cmd, "encoding") == 0)
439         {
440                 char       *encoding = psql_scan_slash_option(scan_state,
441                                                                                                           OT_NORMAL, NULL, false);
442
443                 if (!encoding)
444                 {
445                         /* show encoding */
446                         puts(pg_encoding_to_char(pset.encoding));
447                 }
448                 else
449                 {
450                         /* set encoding */
451                         if (PQsetClientEncoding(pset.db, encoding) == -1)
452                                 psql_error("%s: invalid encoding name or conversion procedure not found\n", encoding);
453                         else
454                         {
455                                 /* save encoding info into psql internal data */
456                                 pset.encoding = PQclientEncoding(pset.db);
457                                 pset.popt.topt.encoding = pset.encoding;
458                                 SetVariable(pset.vars, "ENCODING",
459                                                         pg_encoding_to_char(pset.encoding));
460                         }
461                         free(encoding);
462                 }
463         }
464
465         /* \f -- change field separator */
466         else if (strcmp(cmd, "f") == 0)
467         {
468                 char       *fname = psql_scan_slash_option(scan_state,
469                                                                                                    OT_NORMAL, NULL, false);
470
471                 success = do_pset("fieldsep", fname, &pset.popt, quiet);
472                 free(fname);
473         }
474
475         /* \g means send query */
476         else if (strcmp(cmd, "g") == 0)
477         {
478                 char       *fname = psql_scan_slash_option(scan_state,
479                                                                                                    OT_FILEPIPE, NULL, false);
480
481                 if (!fname)
482                         pset.gfname = NULL;
483                 else
484                 {
485                         expand_tilde(&fname);
486                         pset.gfname = pg_strdup(fname);
487                 }
488                 free(fname);
489                 status = PSQL_CMD_SEND;
490         }
491
492         /* help */
493         else if (strcmp(cmd, "h") == 0 || strcmp(cmd, "help") == 0)
494         {
495                 char       *opt = psql_scan_slash_option(scan_state,
496                                                                                                  OT_WHOLE_LINE, NULL, false);
497
498                 helpSQL(opt, pset.popt.topt.pager);
499                 free(opt);
500         }
501
502         /* HTML mode */
503         else if (strcmp(cmd, "H") == 0 || strcmp(cmd, "html") == 0)
504         {
505                 if (pset.popt.topt.format != PRINT_HTML)
506                         success = do_pset("format", "html", &pset.popt, quiet);
507                 else
508                         success = do_pset("format", "aligned", &pset.popt, quiet);
509         }
510
511
512         /* \i is include file */
513         else if (strcmp(cmd, "i") == 0 || strcmp(cmd, "include") == 0)
514         {
515                 char       *fname = psql_scan_slash_option(scan_state,
516                                                                                                    OT_NORMAL, NULL, true);
517
518                 if (!fname)
519                 {
520                         psql_error("\\%s: missing required argument\n", cmd);
521                         success = false;
522                 }
523                 else
524                 {
525                         expand_tilde(&fname);
526                         success = (process_file(fname) == EXIT_SUCCESS);
527                         free(fname);
528                 }
529         }
530
531         /* \l is list databases */
532         else if (strcmp(cmd, "l") == 0 || strcmp(cmd, "list") == 0)
533                 success = listAllDbs(false);
534         else if (strcmp(cmd, "l+") == 0 || strcmp(cmd, "list+") == 0)
535                 success = listAllDbs(true);
536
537         /*
538          * large object things
539          */
540         else if (strncmp(cmd, "lo_", 3) == 0)
541         {
542                 char       *opt1,
543                                    *opt2;
544
545                 opt1 = psql_scan_slash_option(scan_state,
546                                                                           OT_NORMAL, NULL, true);
547                 opt2 = psql_scan_slash_option(scan_state,
548                                                                           OT_NORMAL, NULL, true);
549
550                 if (strcmp(cmd + 3, "export") == 0)
551                 {
552                         if (!opt2)
553                         {
554                                 psql_error("\\%s: missing required argument\n", cmd);
555                                 success = false;
556                         }
557                         else
558                         {
559                                 expand_tilde(&opt2);
560                                 success = do_lo_export(opt1, opt2);
561                         }
562                 }
563
564                 else if (strcmp(cmd + 3, "import") == 0)
565                 {
566                         if (!opt1)
567                         {
568                                 psql_error("\\%s: missing required argument\n", cmd);
569                                 success = false;
570                         }
571                         else
572                         {
573                                 expand_tilde(&opt1);
574                                 success = do_lo_import(opt1, opt2);
575                         }
576                 }
577
578                 else if (strcmp(cmd + 3, "list") == 0)
579                         success = do_lo_list();
580
581                 else if (strcmp(cmd + 3, "unlink") == 0)
582                 {
583                         if (!opt1)
584                         {
585                                 psql_error("\\%s: missing required argument\n", cmd);
586                                 success = false;
587                         }
588                         else
589                                 success = do_lo_unlink(opt1);
590                 }
591
592                 else
593                         status = PSQL_CMD_UNKNOWN;
594
595                 free(opt1);
596                 free(opt2);
597         }
598
599
600         /* \o -- set query output */
601         else if (strcmp(cmd, "o") == 0 || strcmp(cmd, "out") == 0)
602         {
603                 char       *fname = psql_scan_slash_option(scan_state,
604                                                                                                    OT_FILEPIPE, NULL, true);
605
606                 expand_tilde(&fname);
607                 success = setQFout(fname);
608                 free(fname);
609         }
610
611         /* \p prints the current query buffer */
612         else if (strcmp(cmd, "p") == 0 || strcmp(cmd, "print") == 0)
613         {
614                 if (query_buf && query_buf->len > 0)
615                         puts(query_buf->data);
616                 else if (!quiet)
617                         puts(_("Query buffer is empty."));
618                 fflush(stdout);
619         }
620
621         /* \password -- set user password */
622         else if (strcmp(cmd, "password") == 0)
623         {
624                 char       *pw1;
625                 char       *pw2;
626
627                 pw1 = simple_prompt("Enter new password: ", 100, false);
628                 pw2 = simple_prompt("Enter it again: ", 100, false);
629
630                 if (strcmp(pw1, pw2) != 0)
631                 {
632                         fprintf(stderr, _("Passwords didn't match.\n"));
633                         success = false;
634                 }
635                 else
636                 {
637                         char       *opt0 = psql_scan_slash_option(scan_state, OT_SQLID, NULL, true);
638                         char       *user;
639                         char       *encrypted_password;
640
641                         if (opt0)
642                                 user = opt0;
643                         else
644                                 user = PQuser(pset.db);
645
646                         encrypted_password = pg_make_encrypted_password(pw1, user);
647
648                         if (!encrypted_password)
649                         {
650                                 fprintf(stderr, _("Password encryption failed.\n"));
651                                 success = false;
652                         }
653                         else
654                         {
655                                 PQExpBufferData buf;
656                                 PGresult   *res;
657
658                                 initPQExpBuffer(&buf);
659                                 printfPQExpBuffer(&buf, "ALTER USER %s PASSWORD '%s';",
660                                                                   fmtId(user), encrypted_password);
661                                 res = PSQLexec(buf.data, false);
662                                 termPQExpBuffer(&buf);
663                                 if (!res)
664                                         success = false;
665                                 else
666                                         PQclear(res);
667                                 PQfreemem(encrypted_password);
668                         }
669                 }
670
671                 free(pw1);
672                 free(pw2);
673         }
674
675         /* \pset -- set printing parameters */
676         else if (strcmp(cmd, "pset") == 0)
677         {
678                 char       *opt0 = psql_scan_slash_option(scan_state,
679                                                                                                   OT_NORMAL, NULL, false);
680                 char       *opt1 = psql_scan_slash_option(scan_state,
681                                                                                                   OT_NORMAL, NULL, false);
682
683                 if (!opt0)
684                 {
685                         psql_error("\\%s: missing required argument\n", cmd);
686                         success = false;
687                 }
688                 else
689                         success = do_pset(opt0, opt1, &pset.popt, quiet);
690
691                 free(opt0);
692                 free(opt1);
693         }
694
695         /* \q or \quit */
696         else if (strcmp(cmd, "q") == 0 || strcmp(cmd, "quit") == 0)
697                 status = PSQL_CMD_TERMINATE;
698
699         /* reset(clear) the buffer */
700         else if (strcmp(cmd, "r") == 0 || strcmp(cmd, "reset") == 0)
701         {
702                 resetPQExpBuffer(query_buf);
703                 psql_scan_reset(scan_state);
704                 if (!quiet)
705                         puts(_("Query buffer reset (cleared)."));
706         }
707
708         /* \s save history in a file or show it on the screen */
709         else if (strcmp(cmd, "s") == 0)
710         {
711                 char       *fname = psql_scan_slash_option(scan_state,
712                                                                                                    OT_NORMAL, NULL, true);
713
714                 expand_tilde(&fname);
715                 /* This scrolls off the screen when using /dev/tty */
716                 success = saveHistory(fname ? fname : "/dev/tty");
717
718                 if (success && !quiet && fname)
719                         printf(gettext("Wrote history to file \"%s/%s\".\n"),
720                                    pset.dirname ? pset.dirname : ".", fname);
721                 if (!fname)
722                         putchar('\n');
723                 free(fname);
724         }
725
726         /* \set -- generalized set variable/option command */
727         else if (strcmp(cmd, "set") == 0)
728         {
729                 char       *opt0 = psql_scan_slash_option(scan_state,
730                                                                                                   OT_NORMAL, NULL, false);
731
732                 if (!opt0)
733                 {
734                         /* list all variables */
735                         PrintVariables(pset.vars);
736                         success = true;
737                 }
738                 else
739                 {
740                         /*
741                          * Set variable to the concatenation of the arguments.
742                          */
743                         char       *newval;
744                         char       *opt;
745
746                         opt = psql_scan_slash_option(scan_state,
747                                                                                  OT_NORMAL, NULL, false);
748                         newval = pg_strdup(opt ? opt : "");
749                         free(opt);
750
751                         while ((opt = psql_scan_slash_option(scan_state,
752                                                                                                  OT_NORMAL, NULL, false)))
753                         {
754                                 newval = realloc(newval, strlen(newval) + strlen(opt) + 1);
755                                 if (!newval)
756                                 {
757                                         psql_error("out of memory\n");
758                                         exit(EXIT_FAILURE);
759                                 }
760                                 strcat(newval, opt);
761                                 free(opt);
762                         }
763
764                         if (SetVariable(pset.vars, opt0, newval))
765                         {
766                                 /* Check for special variables */
767                                 if (strcmp(opt0, "VERBOSITY") == 0)
768                                         SyncVerbosityVariable();
769                         }
770                         else
771                         {
772                                 psql_error("\\%s: error\n", cmd);
773                                 success = false;
774                         }
775                         free(newval);
776                 }
777                 free(opt0);
778         }
779
780         /* \t -- turn off headers and row count */
781         else if (strcmp(cmd, "t") == 0)
782                 success = do_pset("tuples_only", NULL, &pset.popt, quiet);
783
784
785         /* \T -- define html <table ...> attributes */
786         else if (strcmp(cmd, "T") == 0)
787         {
788                 char       *value = psql_scan_slash_option(scan_state,
789                                                                                                    OT_NORMAL, NULL, false);
790
791                 success = do_pset("tableattr", value, &pset.popt, quiet);
792                 free(value);
793         }
794
795         /* \timing -- toggle timing of queries */
796         else if (strcmp(cmd, "timing") == 0)
797         {
798                 pset.timing = !pset.timing;
799                 if (!quiet)
800                 {
801                         if (pset.timing)
802                                 puts(_("Timing is on."));
803                         else
804                                 puts(_("Timing is off."));
805                 }
806         }
807
808         /* \unset */
809         else if (strcmp(cmd, "unset") == 0)
810         {
811                 char       *opt = psql_scan_slash_option(scan_state,
812                                                                                                  OT_NORMAL, NULL, false);
813
814                 if (!opt)
815                 {
816                         psql_error("\\%s: missing required argument\n", cmd);
817                         success = false;
818                 }
819                 else if (!SetVariable(pset.vars, opt, NULL))
820                 {
821                         psql_error("\\%s: error\n", cmd);
822                         success = false;
823                 }
824                 free(opt);
825         }
826
827         /* \w -- write query buffer to file */
828         else if (strcmp(cmd, "w") == 0 || strcmp(cmd, "write") == 0)
829         {
830                 FILE       *fd = NULL;
831                 bool            is_pipe = false;
832                 char       *fname = NULL;
833
834                 if (!query_buf)
835                 {
836                         psql_error("no query buffer\n");
837                         status = PSQL_CMD_ERROR;
838                 }
839                 else
840                 {
841                         fname = psql_scan_slash_option(scan_state,
842                                                                                    OT_FILEPIPE, NULL, true);
843                         expand_tilde(&fname);
844
845                         if (!fname)
846                         {
847                                 psql_error("\\%s: missing required argument\n", cmd);
848                                 success = false;
849                         }
850                         else
851                         {
852                                 if (fname[0] == '|')
853                                 {
854                                         is_pipe = true;
855                                         fd = popen(&fname[1], "w");
856                                 }
857                                 else
858                                 {
859                                         canonicalize_path(fname);
860                                         fd = fopen(fname, "w");
861                                 }
862                                 if (!fd)
863                                 {
864                                         psql_error("%s: %s\n", fname, strerror(errno));
865                                         success = false;
866                                 }
867                         }
868                 }
869
870                 if (fd)
871                 {
872                         int                     result;
873
874                         if (query_buf && query_buf->len > 0)
875                                 fprintf(fd, "%s\n", query_buf->data);
876
877                         if (is_pipe)
878                                 result = pclose(fd);
879                         else
880                                 result = fclose(fd);
881
882                         if (result == EOF)
883                         {
884                                 psql_error("%s: %s\n", fname, strerror(errno));
885                                 success = false;
886                         }
887                 }
888
889                 free(fname);
890         }
891
892         /* \x -- toggle expanded table representation */
893         else if (strcmp(cmd, "x") == 0)
894                 success = do_pset("expanded", NULL, &pset.popt, quiet);
895
896         /* \z -- list table rights (equivalent to \dp) */
897         else if (strcmp(cmd, "z") == 0)
898         {
899                 char       *pattern = psql_scan_slash_option(scan_state,
900                                                                                                          OT_NORMAL, NULL, true);
901
902                 success = permissionsList(pattern);
903                 if (pattern)
904                         free(pattern);
905         }
906
907         /* \! -- shell escape */
908         else if (strcmp(cmd, "!") == 0)
909         {
910                 char       *opt = psql_scan_slash_option(scan_state,
911                                                                                                  OT_WHOLE_LINE, NULL, false);
912
913                 success = do_shell(opt);
914                 free(opt);
915         }
916
917         /* \? -- slash command help */
918         else if (strcmp(cmd, "?") == 0)
919                 slashUsage(pset.popt.topt.pager);
920
921 #if 0
922
923         /*
924          * These commands don't do anything. I just use them to test the parser.
925          */
926         else if (strcmp(cmd, "void") == 0 || strcmp(cmd, "#") == 0)
927         {
928                 int                     i = 0;
929                 char       *value;
930
931                 while ((value = psql_scan_slash_option(scan_state,
932                                                                                            OT_NORMAL, NULL, true)))
933                 {
934                         fprintf(stderr, "+ opt(%d) = |%s|\n", i++, value);
935                         free(value);
936                 }
937         }
938 #endif
939
940         else
941                 status = PSQL_CMD_UNKNOWN;
942
943         if (!success)
944                 status = PSQL_CMD_ERROR;
945
946         return status;
947 }
948
949
950
951 /* do_connect
952  * -- handler for \connect
953  *
954  * Connects to a database (new_dbname) as a certain user (new_user).
955  * The new user can be NULL. A db name of "-" is the same as the old one.
956  * (That is, the one currently in pset. But pset.db can also be NULL. A NULL
957  * dbname is handled by libpq.)
958  * Returns true if all ok, false if the new connection couldn't be established.
959  * The old connection will be kept if the session is interactive.
960  */
961 static bool
962 do_connect(const char *new_dbname, const char *new_user)
963 {
964         PGconn     *oldconn = pset.db;
965         const char *dbparam = NULL;
966         const char *userparam = NULL;
967         const char *pwparam = NULL;
968         char       *password_prompt = NULL;
969         char       *prompted_password = NULL;
970         bool            need_pass;
971         bool            success = false;
972
973         /* Delete variables (in case we fail before setting them anew) */
974         UnsyncVariables();
975
976         /* If dbname is "" then use old name, else new one (even if NULL) */
977         if (oldconn && new_dbname && PQdb(oldconn) && strcmp(new_dbname, "") == 0)
978                 dbparam = PQdb(oldconn);
979         else
980                 dbparam = new_dbname;
981
982         /* If user is "" then use the old one */
983         if (new_user && PQuser(oldconn) && strcmp(new_user, "") == 0)
984                 userparam = PQuser(oldconn);
985         else
986                 userparam = new_user;
987
988         if (userparam == NULL)
989                 password_prompt = strdup("Password: ");
990         else
991         {
992                 password_prompt = malloc(strlen(_("Password for user %s: ")) - 2 +
993                                                                  strlen(userparam) + 1);
994                 sprintf(password_prompt, _("Password for user %s: "), userparam);
995         }
996
997         /* need to prompt for password? */
998         if (pset.getPassword)
999                 pwparam = prompted_password = simple_prompt(password_prompt, 100, false);
1000
1001         /*
1002          * Use old password (if any) if no new one given and we are reconnecting
1003          * as same user
1004          */
1005         if (!pwparam && oldconn && PQuser(oldconn) && userparam &&
1006                 strcmp(PQuser(oldconn), userparam) == 0)
1007                 pwparam = PQpass(oldconn);
1008
1009         do
1010         {
1011                 need_pass = false;
1012                 pset.db = PQsetdbLogin(PQhost(oldconn), PQport(oldconn),
1013                                                            NULL, NULL, dbparam, userparam, pwparam);
1014
1015                 if (PQstatus(pset.db) == CONNECTION_BAD &&
1016                         strcmp(PQerrorMessage(pset.db), PQnoPasswordSupplied) == 0 &&
1017                         !feof(stdin))
1018                 {
1019                         PQfinish(pset.db);
1020                         need_pass = true;
1021                         free(prompted_password);
1022                         prompted_password = NULL;
1023                         pwparam = prompted_password = simple_prompt(password_prompt, 100, false);
1024                 }
1025         } while (need_pass);
1026
1027         free(prompted_password);
1028         free(password_prompt);
1029
1030         /*
1031          * If connection failed, try at least keep the old one. That's probably
1032          * more convenient than just kicking you out of the program.
1033          */
1034         if (!pset.db || PQstatus(pset.db) == CONNECTION_BAD)
1035         {
1036                 if (pset.cur_cmd_interactive)
1037                 {
1038                         psql_error("%s", PQerrorMessage(pset.db));
1039                         PQfinish(pset.db);
1040                         if (oldconn)
1041                         {
1042                                 fputs(_("Previous connection kept\n"), stderr);
1043                                 pset.db = oldconn;
1044                         }
1045                         else
1046                                 pset.db = NULL;
1047                 }
1048                 else
1049                 {
1050                         /*
1051                          * we don't want unpredictable things to happen in scripting mode
1052                          */
1053                         psql_error("\\connect: %s", PQerrorMessage(pset.db));
1054                         PQfinish(pset.db);
1055                         if (oldconn)
1056                                 PQfinish(oldconn);
1057                         pset.db = NULL;
1058                 }
1059         }
1060         else
1061         {
1062                 if (!QUIET())
1063                 {
1064                         if (userparam != new_user)      /* no new user */
1065                                 printf(_("You are now connected to database \"%s\".\n"), dbparam);
1066                         else if (dbparam != new_dbname)         /* no new db */
1067                                 printf(_("You are now connected as new user \"%s\".\n"), new_user);
1068                         else
1069                                 /* both new */
1070                                 printf(_("You are now connected to database \"%s\" as user \"%s\".\n"),
1071                                            PQdb(pset.db), PQuser(pset.db));
1072                 }
1073
1074                 if (oldconn)
1075                         PQfinish(oldconn);
1076
1077                 success = true;
1078         }
1079
1080         PQsetNoticeProcessor(pset.db, NoticeProcessor, NULL);
1081
1082         /* Update variables */
1083         SyncVariables();
1084
1085         return success;
1086 }
1087
1088
1089 /*
1090  * SyncVariables
1091  *
1092  * Make psql's internal variables agree with connection state upon
1093  * establishing a new connection.
1094  */
1095 void
1096 SyncVariables(void)
1097 {
1098         /* get stuff from connection */
1099         pset.encoding = PQclientEncoding(pset.db);
1100         pset.popt.topt.encoding = pset.encoding;
1101
1102         SetVariable(pset.vars, "DBNAME", PQdb(pset.db));
1103         SetVariable(pset.vars, "USER", PQuser(pset.db));
1104         SetVariable(pset.vars, "HOST", PQhost(pset.db));
1105         SetVariable(pset.vars, "PORT", PQport(pset.db));
1106         SetVariable(pset.vars, "ENCODING", pg_encoding_to_char(pset.encoding));
1107
1108         /* send stuff to it, too */
1109         SyncVerbosityVariable();
1110 }
1111
1112 /*
1113  * UnsyncVariables
1114  *
1115  * Clear variables that should be not be set when there is no connection.
1116  */
1117 void
1118 UnsyncVariables(void)
1119 {
1120         SetVariable(pset.vars, "DBNAME", NULL);
1121         SetVariable(pset.vars, "USER", NULL);
1122         SetVariable(pset.vars, "HOST", NULL);
1123         SetVariable(pset.vars, "PORT", NULL);
1124         SetVariable(pset.vars, "ENCODING", NULL);
1125 }
1126
1127 /*
1128  * Update connection state from VERBOSITY variable
1129  */
1130 void
1131 SyncVerbosityVariable(void)
1132 {
1133         switch (SwitchVariable(pset.vars, "VERBOSITY",
1134                                                    "default", "terse", "verbose", NULL))
1135         {
1136                 case 1:                 /* default */
1137                         pset.verbosity = PQERRORS_DEFAULT;
1138                         break;
1139                 case 2:                 /* terse */
1140                         pset.verbosity = PQERRORS_TERSE;
1141                         break;
1142                 case 3:                 /* verbose */
1143                         pset.verbosity = PQERRORS_VERBOSE;
1144                         break;
1145                 default:                                /* not set or unrecognized value */
1146                         pset.verbosity = PQERRORS_DEFAULT;
1147                         break;
1148         }
1149
1150         PQsetErrorVerbosity(pset.db, pset.verbosity);
1151 }
1152
1153
1154 /*
1155  * do_edit -- handler for \e
1156  *
1157  * If you do not specify a filename, the current query buffer will be copied
1158  * into a temporary one.
1159  */
1160
1161 static bool
1162 editFile(const char *fname)
1163 {
1164         const char *editorName;
1165         char       *sys;
1166         int                     result;
1167
1168         psql_assert(fname);
1169
1170         /* Find an editor to use */
1171         editorName = getenv("PSQL_EDITOR");
1172         if (!editorName)
1173                 editorName = getenv("EDITOR");
1174         if (!editorName)
1175                 editorName = getenv("VISUAL");
1176         if (!editorName)
1177                 editorName = DEFAULT_EDITOR;
1178
1179         /*
1180          * On Unix the EDITOR value should *not* be quoted, since it might include
1181          * switches, eg, EDITOR="pico -t"; it's up to the user to put quotes in it
1182          * if necessary.  But this policy is not very workable on Windows, due to
1183          * severe brain damage in their command shell plus the fact that standard
1184          * program paths include spaces.
1185          */
1186         sys = pg_malloc(strlen(editorName) + strlen(fname) + 10 + 1);
1187 #ifndef WIN32
1188         sprintf(sys, "exec %s '%s'", editorName, fname);
1189 #else
1190         sprintf(sys, "%s\"%s\" \"%s\"%s",
1191                         SYSTEMQUOTE, editorName, fname, SYSTEMQUOTE);
1192 #endif
1193         result = system(sys);
1194         if (result == -1)
1195                 psql_error("could not start editor \"%s\"\n", editorName);
1196         else if (result == 127)
1197                 psql_error("could not start /bin/sh\n");
1198         free(sys);
1199
1200         return result == 0;
1201 }
1202
1203
1204 /* call this one */
1205 static bool
1206 do_edit(const char *filename_arg, PQExpBuffer query_buf)
1207 {
1208         char            fnametmp[MAXPGPATH];
1209         FILE       *stream = NULL;
1210         const char *fname;
1211         bool            error = false;
1212         int                     fd;
1213
1214 #ifndef WIN32_CLIENT_ONLY
1215         struct stat before,
1216                                 after;
1217 #endif
1218
1219         if (filename_arg)
1220                 fname = filename_arg;
1221         else
1222         {
1223                 /* make a temp file to edit */
1224 #ifndef WIN32
1225                 const char *tmpdir = getenv("TMPDIR");
1226
1227                 if (!tmpdir)
1228                         tmpdir = "/tmp";
1229 #else
1230                 char            tmpdir[MAXPGPATH];
1231                 int                     ret;
1232
1233                 ret = GetTempPath(MAXPGPATH, tmpdir);
1234                 if (ret == 0 || ret > MAXPGPATH)
1235                 {
1236                         psql_error("cannot locate temporary directory: %s",
1237                                            !ret ? strerror(errno) : "");
1238                         return false;
1239                 }
1240
1241                 /*
1242                  * No canonicalize_path() here. EDIT.EXE run from CMD.EXE prepends the
1243                  * current directory to the supplied path unless we use only
1244                  * backslashes, so we do that.
1245                  */
1246 #endif
1247 #ifndef WIN32
1248                 snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d", tmpdir,
1249                                  "/", (int) getpid());
1250 #else
1251                 snprintf(fnametmp, sizeof(fnametmp), "%s%spsql.edit.%d", tmpdir,
1252                            "" /* trailing separator already present */ , (int) getpid());
1253 #endif
1254
1255                 fname = (const char *) fnametmp;
1256
1257                 fd = open(fname, O_WRONLY | O_CREAT | O_EXCL, 0600);
1258                 if (fd != -1)
1259                         stream = fdopen(fd, "w");
1260
1261                 if (fd == -1 || !stream)
1262                 {
1263                         psql_error("could not open temporary file \"%s\": %s\n", fname, strerror(errno));
1264                         error = true;
1265                 }
1266                 else
1267                 {
1268                         unsigned int ql = query_buf->len;
1269
1270                         if (ql == 0 || query_buf->data[ql - 1] != '\n')
1271                         {
1272                                 appendPQExpBufferChar(query_buf, '\n');
1273                                 ql++;
1274                         }
1275
1276                         if (fwrite(query_buf->data, 1, ql, stream) != ql)
1277                         {
1278                                 psql_error("%s: %s\n", fname, strerror(errno));
1279                                 fclose(stream);
1280                                 remove(fname);
1281                                 error = true;
1282                         }
1283                         else if (fclose(stream) != 0)
1284                         {
1285                                 psql_error("%s: %s\n", fname, strerror(errno));
1286                                 remove(fname);
1287                                 error = true;
1288                         }
1289                 }
1290         }
1291
1292 #ifndef WIN32_CLIENT_ONLY
1293         if (!error && stat(fname, &before) != 0)
1294         {
1295                 psql_error("%s: %s\n", fname, strerror(errno));
1296                 error = true;
1297         }
1298 #endif
1299
1300         /* call editor */
1301         if (!error)
1302                 error = !editFile(fname);
1303
1304 #ifndef WIN32_CLIENT_ONLY
1305         if (!error && stat(fname, &after) != 0)
1306         {
1307                 psql_error("%s: %s\n", fname, strerror(errno));
1308                 error = true;
1309         }
1310
1311         if (!error && before.st_mtime != after.st_mtime)
1312         {
1313 #else
1314         if (!error)
1315         {
1316 #endif
1317                 stream = fopen(fname, PG_BINARY_R);
1318                 if (!stream)
1319                 {
1320                         psql_error("%s: %s\n", fname, strerror(errno));
1321                         error = true;
1322                 }
1323                 else
1324                 {
1325                         /* read file back in */
1326                         char            line[1024];
1327
1328                         resetPQExpBuffer(query_buf);
1329                         while (fgets(line, sizeof(line), stream) != NULL)
1330                                 appendPQExpBufferStr(query_buf, line);
1331
1332                         if (ferror(stream))
1333                         {
1334                                 psql_error("%s: %s\n", fname, strerror(errno));
1335                                 error = true;
1336                         }
1337
1338 #ifdef USE_READLINE
1339 #ifdef HAVE_REPLACE_HISTORY_ENTRY
1340
1341                         replace_history_entry(where_history(), query_buf->data, NULL);
1342 #else
1343                         add_history(query_buf->data);
1344 #endif
1345 #endif
1346                         fclose(stream);
1347                 }
1348
1349         }
1350
1351         /* remove temp file */
1352         if (!filename_arg)
1353         {
1354                 if (remove(fname) == -1)
1355                 {
1356                         psql_error("%s: %s\n", fname, strerror(errno));
1357                         error = true;
1358                 }
1359         }
1360
1361         return !error;
1362 }
1363
1364
1365
1366 /*
1367  * process_file
1368  *
1369  * Read commands from filename and then them to the main processing loop
1370  * Handler for \i, but can be used for other things as well.  Returns
1371  * MainLoop() error code.
1372  */
1373 int
1374 process_file(char *filename)
1375 {
1376         FILE       *fd;
1377         int                     result;
1378         char       *oldfilename;
1379
1380         if (!filename)
1381                 return EXIT_FAILURE;
1382
1383         canonicalize_path(filename);
1384         fd = fopen(filename, PG_BINARY_R);
1385
1386         if (!fd)
1387         {
1388                 psql_error("%s: %s\n", filename, strerror(errno));
1389                 return EXIT_FAILURE;
1390         }
1391
1392         oldfilename = pset.inputfile;
1393         pset.inputfile = filename;
1394         result = MainLoop(fd);
1395         fclose(fd);
1396         pset.inputfile = oldfilename;
1397         return result;
1398 }
1399
1400
1401
1402 /*
1403  * do_pset
1404  *
1405  */
1406 static const char *
1407 _align2string(enum printFormat in)
1408 {
1409         switch (in)
1410         {
1411                 case PRINT_NOTHING:
1412                         return "nothing";
1413                         break;
1414                 case PRINT_UNALIGNED:
1415                         return "unaligned";
1416                         break;
1417                 case PRINT_ALIGNED:
1418                         return "aligned";
1419                         break;
1420                 case PRINT_HTML:
1421                         return "html";
1422                         break;
1423                 case PRINT_LATEX:
1424                         return "latex";
1425                         break;
1426                 case PRINT_TROFF_MS:
1427                         return "troff-ms";
1428                         break;
1429         }
1430         return "unknown";
1431 }
1432
1433
1434 bool
1435 do_pset(const char *param, const char *value, printQueryOpt *popt, bool quiet)
1436 {
1437         size_t          vallen = 0;
1438
1439         psql_assert(param);
1440
1441         if (value)
1442                 vallen = strlen(value);
1443
1444         /* set format */
1445         if (strcmp(param, "format") == 0)
1446         {
1447                 if (!value)
1448                         ;
1449                 else if (pg_strncasecmp("unaligned", value, vallen) == 0)
1450                         popt->topt.format = PRINT_UNALIGNED;
1451                 else if (pg_strncasecmp("aligned", value, vallen) == 0)
1452                         popt->topt.format = PRINT_ALIGNED;
1453                 else if (pg_strncasecmp("html", value, vallen) == 0)
1454                         popt->topt.format = PRINT_HTML;
1455                 else if (pg_strncasecmp("latex", value, vallen) == 0)
1456                         popt->topt.format = PRINT_LATEX;
1457                 else if (pg_strncasecmp("troff-ms", value, vallen) == 0)
1458                         popt->topt.format = PRINT_TROFF_MS;
1459                 else
1460                 {
1461                         psql_error("\\pset: allowed formats are unaligned, aligned, html, latex, troff-ms\n");
1462                         return false;
1463                 }
1464
1465                 if (!quiet)
1466                         printf(_("Output format is %s.\n"), _align2string(popt->topt.format));
1467         }
1468
1469         /* set border style/width */
1470         else if (strcmp(param, "border") == 0)
1471         {
1472                 if (value)
1473                         popt->topt.border = atoi(value);
1474
1475                 if (!quiet)
1476                         printf(_("Border style is %d.\n"), popt->topt.border);
1477         }
1478
1479         /* set expanded/vertical mode */
1480         else if (strcmp(param, "x") == 0 || strcmp(param, "expanded") == 0 || strcmp(param, "vertical") == 0)
1481         {
1482                 popt->topt.expanded = !popt->topt.expanded;
1483                 if (!quiet)
1484                         printf(popt->topt.expanded
1485                                    ? _("Expanded display is on.\n")
1486                                    : _("Expanded display is off.\n"));
1487         }
1488
1489         /* locale-aware numeric output */
1490         else if (strcmp(param, "numericlocale") == 0)
1491         {
1492                 popt->topt.numericLocale = !popt->topt.numericLocale;
1493                 if (!quiet)
1494                 {
1495                         if (popt->topt.numericLocale)
1496                                 puts(_("Showing locale-adjusted numeric output."));
1497                         else
1498                                 puts(_("Locale-adjusted numeric output is off."));
1499                 }
1500         }
1501
1502         /* null display */
1503         else if (strcmp(param, "null") == 0)
1504         {
1505                 if (value)
1506                 {
1507                         free(popt->nullPrint);
1508                         popt->nullPrint = pg_strdup(value);
1509                 }
1510                 if (!quiet)
1511                         printf(_("Null display is \"%s\".\n"), popt->nullPrint ? popt->nullPrint : "");
1512         }
1513
1514         /* field separator for unaligned text */
1515         else if (strcmp(param, "fieldsep") == 0)
1516         {
1517                 if (value)
1518                 {
1519                         free(popt->topt.fieldSep);
1520                         popt->topt.fieldSep = pg_strdup(value);
1521                 }
1522                 if (!quiet)
1523                         printf(_("Field separator is \"%s\".\n"), popt->topt.fieldSep);
1524         }
1525
1526         /* record separator for unaligned text */
1527         else if (strcmp(param, "recordsep") == 0)
1528         {
1529                 if (value)
1530                 {
1531                         free(popt->topt.recordSep);
1532                         popt->topt.recordSep = pg_strdup(value);
1533                 }
1534                 if (!quiet)
1535                 {
1536                         if (strcmp(popt->topt.recordSep, "\n") == 0)
1537                                 printf(_("Record separator is <newline>."));
1538                         else
1539                                 printf(_("Record separator is \"%s\".\n"), popt->topt.recordSep);
1540                 }
1541         }
1542
1543         /* toggle between full and tuples-only format */
1544         else if (strcmp(param, "t") == 0 || strcmp(param, "tuples_only") == 0)
1545         {
1546                 popt->topt.tuples_only = !popt->topt.tuples_only;
1547                 if (!quiet)
1548                 {
1549                         if (popt->topt.tuples_only)
1550                                 puts(_("Showing only tuples."));
1551                         else
1552                                 puts(_("Tuples only is off."));
1553                 }
1554         }
1555
1556         /* set title override */
1557         else if (strcmp(param, "title") == 0)
1558         {
1559                 free(popt->title);
1560                 if (!value)
1561                         popt->title = NULL;
1562                 else
1563                         popt->title = pg_strdup(value);
1564
1565                 if (!quiet)
1566                 {
1567                         if (popt->title)
1568                                 printf(_("Title is \"%s\".\n"), popt->title);
1569                         else
1570                                 printf(_("Title is unset.\n"));
1571                 }
1572         }
1573
1574         /* set HTML table tag options */
1575         else if (strcmp(param, "T") == 0 || strcmp(param, "tableattr") == 0)
1576         {
1577                 free(popt->topt.tableAttr);
1578                 if (!value)
1579                         popt->topt.tableAttr = NULL;
1580                 else
1581                         popt->topt.tableAttr = pg_strdup(value);
1582
1583                 if (!quiet)
1584                 {
1585                         if (popt->topt.tableAttr)
1586                                 printf(_("Table attribute is \"%s\".\n"), popt->topt.tableAttr);
1587                         else
1588                                 printf(_("Table attributes unset.\n"));
1589                 }
1590         }
1591
1592         /* toggle use of pager */
1593         else if (strcmp(param, "pager") == 0)
1594         {
1595                 if (value && pg_strcasecmp(value, "always") == 0)
1596                         popt->topt.pager = 2;
1597                 else if (popt->topt.pager == 1)
1598                         popt->topt.pager = 0;
1599                 else
1600                         popt->topt.pager = 1;
1601                 if (!quiet)
1602                 {
1603                         if (popt->topt.pager == 1)
1604                                 puts(_("Pager is used for long output."));
1605                         else if (popt->topt.pager == 2)
1606                                 puts(_("Pager is always used."));
1607                         else
1608                                 puts(_("Pager usage is off."));
1609                 }
1610         }
1611
1612         /* disable "(x rows)" footer */
1613         else if (strcmp(param, "footer") == 0)
1614         {
1615                 popt->default_footer = !popt->default_footer;
1616                 if (!quiet)
1617                 {
1618                         if (popt->default_footer)
1619                                 puts(_("Default footer is on."));
1620                         else
1621                                 puts(_("Default footer is off."));
1622                 }
1623         }
1624
1625         else
1626         {
1627                 psql_error("\\pset: unknown option: %s\n", param);
1628                 return false;
1629         }
1630
1631         return true;
1632 }
1633
1634
1635
1636 #ifndef WIN32
1637 #define DEFAULT_SHELL "/bin/sh"
1638 #else
1639 /*
1640  *      CMD.EXE is in different places in different Win32 releases so we
1641  *      have to rely on the path to find it.
1642  */
1643 #define DEFAULT_SHELL "cmd.exe"
1644 #endif
1645
1646 static bool
1647 do_shell(const char *command)
1648 {
1649         int                     result;
1650
1651         if (!command)
1652         {
1653                 char       *sys;
1654                 const char *shellName;
1655
1656                 shellName = getenv("SHELL");
1657 #ifdef WIN32
1658                 if (shellName == NULL)
1659                         shellName = getenv("COMSPEC");
1660 #endif
1661                 if (shellName == NULL)
1662                         shellName = DEFAULT_SHELL;
1663
1664                 sys = pg_malloc(strlen(shellName) + 16);
1665 #ifndef WIN32
1666                 sprintf(sys,
1667                 /* See EDITOR handling comment for an explaination */
1668                                 "exec %s", shellName);
1669 #else
1670                 sprintf(sys,
1671                 /* See EDITOR handling comment for an explaination */
1672                                 "%s\"%s\"%s", SYSTEMQUOTE, shellName, SYSTEMQUOTE);
1673 #endif
1674                 result = system(sys);
1675                 free(sys);
1676         }
1677         else
1678                 result = system(command);
1679
1680         if (result == 127 || result == -1)
1681         {
1682                 psql_error("\\!: failed\n");
1683                 return false;
1684         }
1685         return true;
1686 }