OpenOCD
options.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Copyright (C) 2004, 2005 by Dominic Rath *
5  * Dominic.Rath@gmx.de *
6  * *
7  * Copyright (C) 2007-2010 Øyvind Harboe *
8  * oyvind.harboe@zylin.com *
9  ***************************************************************************/
10 
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14 
15 #include "configuration.h"
16 #include "log.h"
17 #include "command.h"
18 
19 #include <getopt.h>
20 
21 #include <limits.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #if IS_DARWIN
25 #include <libproc.h>
26 #endif
27 /* sys/sysctl.h is deprecated on Linux from glibc 2.30 */
28 #ifndef __linux__
29 #ifdef HAVE_SYS_SYSCTL_H
30 #include <sys/sysctl.h>
31 #endif
32 #endif
33 #if IS_WIN32 && !IS_CYGWIN
34 #include <windows.h>
35 #endif
36 
37 static int help_flag, version_flag;
38 
39 static const struct option long_options[] = {
40  {"help", no_argument, &help_flag, 1},
41  {"version", no_argument, &version_flag, 1},
42  {"debug", optional_argument, NULL, 'd'},
43  {"file", required_argument, NULL, 'f'},
44  {"search", required_argument, NULL, 's'},
45  {"log_output", required_argument, NULL, 'l'},
46  {"command", required_argument, NULL, 'c'},
47  {NULL, 0, NULL, 0}
48 };
49 
50 int configuration_output_handler(struct command_context *context, const char *line)
51 {
52  LOG_USER_N("%s", line);
53 
54  return ERROR_OK;
55 }
56 
57 /* Return the canonical path to the directory the openocd executable is in.
58  * The path should be absolute, use / as path separator and have all symlinks
59  * resolved. The returned string is malloc'd. */
60 static char *find_exe_path(void)
61 {
62  char *exepath = NULL;
63 
64  do {
65 #if IS_WIN32 && !IS_CYGWIN
66  exepath = malloc(MAX_PATH);
67  if (!exepath)
68  break;
69  GetModuleFileName(NULL, exepath, MAX_PATH);
70 
71  /* Convert path separators to UNIX style, should work on Windows also. */
72  for (char *p = exepath; *p; p++) {
73  if (*p == '\\')
74  *p = '/';
75  }
76 
77 #elif IS_DARWIN
78  exepath = malloc(PROC_PIDPATHINFO_MAXSIZE);
79  if (!exepath)
80  break;
81  if (proc_pidpath(getpid(), exepath, PROC_PIDPATHINFO_MAXSIZE) <= 0) {
82  free(exepath);
83  exepath = NULL;
84  }
85 
86 #elif defined(CTL_KERN) && defined(KERN_PROC) && defined(KERN_PROC_PATHNAME) /* *BSD */
87 #ifndef PATH_MAX
88 #define PATH_MAX 1024
89 #endif
90  char *path = malloc(PATH_MAX);
91  if (!path)
92  break;
93  int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
94  size_t size = PATH_MAX;
95 
96  if (sysctl(mib, (u_int)ARRAY_SIZE(mib), path, &size, NULL, 0) != 0)
97  break;
98 
99 #ifdef HAVE_REALPATH
100  exepath = realpath(path, NULL);
101  free(path);
102 #else
103  exepath = path;
104 #endif
105 
106 #elif defined(HAVE_REALPATH) /* Assume POSIX.1-2008 */
107  /* Try Unices in order of likelihood. */
108  exepath = realpath("/proc/self/exe", NULL); /* Linux/Cygwin */
109  if (!exepath)
110  exepath = realpath("/proc/self/path/a.out", NULL); /* Solaris */
111  if (!exepath)
112  exepath = realpath("/proc/curproc/file", NULL); /* FreeBSD (Should be covered above) */
113 #endif
114  } while (0);
115 
116  if (exepath) {
117  /* Strip executable file name, leaving path */
118  *strrchr(exepath, '/') = '\0';
119  } else {
120  LOG_WARNING("Could not determine executable path, using configured BINDIR.");
121  LOG_DEBUG("BINDIR = %s", BINDIR);
122 #ifdef HAVE_REALPATH
123  exepath = realpath(BINDIR, NULL);
124 #else
125  exepath = strdup(BINDIR);
126 #endif
127  }
128 
129  return exepath;
130 }
131 
132 static char *find_relative_path(const char *from, const char *to)
133 {
134  size_t i;
135 
136  /* Skip common /-separated parts of from and to */
137  i = 0;
138  for (size_t n = 0; from[n] == to[n]; n++) {
139  if (from[n] == '\0') {
140  i = n;
141  break;
142  }
143  if (from[n] == '/')
144  i = n + 1;
145  }
146  from += i;
147  to += i;
148 
149  /* Count number of /-separated non-empty parts of from */
150  i = 0;
151  while (from[0] != '\0') {
152  if (from[0] != '/')
153  i++;
154  char *next = strchr(from, '/');
155  if (!next)
156  break;
157  from = next + 1;
158  }
159 
160  /* Prepend that number of ../ in front of to */
161  char *relpath = malloc(i * 3 + strlen(to) + 1);
162  relpath[0] = '\0';
163  for (size_t n = 0; n < i; n++)
164  strcat(relpath, "../");
165  strcat(relpath, to);
166 
167  return relpath;
168 }
169 
170 static void add_user_dirs(void)
171 {
172  char *path;
173 
174 #if IS_WIN32
175  const char *appdata = getenv("APPDATA");
176 
177  if (appdata) {
178  path = alloc_printf("%s/OpenOCD", appdata);
179  if (path) {
180  /* Convert path separators to UNIX style, should work on Windows also. */
181  for (char *p = path; *p; p++) {
182  if (*p == '\\')
183  *p = '/';
184  }
185  add_script_search_dir(path);
186  free(path);
187  }
188  }
189  /* WIN32 may also have HOME defined, particularly under Cygwin, so add those paths below too */
190 #endif
191 
192  const char *home = getenv("HOME");
193 #if IS_DARWIN
194  if (home) {
195  path = alloc_printf("%s/Library/Preferences/org.openocd", home);
196  if (path) {
197  add_script_search_dir(path);
198  free(path);
199  }
200  }
201 #endif
202  const char *xdg_config = getenv("XDG_CONFIG_HOME");
203 
204  if (xdg_config) {
205  path = alloc_printf("%s/openocd", xdg_config);
206  if (path) {
207  add_script_search_dir(path);
208  free(path);
209  }
210  } else if (home) {
211  path = alloc_printf("%s/.config/openocd", home);
212  if (path) {
213  add_script_search_dir(path);
214  free(path);
215  }
216  }
217 
218  if (home) {
219  path = alloc_printf("%s/.openocd", home);
220  if (path) {
221  add_script_search_dir(path);
222  free(path);
223  }
224  }
225 }
226 
227 static void add_default_dirs(void)
228 {
229  char *path;
230  char *exepath = find_exe_path();
231  char *bin2data = find_relative_path(BINDIR, PKGDATADIR);
232 
233  LOG_DEBUG("bindir=%s", BINDIR);
234  LOG_DEBUG("pkgdatadir=%s", PKGDATADIR);
235  LOG_DEBUG("exepath=%s", exepath);
236  LOG_DEBUG("bin2data=%s", bin2data);
237 
238  /*
239  * The directory containing OpenOCD-supplied scripts should be
240  * listed last in the built-in search order, so the user can
241  * override these scripts with site-specific customizations.
242  */
243  path = getenv("OPENOCD_SCRIPTS");
244  if (path)
245  add_script_search_dir(path);
246 
247  add_user_dirs();
248 
249  path = alloc_printf("%s/%s/%s", exepath, bin2data, "site");
250  if (path) {
251  add_script_search_dir(path);
252  free(path);
253  }
254 
255  path = alloc_printf("%s/%s/%s", exepath, bin2data, "scripts");
256  if (path) {
257  add_script_search_dir(path);
258  free(path);
259  }
260 
261  free(exepath);
262  free(bin2data);
263 }
264 
265 int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
266 {
267  int c;
268 
269  while (1) {
270  /* getopt_long stores the option index here. */
271  int option_index = 0;
272 
273  c = getopt_long(argc, argv, "hvd::l:f:s:c:", long_options, &option_index);
274 
275  /* Detect the end of the options. */
276  if (c == -1)
277  break;
278 
279  switch (c) {
280  case 0:
281  break;
282  case 'h': /* --help | -h */
283  help_flag = 1;
284  break;
285  case 'v': /* --version | -v */
286  version_flag = 1;
287  break;
288  case 'f': /* --file | -f */
289  {
290  char *command = alloc_printf("script {%s}", optarg);
292  free(command);
293  break;
294  }
295  case 's': /* --search | -s */
296  add_script_search_dir(optarg);
297  break;
298  case 'd': /* --debug | -d */
299  {
300  int retval = command_run_linef(cmd_ctx, "debug_level %s", optarg ? optarg : "3");
301  if (retval != ERROR_OK)
302  return retval;
303  break;
304  }
305  case 'l': /* --log_output | -l */
306  if (optarg)
307  command_run_linef(cmd_ctx, "log_output %s", optarg);
308  break;
309  case 'c': /* --command | -c */
310  if (optarg)
311  add_config_command(optarg);
312  break;
313  default: /* '?' */
314  /* getopt will emit an error message, all we have to do is bail. */
315  return ERROR_FAIL;
316  }
317  }
318 
319  if (optind < argc) {
320  /* Catch extra arguments on the command line. */
321  LOG_OUTPUT("Unexpected command line argument: %s\n", argv[optind]);
322  return ERROR_FAIL;
323  }
324 
325  if (help_flag) {
326  LOG_OUTPUT("Open On-Chip Debugger\nLicensed under GNU GPL v2\n");
327  LOG_OUTPUT("--help | -h\tdisplay this help\n");
328  LOG_OUTPUT("--version | -v\tdisplay OpenOCD version\n");
329  LOG_OUTPUT("--file | -f\tuse configuration file <name>\n");
330  LOG_OUTPUT("--search | -s\tdir to search for config files and scripts\n");
331  LOG_OUTPUT("--debug | -d\tset debug level to 3\n");
332  LOG_OUTPUT(" | -d<n>\tset debug level to <level>\n");
333  LOG_OUTPUT("--log_output | -l\tredirect log output to file <name>\n");
334  LOG_OUTPUT("--command | -c\trun <command>\n");
335  exit(-1);
336  }
337 
338  if (version_flag) {
339  /* Nothing to do, version gets printed automatically. */
340  /* It is not an error to request the VERSION number. */
341  exit(0);
342  }
343 
344  /* dump full command line */
345  for (int i = 0; i < argc; i++)
346  LOG_DEBUG("ARGV[%d] = \"%s\"", i, argv[i]);
347 
348  /* paths specified on the command line take precedence over these
349  * built-in paths
350  */
352 
353  return ERROR_OK;
354 }
int command_run_linef(struct command_context *context, const char *format,...)
Definition: command.c:613
void add_config_command(const char *cfg)
Definition: configuration.c:36
void add_script_search_dir(const char *dir)
Definition: configuration.c:25
char * alloc_printf(const char *format,...)
Definition: log.c:364
#define LOG_OUTPUT(expr ...)
Definition: log.h:141
#define LOG_WARNING(expr ...)
Definition: log.h:129
#define ERROR_FAIL
Definition: log.h:170
#define LOG_USER_N(expr ...)
Definition: log.h:138
#define LOG_DEBUG(expr ...)
Definition: log.h:109
#define ERROR_OK
Definition: log.h:164
static char * find_exe_path(void)
Definition: options.c:60
int configuration_output_handler(struct command_context *context, const char *line)
Definition: options.c:50
static int version_flag
Definition: options.c:37
static void add_user_dirs(void)
Definition: options.c:170
static char * find_relative_path(const char *from, const char *to)
Definition: options.c:132
static int help_flag
Definition: options.c:37
static const struct option long_options[]
Definition: options.c:39
int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
Definition: options.c:265
static void add_default_dirs(void)
Definition: options.c:227
size_t size
Size of the control block search area.
Definition: rtt/rtt.c:30
#define ARRAY_SIZE(x)
Compute the number of elements of a variable length array.
Definition: types.h:57
#define NULL
Definition: usb.h:16