+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "shared/log.h"
+#include "crash-manager.h"
+
+static void print_help(const char *name)
+{
+ printf("Syntax: %s [OPTIONS]\n"
+ "\n"
+ " -p --pid=PID PID of dumped process\n"
+ " -u --uid=UID real UID of dumped process\n"
+ " -g --gid=GID real GID of dumped process\n"
+ " -i --tid=TID TID of thread that triggered core dump\n"
+ " -s --signal=SIG number of signal causing dump\n"
+ " -t --time=TIME time of dump, expressed as seconds since the Epoch\n"
+ " -l --live get coredump of running process\n"
+ " -k --kill-after-dump kill after dump (only with --live option)\n"
+ " -r --print print report path to stdout\n"
+ " -o --output output directory\n"
+ " -h --help this message\n"
+ "\n"
+ "for --live option only --pid is required\n"
+ "\n", name);
+}
+
+static bool parse_args(struct crash_info *cinfo, int argc, char *argv[])
+{
+#define QUOTE(member) #member
+#define GET_NUMBER(member) \
+ do {\
+ errno = 0; \
+ cinfo->member##_info = strtol(optarg, NULL, 10); \
+ if (errno != 0) { \
+ _D("%s argument error\n", QUOTE(member)); \
+ printf("%s argument error\n", QUOTE(member)); \
+ return false; \
+ } \
+ } while(0)
+
+ bool result = true;
+ int opt;
+ bool pid_set = false;
+ bool uid_set = false;
+ bool gid_set = false;
+ bool sig_set = false;
+
+ struct option long_options[] = {
+ {"pid", required_argument, NULL, 'p'},
+ {"uid", required_argument, NULL, 'u'},
+ {"gid", required_argument, NULL, 'g'},
+ {"tid", required_argument, NULL, 'i'},
+ {"signal", required_argument, NULL, 's'},
+ {"time", required_argument, NULL, 't'},
+ {"live", no_argument, NULL, 'l'},
+ {"kill-after-dump", no_argument, NULL, 'k'},
+ {"print", no_argument, NULL, 'r'},
+ {"output", required_argument, NULL, 'o'},
+ {"help", no_argument, NULL, 'h'},
+ };
+
+ while ((opt = getopt_long(argc, argv, "p:u:g:i:s:t:hlkro:", long_options, NULL)) != -1) {
+ switch (opt) {
+ case 'p':
+ GET_NUMBER(pid);
+ pid_set = true;
+ break;
+ case 'u':
+ GET_NUMBER(uid);
+ uid_set = true;
+ break;
+ case 'g':
+ GET_NUMBER(gid);
+ gid_set = true;
+ break;
+ case 'i':
+ GET_NUMBER(tid);
+ break;
+ case 's':
+ GET_NUMBER(sig);
+ sig_set = true;
+ break;
+ case 't':
+ GET_NUMBER(time);
+ break;
+ case 'l':
+ cinfo->livedump = true;
+ break;
+ case 'k':
+ cinfo->kill = true;
+ break;
+ case 'r':
+ cinfo->print_result_path = true;
+ break;
+ case 'o':
+ cinfo->output_path = optarg;
+ _D("output path: %s\n", optarg);
+ break;
+ case 'h':
+ default:
+ print_help(argv[0]);
+ return false;
+ }
+ }
+
+ if (!pid_set || (!cinfo->livedump && (!gid_set || !uid_set || !sig_set))) {
+ printf("Not enough parameters.\n\n");
+ print_help(argv[0]);
+ return false;
+ }
+
+ if (cinfo->livedump && sig_set) {
+ printf("--sig can not be used with --live option\n\n");
+ print_help(argv[0]);
+ return false;
+ }
+
+ if (!cinfo->livedump && cinfo->kill) {
+ printf("Option --kill-after-dump can be used only with --live\n");
+ return false;
+ }
+ return result;
+#undef QUOTE
+#undef GET_NUMBER
+}
+
+
+int main(int argc, char *argv[])
+{
+ struct crash_info cinfo;
+
+ /*
+ * prctl(PR_SET_DUMPABLE, 0) is not neccessary. Kernel runs the
+ * crash-manager and sets RLIMIT_CORE to 1 for the process. This is special
+ * value that prevents from running crash-manager recursively.
+ */
+
+ crash_info_init(&cinfo);
+
+ /* Parse args */
+ if (!parse_args(&cinfo, argc, argv))
+ return EXIT_FAILURE;
+
+ int res = crash_manager_direct(&cinfo) ? EXIT_SUCCESS : EXIT_FAILURE;
+
+ crash_manager_free(&cinfo);
+ _I("Exiting with exit code %d", res);
+ return res;
+}