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; ; n++) {
139  if (!from[n] || !to[n]) {
140  /* one path ended: common only if the other ends or continues with '/' */
141  if ((!from[n] || from[n] == '/') && (!to[n] || to[n] == '/'))
142  i = n;
143  break;
144  }
145  if (from[n] != to[n])
146  break;
147  if (from[n] == '/')
148  i = n + 1;
149  }
150  from += i;
151  to += i;
152  if (*from == '/')
153  from++;
154  if (*to == '/')
155  to++;
156 
157  /* Count number of /-separated non-empty parts of from */
158  i = 0;
159  while (from[0] != '\0') {
160  if (from[0] != '/')
161  i++;
162  const char *next = strchr(from, '/');
163  if (!next)
164  break;
165  from = next + 1;
166  }
167 
168  /* Prepend that number of ../ in front of to */
169  char *relpath = malloc(i * 3 + strlen(to) + 1);
170  relpath[0] = '\0';
171  for (size_t n = 0; n < i; n++)
172  strcat(relpath, "../");
173  size_t len = strlen(relpath);
174  if (!*to && len)
175  relpath[len - 1] = '\0';
176  strcat(relpath, to);
177 
178  return relpath;
179 }
180 
181 static void add_user_dirs(void)
182 {
183  char *path;
184 
185 #if IS_WIN32
186  const char *appdata = getenv("APPDATA");
187 
188  if (appdata) {
189  path = alloc_printf("%s/OpenOCD", appdata);
190  if (path) {
191  /* Convert path separators to UNIX style, should work on Windows also. */
192  for (char *p = path; *p; p++) {
193  if (*p == '\\')
194  *p = '/';
195  }
196  add_script_search_dir(path);
197  free(path);
198  }
199  }
200  /* WIN32 may also have HOME defined, particularly under Cygwin, so add those paths below too */
201 #endif
202 
203  const char *home = getenv("HOME");
204 #if IS_DARWIN
205  if (home) {
206  path = alloc_printf("%s/Library/Preferences/org.openocd", home);
207  if (path) {
208  add_script_search_dir(path);
209  free(path);
210  }
211  }
212 #endif
213  const char *xdg_config = getenv("XDG_CONFIG_HOME");
214 
215  if (xdg_config) {
216  path = alloc_printf("%s/openocd", xdg_config);
217  if (path) {
218  add_script_search_dir(path);
219  free(path);
220  }
221  } else if (home) {
222  path = alloc_printf("%s/.config/openocd", home);
223  if (path) {
224  add_script_search_dir(path);
225  free(path);
226  }
227  }
228 
229  if (home) {
230  path = alloc_printf("%s/.openocd", home);
231  if (path) {
232  add_script_search_dir(path);
233  free(path);
234  }
235  }
236 }
237 
238 static void add_default_dirs(void)
239 {
240  char *path;
241  char *exepath = find_exe_path();
242  char *bin2data = find_relative_path(BINDIR, PKGDATADIR);
243 
244  LOG_DEBUG("bindir=%s", BINDIR);
245  LOG_DEBUG("pkgdatadir=%s", PKGDATADIR);
246  LOG_DEBUG("exepath=%s", exepath);
247  LOG_DEBUG("bin2data=%s", bin2data);
248 
249  /*
250  * The directory containing OpenOCD-supplied scripts should be
251  * listed last in the built-in search order, so the user can
252  * override these scripts with site-specific customizations.
253  */
254  path = getenv("OPENOCD_SCRIPTS");
255  if (path)
256  add_script_search_dir(path);
257 
258  add_user_dirs();
259 
260  path = alloc_printf("%s/%s/%s", exepath, bin2data, "site");
261  if (path) {
262  add_script_search_dir(path);
263  free(path);
264  }
265 
266  path = alloc_printf("%s/%s/%s", exepath, bin2data, "scripts");
267  if (path) {
268  add_script_search_dir(path);
269  free(path);
270  }
271 
272  free(exepath);
273  free(bin2data);
274 }
275 
276 int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
277 {
278  int c;
279 
280  while (1) {
281  /* getopt_long stores the option index here. */
282  int option_index = 0;
283 
284  c = getopt_long(argc, argv, "hvd::l:f:s:c:", long_options, &option_index);
285 
286  /* Detect the end of the options. */
287  if (c == -1)
288  break;
289 
290  switch (c) {
291  case 0:
292  break;
293  case 'h': /* --help | -h */
294  help_flag = 1;
295  break;
296  case 'v': /* --version | -v */
297  version_flag = 1;
298  break;
299  case 'f': /* --file | -f */
300  {
301  char *command = alloc_printf("script {%s}", optarg);
303  free(command);
304  break;
305  }
306  case 's': /* --search | -s */
307  add_script_search_dir(optarg);
308  break;
309  case 'd': /* --debug | -d */
310  {
311  int retval = command_run_linef(cmd_ctx, "debug_level %s", optarg ? optarg : "3");
312  if (retval != ERROR_OK)
313  return retval;
314  break;
315  }
316  case 'l': /* --log_output | -l */
317  {
318  int retval = command_run_linef(cmd_ctx, "log_output %s", optarg);
319  if (retval != ERROR_OK)
320  return retval;
321  break;
322  }
323  case 'c': /* --command | -c */
324  add_config_command(optarg);
325  break;
326  default: /* '?' */
327  /* getopt will emit an error message, all we have to do is bail. */
328  return ERROR_FAIL;
329  }
330  }
331 
332  if (optind < argc) {
333  /* Catch extra arguments on the command line. */
334  LOG_OUTPUT("Unexpected command line argument: %s\n", argv[optind]);
335  return ERROR_FAIL;
336  }
337 
338  if (help_flag) {
339  LOG_OUTPUT("Open On-Chip Debugger\nLicensed under GNU GPL v2\n");
340  LOG_OUTPUT("--help | -h\tdisplay this help\n");
341  LOG_OUTPUT("--version | -v\tdisplay OpenOCD version\n");
342  LOG_OUTPUT("--file | -f\tuse configuration file <name>\n");
343  LOG_OUTPUT("--search | -s\tdir to search for config files and scripts\n");
344  LOG_OUTPUT("--debug | -d\tset debug level to 3\n");
345  LOG_OUTPUT(" | -d<n>\tset debug level to <level>\n");
346  LOG_OUTPUT("--log_output | -l\tredirect log output to file <name>\n");
347  LOG_OUTPUT("--command | -c\trun <command>\n");
348  exit(0);
349  }
350 
351  if (version_flag) {
352  /* Nothing to do, version gets printed automatically. */
353  /* It is not an error to request the VERSION number. */
354  exit(0);
355  }
356 
357  /* dump full command line */
358  for (int i = 0; i < argc; i++)
359  LOG_DEBUG("ARGV[%d] = \"%s\"", i, argv[i]);
360 
361  /* paths specified on the command line take precedence over these
362  * built-in paths
363  */
365 
366  return ERROR_OK;
367 }
int command_run_linef(struct command_context *context, const char *format,...)
Definition: command.c:553
void add_config_command(const char *cfg)
Definition: configuration.c:36
void add_script_search_dir(const char *dir)
Definition: configuration.c:25
uint32_t size
Size of dw_spi_transaction::buffer.
Definition: dw-spi-helper.h:4
char * alloc_printf(const char *format,...)
Definition: log.c:386
#define LOG_OUTPUT(expr ...)
Definition: log.h:156
#define LOG_WARNING(expr ...)
Definition: log.h:144
#define ERROR_FAIL
Definition: log.h:188
#define LOG_USER_N(expr ...)
Definition: log.h:153
#define LOG_DEBUG(expr ...)
Definition: log.h:124
#define ERROR_OK
Definition: log.h:182
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:181
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:276
static void add_default_dirs(void)
Definition: options.c:238
#define ARRAY_SIZE(x)
Compute the number of elements of a variable length array.
Definition: types.h:57
#define NULL
Definition: usb.h:16