1 /* MI Command Set - environment commands.
2    Copyright (C) 2002-2021 Free Software Foundation, Inc.
3 
4    Contributed by Red Hat Inc.
5 
6    This file is part of GDB.
7 
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12 
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17 
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
20 
21 #include "defs.h"
22 #include "inferior.h"
23 #include "value.h"
24 #include "mi-out.h"
25 #include "mi-cmds.h"
26 #include "mi-getopt.h"
27 #include "symtab.h"
28 #include "target.h"
29 #include "gdbsupport/environ.h"
30 #include "command.h"
31 #include "ui-out.h"
32 #include "top.h"
33 #include <sys/stat.h>
34 #include "source.h"
35 
36 static const char path_var_name[] = "PATH";
37 static char *orig_path = NULL;
38 
39 /* The following is copied from mi-main.c so for m1 and below we can
40    perform old behavior and use cli commands.  If ARGS is non-null,
41    append it to the CMD.  */
42 
43 static void
env_execute_cli_command(const char * cmd,const char * args)44 env_execute_cli_command (const char *cmd, const char *args)
45 {
46   if (cmd != 0)
47     {
48       gdb::unique_xmalloc_ptr<char> run;
49 
50       if (args != NULL)
51 	run.reset (xstrprintf ("%s %s", cmd, args));
52       else
53 	run.reset (xstrdup (cmd));
54       execute_command ( /*ui */ run.get (), 0 /*from_tty */ );
55     }
56 }
57 
58 /* Print working directory.  */
59 
60 void
mi_cmd_env_pwd(const char * command,char ** argv,int argc)61 mi_cmd_env_pwd (const char *command, char **argv, int argc)
62 {
63   struct ui_out *uiout = current_uiout;
64 
65   if (argc > 0)
66     error (_("-environment-pwd: No arguments allowed"));
67 
68   if (mi_version (uiout) < 2)
69     {
70       env_execute_cli_command ("pwd", NULL);
71       return;
72     }
73 
74   /* Otherwise the mi level is 2 or higher.  */
75 
76   gdb::unique_xmalloc_ptr<char> cwd (getcwd (NULL, 0));
77   if (cwd == NULL)
78     error (_("-environment-pwd: error finding name of working directory: %s"),
79 	   safe_strerror (errno));
80 
81   uiout->field_string ("cwd", cwd.get ());
82 }
83 
84 /* Change working directory.  */
85 
86 void
mi_cmd_env_cd(const char * command,char ** argv,int argc)87 mi_cmd_env_cd (const char *command, char **argv, int argc)
88 {
89   if (argc == 0 || argc > 1)
90     error (_("-environment-cd: Usage DIRECTORY"));
91 
92   env_execute_cli_command ("cd", argv[0]);
93 }
94 
95 static void
env_mod_path(const char * dirname,char ** which_path)96 env_mod_path (const char *dirname, char **which_path)
97 {
98   if (dirname == 0 || dirname[0] == '\0')
99     return;
100 
101   /* Call add_path with last arg 0 to indicate not to parse for
102      separator characters.  */
103   add_path (dirname, which_path, 0);
104 }
105 
106 /* Add one or more directories to start of executable search path.  */
107 
108 void
mi_cmd_env_path(const char * command,char ** argv,int argc)109 mi_cmd_env_path (const char *command, char **argv, int argc)
110 {
111   struct ui_out *uiout = current_uiout;
112   char *exec_path;
113   const char *env;
114   int reset = 0;
115   int oind = 0;
116   int i;
117   char *oarg;
118   enum opt
119     {
120       RESET_OPT
121     };
122   static const struct mi_opt opts[] =
123   {
124     {"r", RESET_OPT, 0},
125     { 0, 0, 0 }
126   };
127 
128   dont_repeat ();
129 
130   if (mi_version (uiout) < 2)
131     {
132       for (i = argc - 1; i >= 0; --i)
133 	env_execute_cli_command ("path", argv[i]);
134       return;
135     }
136 
137   /* Otherwise the mi level is 2 or higher.  */
138   while (1)
139     {
140       int opt = mi_getopt ("-environment-path", argc, argv, opts,
141 			   &oind, &oarg);
142 
143       if (opt < 0)
144 	break;
145       switch ((enum opt) opt)
146 	{
147 	case RESET_OPT:
148 	  reset = 1;
149 	  break;
150 	}
151     }
152   argv += oind;
153   argc -= oind;
154 
155 
156   if (reset)
157     {
158       /* Reset implies resetting to original path first.  */
159       exec_path = xstrdup (orig_path);
160     }
161   else
162     {
163       /* Otherwise, get current path to modify.  */
164       env = current_inferior ()->environment.get (path_var_name);
165 
166       /* Can be null if path is not set.  */
167       if (!env)
168 	env = "";
169       exec_path = xstrdup (env);
170     }
171 
172   for (i = argc - 1; i >= 0; --i)
173     env_mod_path (argv[i], &exec_path);
174 
175   current_inferior ()->environment.set (path_var_name, exec_path);
176   xfree (exec_path);
177   env = current_inferior ()->environment.get (path_var_name);
178   uiout->field_string ("path", env);
179 }
180 
181 /* Add zero or more directories to the front of the source path.  */
182 
183 void
mi_cmd_env_dir(const char * command,char ** argv,int argc)184 mi_cmd_env_dir (const char *command, char **argv, int argc)
185 {
186   struct ui_out *uiout = current_uiout;
187   int i;
188   int oind = 0;
189   int reset = 0;
190   char *oarg;
191   enum opt
192     {
193       RESET_OPT
194     };
195   static const struct mi_opt opts[] =
196   {
197     {"r", RESET_OPT, 0},
198     { 0, 0, 0 }
199   };
200 
201   dont_repeat ();
202 
203   if (mi_version (uiout) < 2)
204     {
205       for (i = argc - 1; i >= 0; --i)
206 	env_execute_cli_command ("dir", argv[i]);
207       return;
208     }
209 
210   /* Otherwise mi level is 2 or higher.  */
211   while (1)
212     {
213       int opt = mi_getopt ("-environment-directory", argc, argv, opts,
214 			   &oind, &oarg);
215 
216       if (opt < 0)
217 	break;
218       switch ((enum opt) opt)
219 	{
220 	case RESET_OPT:
221 	  reset = 1;
222 	  break;
223 	}
224     }
225   argv += oind;
226   argc -= oind;
227 
228   if (reset)
229     {
230       /* Reset means setting to default path first.  */
231       xfree (source_path);
232       init_source_path ();
233     }
234 
235   for (i = argc - 1; i >= 0; --i)
236     env_mod_path (argv[i], &source_path);
237 
238   uiout->field_string ("source-path", source_path);
239   forget_cached_source_info ();
240 }
241 
242 /* Set the inferior terminal device name.  */
243 
244 void
mi_cmd_inferior_tty_set(const char * command,char ** argv,int argc)245 mi_cmd_inferior_tty_set (const char *command, char **argv, int argc)
246 {
247   current_inferior ()->set_tty (argv[0]);
248 }
249 
250 /* Print the inferior terminal device name.  */
251 
252 void
mi_cmd_inferior_tty_show(const char * command,char ** argv,int argc)253 mi_cmd_inferior_tty_show (const char *command, char **argv, int argc)
254 {
255   if ( !mi_valid_noargs ("-inferior-tty-show", argc, argv))
256     error (_("-inferior-tty-show: Usage: No args"));
257 
258   const char *inferior_tty = current_inferior ()->tty ();
259   if (inferior_tty != NULL)
260     current_uiout->field_string ("inferior_tty_terminal", inferior_tty);
261 }
262 
263 void _initialize_mi_cmd_env ();
264 void
_initialize_mi_cmd_env()265 _initialize_mi_cmd_env ()
266 {
267   const char *env;
268 
269   /* We want original execution path to reset to, if desired later.
270      At this point, current inferior is not created, so cannot use
271      current_inferior ()->environment.  We use getenv here because it
272      is not necessary to create a whole new gdb_environ just for one
273      variable.  */
274   env = getenv (path_var_name);
275 
276   /* Can be null if path is not set.  */
277   if (!env)
278     env = "";
279   orig_path = xstrdup (env);
280 }
281