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

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)