// // MAIN // int main(int argc, char **argv) { int res = EXIT_SUCCESS; sinsp* inspector = NULL; vector<string> infiles; string outfile; int op; uint64_t cnt = -1; bool quiet = false; bool absolute_times = false; bool is_filter_display = false; bool verbose = false; bool list_flds = false; bool print_progress = false; bool compress = false; sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL; sinsp_filter* display_filter = NULL; double duration = 1; captureinfo cinfo; string output_format; uint32_t snaplen = 0; int long_index = 0; int32_t n_filterargs = 0; int cflag = 0; string cname; vector<summary_table_entry>* summary_table = NULL; string timefmt = "%evt.time"; static struct option long_options[] = { {"print-ascii", no_argument, 0, 'A' }, {"abstimes", no_argument, 0, 'a' }, #ifdef HAS_CHISELS {"chisel", required_argument, 0, 'c' }, {"list-chisels", no_argument, &cflag, 1 }, #endif {"compress", no_argument, 0, 'z' }, {"displayflt", no_argument, 0, 'd' }, {"debug", no_argument, 0, 'D'}, {"help", no_argument, 0, 'h' }, #ifdef HAS_CHISELS {"chisel-info", required_argument, 0, 'i' }, #endif {"json", no_argument, 0, 'j' }, {"list", no_argument, 0, 'l' }, {"list-events", no_argument, 0, 'L' }, {"numevents", required_argument, 0, 'n' }, {"progress", required_argument, 0, 'P' }, {"print", required_argument, 0, 'p' }, {"quiet", no_argument, 0, 'q' }, {"readfile", required_argument, 0, 'r' }, {"snaplen", required_argument, 0, 's' }, {"summary", no_argument, 0, 'S' }, {"timetype", required_argument, 0, 't' }, {"verbose", no_argument, 0, 'v' }, {"writefile", required_argument, 0, 'w' }, {"print-hex", no_argument, 0, 'x'}, {"print-hex-ascii", no_argument, 0, 'X'}, {0, 0, 0, 0} }; output_format = "*%evt.num <TIME> %evt.cpu %proc.name (%thread.tid) %evt.dir %evt.type %evt.args"; // output_format = DEFAULT_OUTPUT_STR; try { inspector = new sinsp(); #ifdef HAS_CHISELS add_chisel_dirs(inspector); #endif // // Parse the args // while((op = getopt_long(argc, argv, "Aac:dDhi:jlLn:Pp:qr:Ss:t:vw:xXz", long_options, &long_index)) != -1) { switch(op) { case 'A': if(event_buffer_format != sinsp_evt::PF_NORMAL) { fprintf(stderr, "you cannot specify more than one output format\n"); delete inspector; return EXIT_SUCCESS; } event_buffer_format = sinsp_evt::PF_EOLS; break; case 'a': absolute_times = true; break; case 0: if(cflag != 1 && cflag != 2) { break; } if(cflag == 2) { cname = optarg; } #ifdef HAS_CHISELS case 'c': { if(cflag == 0) { string ostr(optarg); if(ostr.size() >= 1) { if(ostr == "l") { cflag = 1; } } } if(cflag == 1) { vector<chisel_desc> chlist; sinsp_chisel::get_chisel_list(&chlist); list_chisels(&chlist, true); delete inspector; return EXIT_SUCCESS; } sinsp_chisel* ch = new sinsp_chisel(inspector, optarg); parse_chisel_args(ch, inspector, optind, argc, argv, &n_filterargs); g_chisels.push_back(ch); } #endif break; case 'D': inspector->set_debug_mode(true); break; #ifdef HAS_CHISELS // --chisel-info and -i case 'i': { cname = optarg; vector<chisel_desc> chlist; sinsp_chisel::get_chisel_list(&chlist); for(uint32_t j = 0; j < chlist.size(); j++) { if(chlist[j].m_name == cname) { print_chisel_info(&chlist[j]); delete inspector; return EXIT_SUCCESS; } } throw sinsp_exception("chisel " + cname + " not found - use -cl to list them."); } break; #endif case 'd': is_filter_display = true; break; case 'j': // throw sinsp_exception("json output not yet implemented"); if(event_buffer_format != sinsp_evt::PF_NORMAL) { fprintf(stderr, "you cannot specify more than one output format\n"); delete inspector; return EXIT_SUCCESS; } event_buffer_format = sinsp_evt::PF_JSON; break; case 'h': usage(); delete inspector; return EXIT_SUCCESS; case 'l': list_flds = true; break; case 'L': list_events(inspector); delete inspector; return EXIT_SUCCESS; case 'n': cnt = atoi(optarg); if(cnt <= 0) { throw sinsp_exception(string("invalid packet count") + optarg); res = EXIT_FAILURE; goto exit; } break; case 'P': print_progress = true; break; case 'p': if(string(optarg) == "p") { // // -pp shows the default output format, useful if the user wants to tweak it. // replace_in_place(output_format, "<TIME>", timefmt); printf("%s\n", output_format.c_str()); delete inspector; return EXIT_SUCCESS; } else { output_format = optarg; } break; case 'q': quiet = true; break; case 'r': infiles.push_back(optarg); break; case 'S': summary_table = new vector<summary_table_entry>; for(uint32_t j = 0; j < PPM_EVENT_MAX; j++) { summary_table->push_back(summary_table_entry(j, false)); } for(uint32_t j = 0; j < PPM_SC_MAX * 2; j++) { summary_table->push_back(summary_table_entry(j, true)); } break; case 's': snaplen = atoi(optarg); break; case 't': { string tms(optarg); if(tms == "h") { timefmt = "%evt.time"; } else if(tms == "a") { timefmt = "%evt.rawtime.s.%evt.rawtime.ns"; } else if(tms == "r") { timefmt = "%evt.reltime.s.%evt.reltime.ns"; } else if(tms == "d") { timefmt = "%evt.latency.s.%evt.latency.ns"; } } break; case 'v': verbose = true; break; case 'w': outfile = optarg; quiet = true; break; case 'x': if(event_buffer_format != sinsp_evt::PF_NORMAL) { fprintf(stderr, "you cannot specify more than one output format\n"); delete inspector; return EXIT_SUCCESS; } event_buffer_format = sinsp_evt::PF_HEX; break; case 'X': if(event_buffer_format != sinsp_evt::PF_NORMAL) { fprintf(stderr, "you cannot specify more than one output format\n"); delete inspector; return EXIT_SUCCESS; } event_buffer_format = sinsp_evt::PF_HEXASCII; break; case 'z': compress = true; break; default: break; } } inspector->set_buffer_format(event_buffer_format); // // If -l was specified, print the fields and exit // if(list_flds) { if(verbose) { // // -ll shows the fields verbosely, i.e. with more information // like the type // list_fields(true); } else { list_fields(false); } res = EXIT_SUCCESS; goto exit; } string filter; // // the filter is at the end of the command line // if(optind + n_filterargs < argc) { #ifdef HAS_FILTERING for(int32_t j = optind + n_filterargs; j < argc; j++) { filter += argv[j]; if(j < argc) { filter += " "; } } if(is_filter_display) { display_filter = new sinsp_filter(inspector, filter); } #else fprintf(stderr, "filtering not compiled.\n"); res = EXIT_FAILURE; goto exit; #endif } if(signal(SIGINT, signal_callback) == SIG_ERR) { fprintf(stderr, "An error occurred while setting SIGINT signal handler.\n"); res = EXIT_FAILURE; goto exit; } if(signal(SIGTERM, signal_callback) == SIG_ERR) { fprintf(stderr, "An error occurred while setting SIGTERM signal handler.\n"); res = EXIT_FAILURE; goto exit; } // // Insert the right time format based on the -t flag // replace_in_place(output_format, "<TIME>", timefmt); // // Create the event formatter // sinsp_evt_formatter formatter(inspector, output_format); for(uint32_t j = 0; j < infiles.size() || infiles.size() == 0; j++) { #ifdef HAS_FILTERING if(filter.size() && !is_filter_display) { inspector->set_filter(filter); } #endif // // Launch the capture // bool open_success = true; if(infiles.size() != 0) { initialize_chisels(); // // We have a file to open // inspector->open(infiles[j]); } else { if(j > 0) { break; } initialize_chisels(); // // No file to open, this is a live capture // #if defined(HAS_CAPTURE) if(print_progress) { fprintf(stderr, "the -P flag cannot be used with live captures.\n"); res = EXIT_FAILURE; goto exit; } try { inspector->open(""); } catch(sinsp_exception e) { open_success = false; } #else // // Starting live capture // If this fails on Windows and OSX, don't try with any driver // inspector->open(""); #endif // // Starting the live capture failed, try to load the driver with // modprobe. // if(!open_success) { open_success = true; system("modprobe sysdig-probe > /dev/null 2> /dev/null"); inspector->open(""); } } if(snaplen != 0) { inspector->set_snaplen(snaplen); } duration = ((double)clock()) / CLOCKS_PER_SEC; if(outfile != "") { inspector->autodump_start(outfile, compress); } // // Notify the chisels that the capture is starting // chisels_on_capture_start(); cinfo = do_inspect(inspector, cnt, quiet, absolute_times, print_progress, display_filter, summary_table, &formatter); duration = ((double)clock()) / CLOCKS_PER_SEC - duration; scap_stats cstats; inspector->get_capture_stats(&cstats); if(verbose) { fprintf(stderr, "Driver Events:%" PRIu64 "\nDriver Drops:%" PRIu64 "\n", cstats.n_evts, cstats.n_drops); fprintf(stderr, "Elapsed time: %.3lf, Captured Events: %" PRIu64 ", %.2lf eps\n", duration, cinfo.m_nevts, (double)cinfo.m_nevts / duration); } // // Done. Close the capture. // inspector->close(); } } catch(sinsp_exception& e) { cerr << e.what() << endl; handle_end_of_file(print_progress); res = EXIT_FAILURE; } catch(...) { handle_end_of_file(print_progress); res = EXIT_FAILURE; } exit: // // If there's a summary table, sort and print it // if(summary_table != NULL) { print_summary_table(inspector, summary_table, 100); } free_chisels(); if(inspector) { delete inspector; } if(display_filter) { delete display_filter; } #ifdef _WIN32 _CrtDumpMemoryLeaks(); #endif return res; }
// // ARGUMENT PARSING AND PROGRAM SETUP // sysdig_init_res sysdig_init(int argc, char **argv) { sysdig_init_res res; sinsp* inspector = NULL; vector<string> infiles; string outfile; int op; uint64_t cnt = -1; bool quiet = false; bool is_filter_display = false; bool verbose = false; bool list_flds = false; bool list_flds_markdown = false; bool print_progress = false; bool compress = false; sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL; sinsp_filter* display_filter = NULL; double duration = 1; int duration_to_tot = 0; captureinfo cinfo; string output_format; uint32_t snaplen = 0; int long_index = 0; int32_t n_filterargs = 0; int cflag = 0; bool jflag = false; bool unbuf_flag = false; bool filter_proclist_flag = false; string cname; vector<summary_table_entry>* summary_table = NULL; string* k8s_api = 0; string* k8s_api_cert = 0; string* mesos_api = 0; // These variables are for the cycle_writer engine int duration_seconds = 0; int rollover_mb = 0; int file_limit = 0; unsigned long event_limit = 0L; static struct option long_options[] = { {"print-ascii", no_argument, 0, 'A' }, {"print-base64", no_argument, 0, 'b' }, #ifdef HAS_CHISELS {"chisel", required_argument, 0, 'c' }, {"list-chisels", no_argument, &cflag, 1 }, #endif {"displayflt", no_argument, 0, 'd' }, {"debug", no_argument, 0, 'D'}, {"exclude-users", no_argument, 0, 'E' }, {"event-limit", required_argument, 0, 'e'}, {"fatfile", no_argument, 0, 'F'}, {"filter-proclist", no_argument, 0, 0 }, {"seconds", required_argument, 0, 'G' }, {"help", no_argument, 0, 'h' }, #ifdef HAS_CHISELS {"chisel-info", required_argument, 0, 'i' }, #endif {"file-size", required_argument, 0, 'C' }, {"json", no_argument, 0, 'j' }, {"k8s-api", required_argument, 0, 'k'}, {"k8s-api-cert", required_argument, 0, 'K' }, {"list", no_argument, 0, 'l' }, {"list-events", no_argument, 0, 'L' }, {"list-markdown", no_argument, 0, 0 }, {"mesos-api", required_argument, 0, 'm'}, {"numevents", required_argument, 0, 'n' }, {"progress", required_argument, 0, 'P' }, {"print", required_argument, 0, 'p' }, {"quiet", no_argument, 0, 'q' }, {"readfile", required_argument, 0, 'r' }, {"snaplen", required_argument, 0, 's' }, {"summary", no_argument, 0, 'S' }, {"timetype", required_argument, 0, 't' }, {"unbuffered", no_argument, 0, 0 }, {"verbose", no_argument, 0, 'v' }, {"version", no_argument, 0, 0 }, {"writefile", required_argument, 0, 'w' }, {"limit", required_argument, 0, 'W' }, {"print-hex", no_argument, 0, 'x'}, {"print-hex-ascii", no_argument, 0, 'X'}, {"compress", no_argument, 0, 'z' }, {0, 0, 0, 0} }; output_format = "*%evt.num %evt.outputtime %evt.cpu %proc.name (%thread.tid) %evt.dir %evt.type %evt.info"; try { inspector = new sinsp(); #ifdef HAS_CHISELS add_chisel_dirs(inspector); #endif // // Parse the args // while((op = getopt_long(argc, argv, "Abc:" "C:" "dDEe:F" "G:" "hi:jk:K:lLm:M:Nn:Pp:qr:Ss:t:v" "W:" "w:xXz", long_options, &long_index)) != -1) { switch(op) { case 'A': if(event_buffer_format != sinsp_evt::PF_NORMAL) { fprintf(stderr, "you cannot specify more than one output format\n"); delete inspector; return sysdig_init_res(EXIT_SUCCESS); } event_buffer_format = sinsp_evt::PF_EOLS; break; case 'b': if(event_buffer_format != sinsp_evt::PF_NORMAL) { fprintf(stderr, "you cannot specify more than one output format\n"); delete inspector; return sysdig_init_res(EXIT_SUCCESS); } event_buffer_format = sinsp_evt::PF_BASE64; break; case 0: if(cflag != 1 && cflag != 2) { break; } if(cflag == 2) { cname = optarg; } #ifdef HAS_CHISELS case 'c': { if(cflag == 0) { string ostr(optarg); if(ostr.size() >= 1) { if(ostr == "l") { cflag = 1; } } } if(cflag == 1) { vector<chisel_desc> chlist; sinsp_chisel::get_chisel_list(&chlist); list_chisels(&chlist, true); delete inspector; return sysdig_init_res(EXIT_SUCCESS); } sinsp_chisel* ch = new sinsp_chisel(inspector, optarg); parse_chisel_args(ch, inspector, optind, argc, argv, &n_filterargs); g_chisels.push_back(ch); } #endif break; // File-size case 'C': rollover_mb = atoi(optarg); if(rollover_mb <= 0) { throw sinsp_exception(string("invalid file size") + optarg); res.m_res = EXIT_FAILURE; goto exit; } break; case 'D': inspector->set_debug_mode(true); inspector->set_log_stderr(); break; case 'E': inspector->set_import_users(false); break; case 'e': event_limit = strtoul(optarg, NULL, 0); if(event_limit <= 0) { throw sinsp_exception(string("invalid parameter 'number of events' ") + optarg); res.m_res = EXIT_FAILURE; goto exit; } break; case 'F': inspector->set_fatfile_dump_mode(true); break; // Number of seconds between roll-over case 'G': duration_seconds = atoi(optarg); if(duration_seconds <= 0) { throw sinsp_exception(string("invalid duration") + optarg); res.m_res = EXIT_FAILURE; goto exit; } break; #ifdef HAS_CHISELS // --chisel-info and -i case 'i': { cname = optarg; vector<chisel_desc> chlist; sinsp_chisel::get_chisel_list(&chlist); for(uint32_t j = 0; j < chlist.size(); j++) { if(chlist[j].m_name == cname) { print_chisel_info(&chlist[j]); delete inspector; return sysdig_init_res(EXIT_SUCCESS); } } throw sinsp_exception("chisel " + cname + " not found - use -cl to list them."); } break; #endif case 'd': is_filter_display = true; break; case 'j': // // set the json flag to 1 for now, the data format will depend from the print format parameters // jflag = true; break; case 'k': k8s_api = new string(optarg); break; case 'K': k8s_api_cert = new string(optarg); break; case 'h': usage(); delete inspector; return sysdig_init_res(EXIT_SUCCESS); case 'l': list_flds = true; break; case 'L': list_events(inspector); delete inspector; return sysdig_init_res(EXIT_SUCCESS); case 'm': mesos_api = new string(optarg); break; case 'M': duration_to_tot = atoi(optarg); if(duration_to_tot <= 0) { throw sinsp_exception(string("invalid duration") + optarg); res.m_res = EXIT_FAILURE; goto exit; } break; case 'N': inspector->set_hostname_and_port_resolution_mode(false); break; case 'n': try { cnt = sinsp_numparser::parseu64(optarg); } catch(...) { throw sinsp_exception("can't parse the -n argument, make sure it's a number"); } if(cnt <= 0) { throw sinsp_exception(string("invalid event count ") + optarg); res.m_res = EXIT_FAILURE; goto exit; } break; case 'P': print_progress = true; break; case 'p': if(string(optarg) == "p") { // -pp shows the default output format, useful if the user wants to tweak it. printf("%s\n", output_format.c_str()); delete inspector; return sysdig_init_res(EXIT_SUCCESS); } else if(string(optarg) == "c" || string(optarg) == "container") { output_format = "*%evt.num %evt.outputtime %evt.cpu %container.name (%container.id) %proc.name (%thread.tid:%thread.vtid) %evt.dir %evt.type %evt.info"; // This enables chisels to determine if they should print container information if(inspector != NULL) { inspector->set_print_container_data(true); } } else if(string(optarg) == "k" || string(optarg) == "kubernetes") { output_format = "*%evt.num %evt.outputtime %evt.cpu %k8s.pod.name (%container.id) %proc.name (%thread.tid:%thread.vtid) %evt.dir %evt.type %evt.info"; // This enables chisels to determine if they should print container information if(inspector != NULL) { inspector->set_print_container_data(true); } } else if(string(optarg) == "m" || string(optarg) == "mesos") { output_format = "*%evt.num %evt.outputtime %evt.cpu %mesos.task.name (%container.id) %proc.name (%thread.tid:%thread.vtid) %evt.dir %evt.type %evt.info"; // This enables chisels to determine if they should print container information if(inspector != NULL) { inspector->set_print_container_data(true); } } else { output_format = optarg; } break; case 'q': quiet = true; break; case 'r': infiles.push_back(optarg); k8s_api = new string(); mesos_api = new string(); break; case 'S': summary_table = new vector<summary_table_entry>; for(uint32_t j = 0; j < PPM_EVENT_MAX; j++) { summary_table->push_back(summary_table_entry(j, false)); } for(uint32_t j = 0; j < PPM_SC_MAX * 2; j++) { summary_table->push_back(summary_table_entry(j, true)); } break; case 's': snaplen = atoi(optarg); break; case 't': { string tms(optarg); if(tms == "h" || tms == "a" || tms == "r" || tms == "d" || tms == "D") { inspector->set_time_output_mode(tms.c_str()[0]); } else { fprintf(stderr, "invalid modifier for flag -t\n"); delete inspector; return sysdig_init_res(EXIT_FAILURE); } } break; case 'v': verbose = true; break; case 'w': outfile = optarg; quiet = true; break; // Number of capture files to cycle through case 'W': file_limit = atoi(optarg); if(file_limit <= 0) { throw sinsp_exception(string("invalid file limit") + optarg); res.m_res = EXIT_FAILURE; goto exit; } break; case 'x': if(event_buffer_format != sinsp_evt::PF_NORMAL) { fprintf(stderr, "you cannot specify more than one output format\n"); delete inspector; return sysdig_init_res(EXIT_FAILURE); } event_buffer_format = sinsp_evt::PF_HEX; break; case 'X': if(event_buffer_format != sinsp_evt::PF_NORMAL) { fprintf(stderr, "you cannot specify more than one output format\n"); delete inspector; return sysdig_init_res(EXIT_FAILURE); } event_buffer_format = sinsp_evt::PF_HEXASCII; break; case 'z': compress = true; break; // getopt_long : '?' for an ambiguous match or an extraneous parameter case '?': delete inspector; return sysdig_init_res(EXIT_FAILURE); break; default: break; } if(string(long_options[long_index].name) == "version") { printf("sysdig version %s\n", SYSDIG_VERSION); delete inspector; return sysdig_init_res(EXIT_SUCCESS); } if(string(long_options[long_index].name) == "unbuffered") { unbuf_flag = true; } if(string(long_options[long_index].name) == "filter-proclist") { filter_proclist_flag = true; } if(string(long_options[long_index].name) == "list-markdown") { list_flds = true; list_flds_markdown = true; } } // // If -j was specified the event_buffer_format must be rewritten to account for it // if(jflag) { switch (event_buffer_format) { case sinsp_evt::PF_NORMAL: event_buffer_format = sinsp_evt::PF_JSON; break; case sinsp_evt::PF_EOLS: event_buffer_format = sinsp_evt::PF_JSONEOLS; break; case sinsp_evt::PF_HEX: event_buffer_format = sinsp_evt::PF_JSONHEX; break; case sinsp_evt::PF_HEXASCII: event_buffer_format = sinsp_evt::PF_JSONHEXASCII; break; case sinsp_evt::PF_BASE64: event_buffer_format = sinsp_evt::PF_JSONBASE64; break; default: // do nothing break; } } inspector->set_buffer_format(event_buffer_format); // // If -l was specified, print the fields and exit // if(list_flds) { if(verbose) { // // -ll shows the fields verbosely, i.e. with more information // like the type // list_fields(true, list_flds_markdown); } else { list_fields(false, list_flds_markdown); } res.m_res = EXIT_SUCCESS; goto exit; } string filter; // // the filter is at the end of the command line // if(optind + n_filterargs < argc) { #ifdef HAS_FILTERING for(int32_t j = optind + n_filterargs; j < argc; j++) { filter += argv[j]; if(j < argc - 1) { filter += " "; } } if(is_filter_display) { sinsp_filter_compiler compiler(inspector, filter); display_filter = compiler.compile(); } #else fprintf(stderr, "filtering not compiled.\n"); res.m_res = EXIT_FAILURE; goto exit; #endif } if(signal(SIGINT, signal_callback) == SIG_ERR) { fprintf(stderr, "An error occurred while setting SIGINT signal handler.\n"); res.m_res = EXIT_FAILURE; goto exit; } if(signal(SIGTERM, signal_callback) == SIG_ERR) { fprintf(stderr, "An error occurred while setting SIGTERM signal handler.\n"); res.m_res = EXIT_FAILURE; goto exit; } // // Create the event formatter // sinsp_evt_formatter formatter(inspector, output_format); // // Set output buffers len // if(!verbose && g_chisels.size() == 0) { inspector->set_max_evt_output_len(80); } // // Determine if we need to filter when dumping to file // if(filter_proclist_flag) { if(filter != "") { if(infiles.size() == 0) { fprintf(stderr, "--filter-proclist not supported with live captures.\n"); res.m_res = EXIT_FAILURE; goto exit; } inspector->filter_proc_table_when_saving(true); } else { fprintf(stderr, "you must specify a filter if you use --filter-proclist.\n"); res.m_res = EXIT_FAILURE; goto exit; } } for(uint32_t j = 0; j < infiles.size() || infiles.size() == 0; j++) { #ifdef HAS_FILTERING if(filter.size() && !is_filter_display) { inspector->set_filter(filter); } #endif // // Launch the capture // if(infiles.size() != 0) { initialize_chisels(); // // We have a file to open // inspector->open(infiles[j]); } else { if(j > 0) { break; } initialize_chisels(); // // No file to open, this is a live capture // #if defined(HAS_CAPTURE) bool open_success = true; if(print_progress) { fprintf(stderr, "the -P flag cannot be used with live captures.\n"); res.m_res = EXIT_FAILURE; goto exit; } try { inspector->open(""); } catch(sinsp_exception e) { open_success = false; } // // Starting the live capture failed, try to load the driver with // modprobe. // if(!open_success) { open_success = true; if(system("modprobe " PROBE_NAME " > /dev/null 2> /dev/null")) { fprintf(stderr, "Unable to load the driver\n"); } inspector->open(""); } #else // // Starting live capture // If this fails on Windows and OSX, don't try with any driver // inspector->open(""); #endif // // Enable gathering the CPU from the kernel module // inspector->set_get_procs_cpu_from_driver(true); } if(snaplen != 0) { inspector->set_snaplen(snaplen); } duration = ((double)clock()) / CLOCKS_PER_SEC; if(outfile != "") { inspector->setup_cycle_writer(outfile, rollover_mb, duration_seconds, file_limit, event_limit, compress); inspector->autodump_next_file(); } // // Notify the chisels that the capture is starting // chisels_on_capture_start(); // // run k8s, if required // if(k8s_api) { if(!k8s_api_cert) { if(char* k8s_cert_env = getenv("SYSDIG_K8S_API_CERT")) { k8s_api_cert = new string(k8s_cert_env); } } inspector->init_k8s_client(k8s_api, k8s_api_cert, verbose); k8s_api = 0; k8s_api_cert = 0; } else if(char* k8s_api_env = getenv("SYSDIG_K8S_API")) { if(k8s_api_env != NULL) { if(!k8s_api_cert) { if(char* k8s_cert_env = getenv("SYSDIG_K8S_API_CERT")) { k8s_api_cert = new string(k8s_cert_env); } } k8s_api = new string(k8s_api_env); inspector->init_k8s_client(k8s_api, k8s_api_cert, verbose); } else { delete k8s_api; delete k8s_api_cert; } k8s_api = 0; k8s_api_cert = 0; } // // run mesos, if required // if(mesos_api) { inspector->init_mesos_client(mesos_api, verbose); } else if(char* mesos_api_env = getenv("SYSDIG_MESOS_API")) { if(mesos_api_env != NULL) { mesos_api = new string(mesos_api_env); inspector->init_mesos_client(mesos_api, verbose); } } delete mesos_api; mesos_api = 0; cinfo = do_inspect(inspector, cnt, duration_to_tot, quiet, jflag, unbuf_flag, print_progress, display_filter, summary_table, &formatter); duration = ((double)clock()) / CLOCKS_PER_SEC - duration; scap_stats cstats; inspector->get_capture_stats(&cstats); if(verbose) { fprintf(stderr, "Driver Events:%" PRIu64 "\nDriver Drops:%" PRIu64 "\n", cstats.n_evts, cstats.n_drops); fprintf(stderr, "Elapsed time: %.3lf, Captured Events: %" PRIu64 ", %.2lf eps\n", duration, cinfo.m_nevts, (double)cinfo.m_nevts / duration); } // // Done. Close the capture. // inspector->close(); } } catch(sinsp_capture_interrupt_exception&) { handle_end_of_file(print_progress); } catch(sinsp_exception& e) { cerr << e.what() << endl; handle_end_of_file(print_progress); res.m_res = EXIT_FAILURE; } catch(...) { handle_end_of_file(print_progress); res.m_res = EXIT_FAILURE; } exit: // // If any of the chisels is requesting another run, // for(vector<sinsp_chisel*>::iterator it = g_chisels.begin(); it != g_chisels.end(); ++it) { string na; if((*it)->get_nextrun_args(&na)) { res.m_next_run_args = sinsp_split(na, ' '); } } // // If there's a summary table, sort and print it // if(summary_table != NULL) { print_summary_table(inspector, summary_table, 100); } // // Free all the stuff that was allocated // free_chisels(); if(inspector) { delete inspector; } if(display_filter) { delete display_filter; } return res; }
// // ARGUMENT PARSING AND PROGRAM SETUP // sysdig_init_res sysdig_init(int argc, char **argv) { sysdig_init_res res; sinsp* inspector = NULL; vector<string> infiles; string outfile; int op; uint64_t cnt = -1; bool quiet = false; bool is_filter_display = false; bool verbose = false; bool list_flds = false; bool print_progress = false; bool compress = false; sinsp_evt::param_fmt event_buffer_format = sinsp_evt::PF_NORMAL; sinsp_filter* display_filter = NULL; double duration = 1; captureinfo cinfo; string output_format; uint32_t snaplen = 0; int long_index = 0; int32_t n_filterargs = 0; int cflag = 0; bool jflag = false; string cname; vector<summary_table_entry>* summary_table = NULL; string timefmt = "%evt.time"; // These variables are for the cycle_writer engine int duration_seconds = 0; int rollover_mb = 0; int file_limit = 0; bool do_cycle = false; static struct option long_options[] = { {"print-ascii", no_argument, 0, 'A' }, {"print-base64", no_argument, 0, 'b' }, #ifdef HAS_CHISELS {"chisel", required_argument, 0, 'c' }, {"list-chisels", no_argument, &cflag, 1 }, #endif {"compress", no_argument, 0, 'z' }, {"displayflt", no_argument, 0, 'd' }, {"debug", no_argument, 0, 'D'}, {"fatfile", no_argument, 0, 'F'}, #ifndef DISABLE_CGW {"seconds", required_argument, 0, 'G' }, #endif {"help", no_argument, 0, 'h' }, #ifdef HAS_CHISELS {"chisel-info", required_argument, 0, 'i' }, #endif #ifndef DISABLE_CGW {"file-size", required_argument, 0, 'C' }, #endif {"json", no_argument, 0, 'j' }, {"list", no_argument, 0, 'l' }, {"list-events", no_argument, 0, 'L' }, {"numevents", required_argument, 0, 'n' }, {"progress", required_argument, 0, 'P' }, {"print", required_argument, 0, 'p' }, {"quiet", no_argument, 0, 'q' }, {"readfile", required_argument, 0, 'r' }, {"snaplen", required_argument, 0, 's' }, {"summary", no_argument, 0, 'S' }, {"timetype", required_argument, 0, 't' }, {"verbose", no_argument, 0, 'v' }, {"version", no_argument, 0, 0 }, {"writefile", required_argument, 0, 'w' }, #ifndef DISABLE_CGW {"limit", required_argument, 0, 'W' }, #endif {"print-hex", no_argument, 0, 'x'}, {"print-hex-ascii", no_argument, 0, 'X'}, {0, 0, 0, 0} }; output_format = "*%evt.num <TIME> %evt.cpu %proc.name (%thread.tid) %evt.dir %evt.type %evt.info"; // output_format = DEFAULT_OUTPUT_STR; try { inspector = new sinsp(); #ifdef HAS_CHISELS add_chisel_dirs(inspector); #endif // // Parse the args // while((op = getopt_long(argc, argv, "Abc:" #ifndef DISABLE_CGW "C:" #endif "dDF" #ifndef DISABLE_CGW "G:" #endif "hi:jlLn:Pp:qr:Ss:t:v" #ifndef DISABLE_CGW "W:" #endif "w:xXz", long_options, &long_index)) != -1) { switch(op) { case 'A': if(event_buffer_format != sinsp_evt::PF_NORMAL) { fprintf(stderr, "you cannot specify more than one output format\n"); delete inspector; return sysdig_init_res(EXIT_SUCCESS); } event_buffer_format = sinsp_evt::PF_EOLS; break; case 'b': if(event_buffer_format != sinsp_evt::PF_NORMAL) { fprintf(stderr, "you cannot specify more than one output format\n"); delete inspector; return sysdig_init_res(EXIT_SUCCESS); } event_buffer_format = sinsp_evt::PF_BASE64; break; case 0: if(cflag != 1 && cflag != 2) { break; } if(cflag == 2) { cname = optarg; } #ifdef HAS_CHISELS case 'c': { if(cflag == 0) { string ostr(optarg); if(ostr.size() >= 1) { if(ostr == "l") { cflag = 1; } } } if(cflag == 1) { vector<chisel_desc> chlist; sinsp_chisel::get_chisel_list(&chlist); list_chisels(&chlist, true); delete inspector; return sysdig_init_res(EXIT_SUCCESS); } sinsp_chisel* ch = new sinsp_chisel(inspector, optarg); parse_chisel_args(ch, inspector, optind, argc, argv, &n_filterargs); g_chisels.push_back(ch); } #endif break; #ifndef DISABLE_CGW // File-size case 'C': rollover_mb = atoi(optarg); if(rollover_mb <= 0) { throw sinsp_exception(string("invalid file size") + optarg); res.m_res = EXIT_FAILURE; goto exit; } // -C always implicates a cycle do_cycle = true; break; #endif case 'D': inspector->set_debug_mode(true); break; case 'F': inspector->set_fatfile_dump_mode(true); break; #ifndef DISABLE_CGW // Number of seconds between roll-over case 'G': duration_seconds = atoi(optarg); if(duration_seconds <= 0) { throw sinsp_exception(string("invalid duration") + optarg); res.m_res = EXIT_FAILURE; goto exit; } break; #endif #ifdef HAS_CHISELS // --chisel-info and -i case 'i': { cname = optarg; vector<chisel_desc> chlist; sinsp_chisel::get_chisel_list(&chlist); for(uint32_t j = 0; j < chlist.size(); j++) { if(chlist[j].m_name == cname) { print_chisel_info(&chlist[j]); delete inspector; return sysdig_init_res(EXIT_SUCCESS); } } throw sinsp_exception("chisel " + cname + " not found - use -cl to list them."); } break; #endif case 'd': is_filter_display = true; break; case 'j': // // set the json flag to 1 for now, the data format will depend from the print format parameters // jflag = true; break; case 'h': usage(); delete inspector; return sysdig_init_res(EXIT_SUCCESS); case 'l': list_flds = true; break; case 'L': list_events(inspector); delete inspector; return sysdig_init_res(EXIT_SUCCESS); case 'n': cnt = atoi(optarg); if(cnt <= 0) { throw sinsp_exception(string("invalid event count ") + optarg); res.m_res = EXIT_FAILURE; goto exit; } break; case 'P': print_progress = true; break; case 'p': if(string(optarg) == "p") { // // -pp shows the default output format, useful if the user wants to tweak it. // replace_in_place(output_format, "<TIME>", timefmt); printf("%s\n", output_format.c_str()); delete inspector; return sysdig_init_res(EXIT_SUCCESS); } else { output_format = optarg; } break; case 'q': quiet = true; break; case 'r': infiles.push_back(optarg); break; case 'S': summary_table = new vector<summary_table_entry>; for(uint32_t j = 0; j < PPM_EVENT_MAX; j++) { summary_table->push_back(summary_table_entry(j, false)); } for(uint32_t j = 0; j < PPM_SC_MAX * 2; j++) { summary_table->push_back(summary_table_entry(j, true)); } break; case 's': snaplen = atoi(optarg); break; case 't': { string tms(optarg); if(tms == "h") { timefmt = "%evt.time"; } else if(tms == "a") { timefmt = "%evt.rawtime.s.%evt.rawtime.ns"; } else if(tms == "r") { timefmt = "%evt.reltime.s.%evt.reltime.ns"; } else if(tms == "d") { timefmt = "%evt.latency.s.%evt.latency.ns"; } else if(tms == "D") { timefmt = "%evt.deltatime.s.%evt.deltatime.ns"; } else { fprintf(stderr, "invalid modifier for flag -t\n"); delete inspector; return sysdig_init_res(EXIT_FAILURE); } } break; case 'v': verbose = true; break; case 'w': outfile = optarg; quiet = true; break; #ifndef DISABLE_CGW // Number of capture files to cycle through case 'W': file_limit = atoi(optarg); if(file_limit <= 0) { throw sinsp_exception(string("invalid file limit") + optarg); res.m_res = EXIT_FAILURE; goto exit; } break; #endif case 'x': if(event_buffer_format != sinsp_evt::PF_NORMAL) { fprintf(stderr, "you cannot specify more than one output format\n"); delete inspector; return sysdig_init_res(EXIT_FAILURE); } event_buffer_format = sinsp_evt::PF_HEX; break; case 'X': if(event_buffer_format != sinsp_evt::PF_NORMAL) { fprintf(stderr, "you cannot specify more than one output format\n"); delete inspector; return sysdig_init_res(EXIT_FAILURE); } event_buffer_format = sinsp_evt::PF_HEXASCII; break; case 'z': compress = true; break; default: break; } if(string(long_options[long_index].name) == "version") { printf("sysdig version %s\n", SYSDIG_VERSION); delete inspector; return sysdig_init_res(EXIT_SUCCESS); } } // // If -j was specified the event_buffer_format must be rewritten to account for it // if(jflag) { switch (event_buffer_format) { case sinsp_evt::PF_NORMAL: event_buffer_format = sinsp_evt::PF_JSON; break; case sinsp_evt::PF_EOLS: event_buffer_format = sinsp_evt::PF_JSONEOLS; break; case sinsp_evt::PF_HEX: event_buffer_format = sinsp_evt::PF_JSONHEX; break; case sinsp_evt::PF_HEXASCII: event_buffer_format = sinsp_evt::PF_JSONHEXASCII; break; case sinsp_evt::PF_BASE64: event_buffer_format = sinsp_evt::PF_JSONBASE64; break; default: // do nothing break; } } inspector->set_buffer_format(event_buffer_format); // // If -l was specified, print the fields and exit // if(list_flds) { if(verbose) { // // -ll shows the fields verbosely, i.e. with more information // like the type // list_fields(true); } else { list_fields(false); } res.m_res = EXIT_SUCCESS; goto exit; } string filter; // // the filter is at the end of the command line // if(optind + n_filterargs < argc) { #ifdef HAS_FILTERING for(int32_t j = optind + n_filterargs; j < argc; j++) { filter += argv[j]; if(j < argc) { filter += " "; } } if(is_filter_display) { display_filter = new sinsp_filter(inspector, filter); } #else fprintf(stderr, "filtering not compiled.\n"); res.m_res = EXIT_FAILURE; goto exit; #endif } if(signal(SIGINT, signal_callback) == SIG_ERR) { fprintf(stderr, "An error occurred while setting SIGINT signal handler.\n"); res.m_res = EXIT_FAILURE; goto exit; } if(signal(SIGTERM, signal_callback) == SIG_ERR) { fprintf(stderr, "An error occurred while setting SIGTERM signal handler.\n"); res.m_res = EXIT_FAILURE; goto exit; } // // Insert the right time format based on the -t flag // replace_in_place(output_format, "<TIME>", timefmt); // // Create the event formatter // sinsp_evt_formatter formatter(inspector, output_format); for(uint32_t j = 0; j < infiles.size() || infiles.size() == 0; j++) { #ifdef HAS_FILTERING if(filter.size() && !is_filter_display) { inspector->set_filter(filter); } #endif // // Launch the capture // bool open_success = true; if(infiles.size() != 0) { initialize_chisels(); // // We have a file to open // inspector->open(infiles[j]); } else { if(j > 0) { break; } initialize_chisels(); // // No file to open, this is a live capture // #if defined(HAS_CAPTURE) if(print_progress) { fprintf(stderr, "the -P flag cannot be used with live captures.\n"); res.m_res = EXIT_FAILURE; goto exit; } try { inspector->open(""); } catch(sinsp_exception e) { open_success = false; } #else // // Starting live capture // If this fails on Windows and OSX, don't try with any driver // inspector->open(""); #endif // // Starting the live capture failed, try to load the driver with // modprobe. // if(!open_success) { open_success = true; system("modprobe sysdig-probe > /dev/null 2> /dev/null"); inspector->open(""); } } if(snaplen != 0) { inspector->set_snaplen(snaplen); } duration = ((double)clock()) / CLOCKS_PER_SEC; if(outfile != "") { inspector->setup_cycle_writer(outfile, rollover_mb, duration_seconds, file_limit, do_cycle, compress); inspector->autodump_next_file(); } // // Notify the chisels that the capture is starting // chisels_on_capture_start(); cinfo = do_inspect(inspector, cnt, quiet, jflag, print_progress, display_filter, summary_table, &formatter); duration = ((double)clock()) / CLOCKS_PER_SEC - duration; scap_stats cstats; inspector->get_capture_stats(&cstats); if(verbose) { fprintf(stderr, "Driver Events:%" PRIu64 "\nDriver Drops:%" PRIu64 "\n", cstats.n_evts, cstats.n_drops); fprintf(stderr, "Elapsed time: %.3lf, Captured Events: %" PRIu64 ", %.2lf eps\n", duration, cinfo.m_nevts, (double)cinfo.m_nevts / duration); } // // Done. Close the capture. // inspector->close(); } } catch(sinsp_capture_interrupt_exception&) { handle_end_of_file(print_progress); } catch(sinsp_exception& e) { cerr << e.what() << endl; handle_end_of_file(print_progress); res.m_res = EXIT_FAILURE; } catch(...) { handle_end_of_file(print_progress); res.m_res = EXIT_FAILURE; } exit: // // If any of the chisels is requesting another run, // for(vector<sinsp_chisel*>::iterator it = g_chisels.begin(); it != g_chisels.end(); ++it) { string na; if((*it)->get_nextrun_args(&na)) { res.m_next_run_args = sinsp_split(na, ' '); } } // // If there's a summary table, sort and print it // if(summary_table != NULL) { print_summary_table(inspector, summary_table, 100); } // // Free all the stuff that was allocated // free_chisels(); if(inspector) { delete inspector; } if(display_filter) { delete display_filter; } return res; }