1 /* MI Command Set - environment commands. 2 Copyright (C) 2002-2023 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 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 = 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 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 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 96 env_mod_path (const char *dirname, std::string &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 109 mi_cmd_env_path (const char *command, char **argv, int argc) 110 { 111 struct ui_out *uiout = current_uiout; 112 const char *env; 113 int reset = 0; 114 int oind = 0; 115 int i; 116 char *oarg; 117 enum opt 118 { 119 RESET_OPT 120 }; 121 static const struct mi_opt opts[] = 122 { 123 {"r", RESET_OPT, 0}, 124 { 0, 0, 0 } 125 }; 126 127 dont_repeat (); 128 129 if (mi_version (uiout) < 2) 130 { 131 for (i = argc - 1; i >= 0; --i) 132 env_execute_cli_command ("path", argv[i]); 133 return; 134 } 135 136 /* Otherwise the mi level is 2 or higher. */ 137 while (1) 138 { 139 int opt = mi_getopt ("-environment-path", argc, argv, opts, 140 &oind, &oarg); 141 142 if (opt < 0) 143 break; 144 switch ((enum opt) opt) 145 { 146 case RESET_OPT: 147 reset = 1; 148 break; 149 } 150 } 151 argv += oind; 152 argc -= oind; 153 154 std::string exec_path; 155 if (reset) 156 { 157 /* Reset implies resetting to original path first. */ 158 exec_path = orig_path; 159 } 160 else 161 { 162 /* Otherwise, get current path to modify. */ 163 env = current_inferior ()->environment.get (path_var_name); 164 165 /* Can be null if path is not set. */ 166 if (!env) 167 env = ""; 168 169 exec_path = 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.c_str ()); 176 env = current_inferior ()->environment.get (path_var_name); 177 uiout->field_string ("path", env); 178 } 179 180 /* Add zero or more directories to the front of the source path. */ 181 182 void 183 mi_cmd_env_dir (const char *command, char **argv, int argc) 184 { 185 struct ui_out *uiout = current_uiout; 186 int i; 187 int oind = 0; 188 int reset = 0; 189 char *oarg; 190 enum opt 191 { 192 RESET_OPT 193 }; 194 static const struct mi_opt opts[] = 195 { 196 {"r", RESET_OPT, 0}, 197 { 0, 0, 0 } 198 }; 199 200 dont_repeat (); 201 202 if (mi_version (uiout) < 2) 203 { 204 for (i = argc - 1; i >= 0; --i) 205 env_execute_cli_command ("dir", argv[i]); 206 return; 207 } 208 209 /* Otherwise mi level is 2 or higher. */ 210 while (1) 211 { 212 int opt = mi_getopt ("-environment-directory", argc, argv, opts, 213 &oind, &oarg); 214 215 if (opt < 0) 216 break; 217 switch ((enum opt) opt) 218 { 219 case RESET_OPT: 220 reset = 1; 221 break; 222 } 223 } 224 argv += oind; 225 argc -= oind; 226 227 if (reset) 228 { 229 /* Reset means setting to default path first. */ 230 init_source_path (); 231 } 232 233 for (i = argc - 1; i >= 0; --i) 234 env_mod_path (argv[i], source_path); 235 236 uiout->field_string ("source-path", source_path); 237 forget_cached_source_info (); 238 } 239 240 /* Set the inferior terminal device name. */ 241 242 void 243 mi_cmd_inferior_tty_set (const char *command, char **argv, int argc) 244 { 245 if (argc > 0) 246 current_inferior ()->set_tty (argv[0]); 247 else 248 current_inferior ()->set_tty (""); 249 } 250 251 /* Print the inferior terminal device name. */ 252 253 void 254 mi_cmd_inferior_tty_show (const char *command, char **argv, int argc) 255 { 256 if ( !mi_valid_noargs ("-inferior-tty-show", argc, argv)) 257 error (_("-inferior-tty-show: Usage: No args")); 258 259 const std::string &inferior_tty = current_inferior ()->tty (); 260 if (!inferior_tty.empty ()) 261 current_uiout->field_string ("inferior_tty_terminal", inferior_tty); 262 } 263 264 void _initialize_mi_cmd_env (); 265 void 266 _initialize_mi_cmd_env () 267 { 268 const char *env; 269 270 /* We want original execution path to reset to, if desired later. 271 At this point, current inferior is not created, so cannot use 272 current_inferior ()->environment. We use getenv here because it 273 is not necessary to create a whole new gdb_environ just for one 274 variable. */ 275 env = getenv (path_var_name); 276 277 /* Can be null if path is not set. */ 278 if (!env) 279 env = ""; 280 orig_path = xstrdup (env); 281 } 282