Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
builtin-help.c
Go to the documentation of this file.
1 /*
2  * builtin-help.c
3  *
4  * Builtin help command
5  */
6 #include "perf.h"
7 #include "util/cache.h"
8 #include "builtin.h"
9 #include "util/exec_cmd.h"
10 #include "common-cmds.h"
11 #include "util/parse-options.h"
12 #include "util/run-command.h"
13 #include "util/help.h"
14 
15 static struct man_viewer_list {
16  struct man_viewer_list *next;
17  char name[FLEX_ARRAY];
18 } *man_viewer_list;
19 
20 static struct man_viewer_info_list {
21  struct man_viewer_info_list *next;
22  const char *info;
23  char name[FLEX_ARRAY];
24 } *man_viewer_info_list;
25 
31 };
32 
33 static enum help_format parse_help_format(const char *format)
34 {
35  if (!strcmp(format, "man"))
36  return HELP_FORMAT_MAN;
37  if (!strcmp(format, "info"))
38  return HELP_FORMAT_INFO;
39  if (!strcmp(format, "web") || !strcmp(format, "html"))
40  return HELP_FORMAT_WEB;
41 
42  pr_err("unrecognized help format '%s'", format);
43  return HELP_FORMAT_NONE;
44 }
45 
46 static const char *get_man_viewer_info(const char *name)
47 {
48  struct man_viewer_info_list *viewer;
49 
50  for (viewer = man_viewer_info_list; viewer; viewer = viewer->next) {
51  if (!strcasecmp(name, viewer->name))
52  return viewer->info;
53  }
54  return NULL;
55 }
56 
57 static int check_emacsclient_version(void)
58 {
59  struct strbuf buffer = STRBUF_INIT;
60  struct child_process ec_process;
61  const char *argv_ec[] = { "emacsclient", "--version", NULL };
62  int version;
63 
64  /* emacsclient prints its version number on stderr */
65  memset(&ec_process, 0, sizeof(ec_process));
66  ec_process.argv = argv_ec;
67  ec_process.err = -1;
68  ec_process.stdout_to_stderr = 1;
69  if (start_command(&ec_process)) {
70  fprintf(stderr, "Failed to start emacsclient.\n");
71  return -1;
72  }
73  strbuf_read(&buffer, ec_process.err, 20);
74  close(ec_process.err);
75 
76  /*
77  * Don't bother checking return value, because "emacsclient --version"
78  * seems to always exits with code 1.
79  */
80  finish_command(&ec_process);
81 
82  if (prefixcmp(buffer.buf, "emacsclient")) {
83  fprintf(stderr, "Failed to parse emacsclient version.\n");
84  strbuf_release(&buffer);
85  return -1;
86  }
87 
88  strbuf_remove(&buffer, 0, strlen("emacsclient"));
89  version = atoi(buffer.buf);
90 
91  if (version < 22) {
92  fprintf(stderr,
93  "emacsclient version '%d' too old (< 22).\n",
94  version);
95  strbuf_release(&buffer);
96  return -1;
97  }
98 
99  strbuf_release(&buffer);
100  return 0;
101 }
102 
103 static void exec_woman_emacs(const char *path, const char *page)
104 {
105  if (!check_emacsclient_version()) {
106  /* This works only with emacsclient version >= 22. */
107  struct strbuf man_page = STRBUF_INIT;
108 
109  if (!path)
110  path = "emacsclient";
111  strbuf_addf(&man_page, "(woman \"%s\")", page);
112  execlp(path, "emacsclient", "-e", man_page.buf, NULL);
113  warning("failed to exec '%s': %s", path, strerror(errno));
114  }
115 }
116 
117 static void exec_man_konqueror(const char *path, const char *page)
118 {
119  const char *display = getenv("DISPLAY");
120  if (display && *display) {
121  struct strbuf man_page = STRBUF_INIT;
122  const char *filename = "kfmclient";
123 
124  /* It's simpler to launch konqueror using kfmclient. */
125  if (path) {
126  const char *file = strrchr(path, '/');
127  if (file && !strcmp(file + 1, "konqueror")) {
128  char *new = strdup(path);
129  char *dest = strrchr(new, '/');
130 
131  /* strlen("konqueror") == strlen("kfmclient") */
132  strcpy(dest + 1, "kfmclient");
133  path = new;
134  }
135  if (file)
136  filename = file;
137  } else
138  path = "kfmclient";
139  strbuf_addf(&man_page, "man:%s(1)", page);
140  execlp(path, filename, "newTab", man_page.buf, NULL);
141  warning("failed to exec '%s': %s", path, strerror(errno));
142  }
143 }
144 
145 static void exec_man_man(const char *path, const char *page)
146 {
147  if (!path)
148  path = "man";
149  execlp(path, "man", page, NULL);
150  warning("failed to exec '%s': %s", path, strerror(errno));
151 }
152 
153 static void exec_man_cmd(const char *cmd, const char *page)
154 {
155  struct strbuf shell_cmd = STRBUF_INIT;
156  strbuf_addf(&shell_cmd, "%s %s", cmd, page);
157  execl("/bin/sh", "sh", "-c", shell_cmd.buf, NULL);
158  warning("failed to exec '%s': %s", cmd, strerror(errno));
159 }
160 
161 static void add_man_viewer(const char *name)
162 {
163  struct man_viewer_list **p = &man_viewer_list;
164  size_t len = strlen(name);
165 
166  while (*p)
167  p = &((*p)->next);
168  *p = zalloc(sizeof(**p) + len + 1);
169  strncpy((*p)->name, name, len);
170 }
171 
172 static int supported_man_viewer(const char *name, size_t len)
173 {
174  return (!strncasecmp("man", name, len) ||
175  !strncasecmp("woman", name, len) ||
176  !strncasecmp("konqueror", name, len));
177 }
178 
179 static void do_add_man_viewer_info(const char *name,
180  size_t len,
181  const char *value)
182 {
183  struct man_viewer_info_list *new = zalloc(sizeof(*new) + len + 1);
184 
185  strncpy(new->name, name, len);
186  new->info = strdup(value);
187  new->next = man_viewer_info_list;
188  man_viewer_info_list = new;
189 }
190 
191 static int add_man_viewer_path(const char *name,
192  size_t len,
193  const char *value)
194 {
195  if (supported_man_viewer(name, len))
196  do_add_man_viewer_info(name, len, value);
197  else
198  warning("'%s': path for unsupported man viewer.\n"
199  "Please consider using 'man.<tool>.cmd' instead.",
200  name);
201 
202  return 0;
203 }
204 
205 static int add_man_viewer_cmd(const char *name,
206  size_t len,
207  const char *value)
208 {
209  if (supported_man_viewer(name, len))
210  warning("'%s': cmd for supported man viewer.\n"
211  "Please consider using 'man.<tool>.path' instead.",
212  name);
213  else
214  do_add_man_viewer_info(name, len, value);
215 
216  return 0;
217 }
218 
219 static int add_man_viewer_info(const char *var, const char *value)
220 {
221  const char *name = var + 4;
222  const char *subkey = strrchr(name, '.');
223 
224  if (!subkey)
225  return error("Config with no key for man viewer: %s", name);
226 
227  if (!strcmp(subkey, ".path")) {
228  if (!value)
229  return config_error_nonbool(var);
230  return add_man_viewer_path(name, subkey - name, value);
231  }
232  if (!strcmp(subkey, ".cmd")) {
233  if (!value)
234  return config_error_nonbool(var);
235  return add_man_viewer_cmd(name, subkey - name, value);
236  }
237 
238  warning("'%s': unsupported man viewer sub key.", subkey);
239  return 0;
240 }
241 
242 static int perf_help_config(const char *var, const char *value, void *cb)
243 {
244  enum help_format *help_formatp = cb;
245 
246  if (!strcmp(var, "help.format")) {
247  if (!value)
248  return config_error_nonbool(var);
249  *help_formatp = parse_help_format(value);
250  if (*help_formatp == HELP_FORMAT_NONE)
251  return -1;
252  return 0;
253  }
254  if (!strcmp(var, "man.viewer")) {
255  if (!value)
256  return config_error_nonbool(var);
257  add_man_viewer(value);
258  return 0;
259  }
260  if (!prefixcmp(var, "man."))
261  return add_man_viewer_info(var, value);
262 
263  return perf_default_config(var, value, cb);
264 }
265 
266 static struct cmdnames main_cmds, other_cmds;
267 
269 {
270  unsigned int i, longest = 0;
271 
272  for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
273  if (longest < strlen(common_cmds[i].name))
274  longest = strlen(common_cmds[i].name);
275  }
276 
277  puts(" The most commonly used perf commands are:");
278  for (i = 0; i < ARRAY_SIZE(common_cmds); i++) {
279  printf(" %-*s ", longest, common_cmds[i].name);
280  puts(common_cmds[i].help);
281  }
282 }
283 
284 static int is_perf_command(const char *s)
285 {
286  return is_in_cmdlist(&main_cmds, s) ||
287  is_in_cmdlist(&other_cmds, s);
288 }
289 
290 static const char *prepend(const char *prefix, const char *cmd)
291 {
292  size_t pre_len = strlen(prefix);
293  size_t cmd_len = strlen(cmd);
294  char *p = malloc(pre_len + cmd_len + 1);
295  memcpy(p, prefix, pre_len);
296  strcpy(p + pre_len, cmd);
297  return p;
298 }
299 
300 static const char *cmd_to_page(const char *perf_cmd)
301 {
302  if (!perf_cmd)
303  return "perf";
304  else if (!prefixcmp(perf_cmd, "perf"))
305  return perf_cmd;
306  else
307  return prepend("perf-", perf_cmd);
308 }
309 
310 static void setup_man_path(void)
311 {
312  struct strbuf new_path = STRBUF_INIT;
313  const char *old_path = getenv("MANPATH");
314 
315  /* We should always put ':' after our path. If there is no
316  * old_path, the ':' at the end will let 'man' to try
317  * system-wide paths after ours to find the manual page. If
318  * there is old_path, we need ':' as delimiter. */
319  strbuf_addstr(&new_path, system_path(PERF_MAN_PATH));
320  strbuf_addch(&new_path, ':');
321  if (old_path)
322  strbuf_addstr(&new_path, old_path);
323 
324  setenv("MANPATH", new_path.buf, 1);
325 
326  strbuf_release(&new_path);
327 }
328 
329 static void exec_viewer(const char *name, const char *page)
330 {
331  const char *info = get_man_viewer_info(name);
332 
333  if (!strcasecmp(name, "man"))
334  exec_man_man(info, page);
335  else if (!strcasecmp(name, "woman"))
336  exec_woman_emacs(info, page);
337  else if (!strcasecmp(name, "konqueror"))
338  exec_man_konqueror(info, page);
339  else if (info)
340  exec_man_cmd(info, page);
341  else
342  warning("'%s': unknown man viewer.", name);
343 }
344 
345 static int show_man_page(const char *perf_cmd)
346 {
347  struct man_viewer_list *viewer;
348  const char *page = cmd_to_page(perf_cmd);
349  const char *fallback = getenv("PERF_MAN_VIEWER");
350 
351  setup_man_path();
352  for (viewer = man_viewer_list; viewer; viewer = viewer->next)
353  exec_viewer(viewer->name, page); /* will return when unable */
354 
355  if (fallback)
356  exec_viewer(fallback, page);
357  exec_viewer("man", page);
358 
359  pr_err("no man viewer handled the request");
360  return -1;
361 }
362 
363 static int show_info_page(const char *perf_cmd)
364 {
365  const char *page = cmd_to_page(perf_cmd);
366  setenv("INFOPATH", system_path(PERF_INFO_PATH), 1);
367  execlp("info", "info", "perfman", page, NULL);
368  return -1;
369 }
370 
371 static int get_html_page_path(struct strbuf *page_path, const char *page)
372 {
373  struct stat st;
374  const char *html_path = system_path(PERF_HTML_PATH);
375 
376  /* Check that we have a perf documentation directory. */
377  if (stat(mkpath("%s/perf.html", html_path), &st)
378  || !S_ISREG(st.st_mode)) {
379  pr_err("'%s': not a documentation directory.", html_path);
380  return -1;
381  }
382 
383  strbuf_init(page_path, 0);
384  strbuf_addf(page_path, "%s/%s.html", html_path, page);
385 
386  return 0;
387 }
388 
389 /*
390  * If open_html is not defined in a platform-specific way (see for
391  * example compat/mingw.h), we use the script web--browse to display
392  * HTML.
393  */
394 #ifndef open_html
395 static void open_html(const char *path)
396 {
397  execl_perf_cmd("web--browse", "-c", "help.browser", path, NULL);
398 }
399 #endif
400 
401 static int show_html_page(const char *perf_cmd)
402 {
403  const char *page = cmd_to_page(perf_cmd);
404  struct strbuf page_path; /* it leaks but we exec bellow */
405 
406  if (get_html_page_path(&page_path, page) != 0)
407  return -1;
408 
409  open_html(page_path.buf);
410 
411  return 0;
412 }
413 
414 int cmd_help(int argc, const char **argv, const char *prefix __maybe_unused)
415 {
416  bool show_all = false;
418  struct option builtin_help_options[] = {
419  OPT_BOOLEAN('a', "all", &show_all, "print all available commands"),
420  OPT_SET_UINT('m', "man", &help_format, "show man page", HELP_FORMAT_MAN),
421  OPT_SET_UINT('w', "web", &help_format, "show manual in web browser",
423  OPT_SET_UINT('i', "info", &help_format, "show info page",
425  OPT_END(),
426  };
427  const char * const builtin_help_usage[] = {
428  "perf help [--all] [--man|--web|--info] [command]",
429  NULL
430  };
431  const char *alias;
432  int rc = 0;
433 
434  load_command_list("perf-", &main_cmds, &other_cmds);
435 
436  perf_config(perf_help_config, &help_format);
437 
438  argc = parse_options(argc, argv, builtin_help_options,
439  builtin_help_usage, 0);
440 
441  if (show_all) {
442  printf("\n usage: %s\n\n", perf_usage_string);
443  list_commands("perf commands", &main_cmds, &other_cmds);
444  printf(" %s\n\n", perf_more_info_string);
445  return 0;
446  }
447 
448  if (!argv[0]) {
449  printf("\n usage: %s\n\n", perf_usage_string);
451  printf("\n %s\n\n", perf_more_info_string);
452  return 0;
453  }
454 
455  alias = alias_lookup(argv[0]);
456  if (alias && !is_perf_command(argv[0])) {
457  printf("`perf %s' is aliased to `%s'\n", argv[0], alias);
458  return 0;
459  }
460 
461  switch (help_format) {
462  case HELP_FORMAT_MAN:
463  rc = show_man_page(argv[0]);
464  break;
465  case HELP_FORMAT_INFO:
466  rc = show_info_page(argv[0]);
467  break;
468  case HELP_FORMAT_WEB:
469  rc = show_html_page(argv[0]);
470  break;
471  case HELP_FORMAT_NONE:
472  /* fall-through */
473  default:
474  rc = -1;
475  break;
476  }
477 
478  return rc;
479 }