_public_ int sd_journal_send_with_location(const char *file, const char *line, const char *func, const char *format, ...) { int r, i, j; va_list ap; struct iovec *iov = NULL; char *f; va_start(ap, format); i = fill_iovec_sprintf(format, ap, 3, &iov); va_end(ap); if (_unlikely_(i < 0)) { r = i; goto finish; } ALLOCA_CODE_FUNC(f, func); IOVEC_SET_STRING(iov[0], file); IOVEC_SET_STRING(iov[1], line); IOVEC_SET_STRING(iov[2], f); r = sd_journal_sendv(iov, i); finish: for (j = 3; j < i; j++) free(iov[j].iov_base); free(iov); return r; }
/** * ot_log_structured: * @message: Text message to send * @keys: (allow-none) (array zero-terminated=1) (element-type utf8): Optional structured data * * Log structured data in an operating-system specific fashion. The * parameter @opts should be an array of UTF-8 KEY=VALUE strings. * This function does not support binary data. See * http://www.freedesktop.org/software/systemd/man/systemd.journal-fields.html * for more information about fields that can be used on a systemd * system. */ static void ot_log_structured (const char *message, const char *const *keys) { #ifdef HAVE_LIBSYSTEMD const char *const*iter; g_autofree char *msgkey = NULL; guint i, n_opts; struct iovec *iovs; for (n_opts = 0, iter = keys; *iter; iter++, n_opts++) ; n_opts++; /* Add one for MESSAGE= */ iovs = g_alloca (sizeof (struct iovec) * n_opts); for (i = 0, iter = keys; *iter; iter++, i++) { iovs[i].iov_base = (char*)keys[i]; iovs[i].iov_len = strlen (keys[i]); } g_assert(i == n_opts-1); msgkey = g_strconcat ("MESSAGE=", message, NULL); iovs[i].iov_base = msgkey; iovs[i].iov_len = strlen (msgkey); // The code location isn't useful since we're wrapping sd_journal_sendv (iovs, n_opts); #else g_print ("%s\n", message); #endif }
static int journald_entry(FILE *fp) { struct iovec *iovec; char *buf = NULL; ssize_t sz; int n, lines, vectors = 8, ret; size_t dummy = 0; iovec = xmalloc(vectors * sizeof(struct iovec)); for (lines = 0; /* nothing */ ; lines++) { buf = NULL; sz = getline(&buf, &dummy, fp); if (sz == -1) break; if (0 < sz && buf[sz - 1] == '\n') { sz--; buf[sz] = '\0'; } if (lines == vectors) { vectors *= 2; iovec = xrealloc(iovec, vectors * sizeof(struct iovec)); } iovec[lines].iov_base = buf; iovec[lines].iov_len = sz; } ret = sd_journal_sendv(iovec, lines); for (n = 0; n < lines; n++) free(iovec[n].iov_base); free(iovec); return ret; }
_public_ int sd_journal_printv(int priority, const char *format, va_list ap) { /* FIXME: Instead of limiting things to LINE_MAX we could do a C99 variable-length array on the stack here in a loop. */ char buffer[8 + LINE_MAX], p[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1]; struct iovec iov[2]; assert_return(priority >= 0, -EINVAL); assert_return(priority <= 7, -EINVAL); assert_return(format, -EINVAL); xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK); memcpy(buffer, "MESSAGE=", 8); vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap); /* Strip trailing whitespace, keep prefix whitespace. */ (void) strstrip(buffer); /* Suppress empty lines */ if (isempty(buffer+8)) return 0; zero(iov); IOVEC_SET_STRING(iov[0], buffer); IOVEC_SET_STRING(iov[1], p); return sd_journal_sendv(iov, 2); }
static PyObject *journal_sendv(PyObject *self, PyObject *args) { struct iovec *iov = NULL; int argc; int i, r; PyObject *ret = NULL; PyObject **encoded; /* Allocate an array for the argument strings */ argc = PyTuple_Size(args); encoded = alloca0(argc * sizeof(PyObject*)); /* Allocate sufficient iovector space for the arguments. */ iov = alloca(argc * sizeof(struct iovec)); /* Iterate through the Python arguments and fill the iovector. */ for (i = 0; i < argc; ++i) { PyObject *item = PyTuple_GetItem(args, i); char *stritem; Py_ssize_t length; if (PyUnicode_Check(item)) { encoded[i] = PyUnicode_AsEncodedString(item, "utf-8", "strict"); if (encoded[i] == NULL) goto out; item = encoded[i]; } if (PyBytes_AsStringAndSize(item, &stritem, &length)) goto out; iov[i].iov_base = stritem; iov[i].iov_len = length; } /* Send the iovector to the journal. */ r = sd_journal_sendv(iov, argc); if (r < 0) { errno = -r; PyErr_SetFromErrno(PyExc_IOError); goto out; } /* End with success. */ Py_INCREF(Py_None); ret = Py_None; out: for (i = 0; i < argc; ++i) Py_XDECREF(encoded[i]); return ret; }
static void do_journal_append(char *file) { struct iovec iovec[5]; int r, f, j = 0; ssize_t n; _cleanup_free_ char *bootchart_file = NULL, *bootchart_message = NULL, *p = NULL; bootchart_file = strappend("BOOTCHART_FILE=", file); if (bootchart_file) IOVEC_SET_STRING(iovec[j++], bootchart_file); IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=9f26aa562cf440c2b16c773d0479b518"); IOVEC_SET_STRING(iovec[j++], "PRIORITY=7"); bootchart_message = strjoin("MESSAGE=Bootchart created: ", file, NULL); if (bootchart_message) IOVEC_SET_STRING(iovec[j++], bootchart_message); p = malloc(9 + BOOTCHART_MAX); if (!p) { r = log_oom(); return; } memcpy(p, "BOOTCHART=", 10); f = open(file, O_RDONLY); if (f < 0) { log_error("Failed to read bootchart data: %m\n"); return; } n = loop_read(f, p + 10, BOOTCHART_MAX, false); if (n < 0) { log_error("Failed to read bootchart data: %s\n", strerror(-n)); close(f); return; } close(f); iovec[j].iov_base = p; iovec[j].iov_len = 10 + n; j++; r = sd_journal_sendv(iovec, j); if (r < 0) log_error("Failed to send bootchart: %s", strerror(-r)); }
static int do_journal_append(char *file) { _cleanup_free_ char *bootchart_message = NULL; _cleanup_free_ char *bootchart_file = NULL; _cleanup_free_ char *p = NULL; _cleanup_close_ int fd = -1; struct iovec iovec[5]; int r, j = 0; ssize_t n; bootchart_file = strappend("BOOTCHART_FILE=", file); if (!bootchart_file) return log_oom(); IOVEC_SET_STRING(iovec[j++], bootchart_file); IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=9f26aa562cf440c2b16c773d0479b518"); IOVEC_SET_STRING(iovec[j++], "PRIORITY=7"); bootchart_message = strjoin("MESSAGE=Bootchart created: ", file, NULL); if (!bootchart_message) return log_oom(); IOVEC_SET_STRING(iovec[j++], bootchart_message); p = malloc(10 + BOOTCHART_MAX); if (!p) return log_oom(); memcpy(p, "BOOTCHART=", 10); fd = open(file, O_RDONLY|O_CLOEXEC); if (fd < 0) return log_error_errno(errno, "Failed to open bootchart data \"%s\": %m", file); n = loop_read(fd, p + 10, BOOTCHART_MAX, false); if (n < 0) return log_error_errno(n, "Failed to read bootchart data: %m"); iovec[j].iov_base = p; iovec[j].iov_len = 10 + n; j++; r = sd_journal_sendv(iovec, j); if (r < 0) log_error_errno(r, "Failed to send bootchart: %m"); return 0; }
static int sendv (lua_State *L) { int res; size_t i, n; struct iovec *iov; luaL_checktype(L, 1, LUA_TTABLE); n = lua_rawlen(L, 1); iov = lua_newuserdata(L, n*sizeof(struct iovec)); /* allocate via lua so we get free cleanup */ for (i=0; i<n; i++) { lua_rawgeti(L, 1, i+1); /* Make sure value is a string, we do **not** want automatic coercion */ if (lua_type(L, -1) != LUA_TSTRING) { return luaL_argerror(L, 1, "non-string table entry"); } iov[i].iov_base = (void*)lua_tolstring(L, -1, &iov[i].iov_len); lua_pop(L, 1); } res = sd_journal_sendv(iov, n); return handle_log_result(L, res); }
_public_ int sd_journal_sendv_with_location( const char *file, const char *line, const char *func, const struct iovec *iov, int n) { struct iovec *niov; char *f; assert_return(iov, -EINVAL); assert_return(n > 0, -EINVAL); niov = alloca(sizeof(struct iovec) * (n + 3)); memcpy(niov, iov, sizeof(struct iovec) * n); ALLOCA_CODE_FUNC(f, func); IOVEC_SET_STRING(niov[n++], file); IOVEC_SET_STRING(niov[n++], line); IOVEC_SET_STRING(niov[n++], f); return sd_journal_sendv(niov, n); }
static int journald_entry(struct logger_ctl *ctl, FILE *fp) { struct iovec *iovec; char *buf = NULL; ssize_t sz; int n, lines, vectors = 8, ret = 0; size_t dummy = 0; iovec = xmalloc(vectors * sizeof(struct iovec)); for (lines = 0; /* nothing */ ; lines++) { buf = NULL; sz = getline(&buf, &dummy, fp); if (sz == -1) break; if (0 < sz && buf[sz - 1] == '\n') { sz--; buf[sz] = '\0'; } if (lines == vectors) { vectors *= 2; if (IOV_MAX < vectors) errx(EXIT_FAILURE, _("maximum input lines (%d) exceeded"), IOV_MAX); iovec = xrealloc(iovec, vectors * sizeof(struct iovec)); } iovec[lines].iov_base = buf; iovec[lines].iov_len = sz; } if (!ctl->noact) ret = sd_journal_sendv(iovec, lines); if (ctl->stderr_printout) { for (n = 0; n < lines; n++) fprintf(stderr, "%s\n", (char *) iovec[n].iov_base); } for (n = 0; n < lines; n++) free(iovec[n].iov_base); free(iovec); return ret; }
_public_ int sd_journal_send(const char *format, ...) { int r, i, j; va_list ap; struct iovec *iov = NULL; va_start(ap, format); i = fill_iovec_sprintf(format, ap, 0, &iov); va_end(ap); if (_unlikely_(i < 0)) { r = i; goto finish; } r = sd_journal_sendv(iov, i); finish: for (j = 0; j < i; j++) free(iov[j].iov_base); free(iov); return r; }
_public_ int sd_journal_printv(int priority, const char *format, va_list ap) { /* FIXME: Instead of limiting things to LINE_MAX we could do a C99 variable-length array on the stack here in a loop. */ char buffer[8 + LINE_MAX], p[11]; struct iovec iov[2]; assert_return(priority >= 0, -EINVAL); assert_return(priority <= 7, -EINVAL); assert_return(format, -EINVAL); snprintf(p, sizeof(p), "PRIORITY=%i", priority & LOG_PRIMASK); char_array_0(p); memcpy(buffer, "MESSAGE=", 8); vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap); char_array_0(buffer); zero(iov); IOVEC_SET_STRING(iov[0], buffer); IOVEC_SET_STRING(iov[1], p); return sd_journal_sendv(iov, 2); }
int main(int argc, char* argv[]) { int r, j = 0; _cleanup_free_ char *p = NULL; ssize_t n; pid_t pid; uid_t uid; gid_t gid; struct iovec iovec[14]; _cleanup_free_ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL, *core_timestamp = NULL, *core_comm = NULL, *core_exe = NULL, *core_unit = NULL, *core_session = NULL, *core_message = NULL, *core_cmdline = NULL, *t = NULL; prctl(PR_SET_DUMPABLE, 0); if (argc != _ARG_MAX) { log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); log_error("Invalid number of arguments passed from kernel."); r = -EINVAL; goto finish; } r = parse_pid(argv[ARG_PID], &pid); if (r < 0) { log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); log_error("Failed to parse PID."); goto finish; } if (cg_pid_get_unit(pid, &t) >= 0) { if (streq(t, SPECIAL_JOURNALD_SERVICE)) { /* Make sure we don't make use of the journal, * if it's the journal which is crashing */ log_set_target(LOG_TARGET_KMSG); log_open(); r = divert_coredump(); goto finish; } core_unit = strappend("COREDUMP_UNIT=", t); } else if (cg_pid_get_user_unit(pid, &t) >= 0) core_unit = strappend("COREDUMP_USER_UNIT=", t); if (core_unit) IOVEC_SET_STRING(iovec[j++], core_unit); /* OK, now we know it's not the journal, hence make use of * it */ log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); r = parse_uid(argv[ARG_UID], &uid); if (r < 0) { log_error("Failed to parse UID."); goto finish; } r = parse_gid(argv[ARG_GID], &gid); if (r < 0) { log_error("Failed to parse GID."); goto finish; } core_pid = strappend("COREDUMP_PID=", argv[ARG_PID]); if (core_pid) IOVEC_SET_STRING(iovec[j++], core_pid); core_uid = strappend("COREDUMP_UID=", argv[ARG_UID]); if (core_uid) IOVEC_SET_STRING(iovec[j++], core_uid); core_gid = strappend("COREDUMP_GID=", argv[ARG_GID]); if (core_gid) IOVEC_SET_STRING(iovec[j++], core_gid); core_signal = strappend("COREDUMP_SIGNAL=", argv[ARG_SIGNAL]); if (core_signal) IOVEC_SET_STRING(iovec[j++], core_signal); core_comm = strappend("COREDUMP_COMM=", argv[ARG_COMM]); if (core_comm) IOVEC_SET_STRING(iovec[j++], core_comm); #ifdef HAVE_LOGIND if (sd_pid_get_session(pid, &t) >= 0) { core_session = strappend("COREDUMP_SESSION=", t); free(t); if (core_session) IOVEC_SET_STRING(iovec[j++], core_session); } #endif if (get_process_exe(pid, &t) >= 0) { core_exe = strappend("COREDUMP_EXE=", t); free(t); if (core_exe) IOVEC_SET_STRING(iovec[j++], core_exe); } if (get_process_cmdline(pid, 0, false, &t) >= 0) { core_cmdline = strappend("COREDUMP_CMDLINE=", t); free(t); if (core_cmdline) IOVEC_SET_STRING(iovec[j++], core_cmdline); } core_timestamp = strjoin("COREDUMP_TIMESTAMP=", argv[ARG_TIMESTAMP], "000000", NULL); if (core_timestamp) IOVEC_SET_STRING(iovec[j++], core_timestamp); IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); IOVEC_SET_STRING(iovec[j++], "PRIORITY=2"); core_message = strjoin("MESSAGE=Process ", argv[ARG_PID], " (", argv[ARG_COMM], ") dumped core.", NULL); if (core_message) IOVEC_SET_STRING(iovec[j++], core_message); /* Now, let's drop privileges to become the user who owns the * segfaulted process and allocate the coredump memory under * his uid. This also ensures that the credentials journald * will see are the ones of the coredumping user, thus making * sure the user himself gets access to the core dump. */ if (setresgid(gid, gid, gid) < 0 || setresuid(uid, uid, uid) < 0) { log_error("Failed to drop privileges: %m"); r = -errno; goto finish; } p = malloc(9 + COREDUMP_MAX); if (!p) { r = log_oom(); goto finish; } memcpy(p, "COREDUMP=", 9); n = loop_read(STDIN_FILENO, p + 9, COREDUMP_MAX, false); if (n < 0) { log_error("Failed to read core dump data: %s", strerror(-n)); r = (int) n; goto finish; } iovec[j].iov_base = p; iovec[j].iov_len = 9 + n; j++; r = sd_journal_sendv(iovec, j); if (r < 0) log_error("Failed to send coredump: %s", strerror(-r)); finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int main(int argc, char **argv) { abrt_init(argv); /* I18n */ setlocale(LC_ALL, ""); #if ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif /* Can't keep these strings/structs static: _() doesn't support that */ const char *program_usage_string = _( "& [-v] [-d DIR] [-m MESSAGEID] [-F FMTFILE] [-p NONE|ESSENTIAL|FULL] [-s SYSLOGID]\n" "\n" "Reports problem information into systemd journal.\n" "\n" "The tool reads problem directory DIR and sends its details\n" "into systemd journal as a message. If MESSAGEID is defined, the tool\n" "creates a catalog message as well.\n" ); enum { OPT_v = 1 << 0, OPT_d = 1 << 1, OPT_m = 1 << 2, OPT_F = 1 << 3, OPT_p = 1 << 4, OPT_s = 1 << 5, OPT_D = 1 << 6, }; const char *dump_dir_name = "."; const char *message_id = NULL; const char *fmt_file = NULL; const char *dump = NULL; const char *syslog_id = NULL; /* Keep enum above and order of options below in sync! */ struct options program_options[] = { OPT__VERBOSE(&g_verbose), OPT_STRING('d', NULL , &dump_dir_name, "DIR" , _("Problem directory")), OPT_STRING('m', "message-id" , &message_id, "STR" , _("Catalog message id")), OPT_STRING('F', NULL , &fmt_file , "FILE" , _("Formatting file for catalog message")), OPT_STRING('p', "dump" , &dump , "STR" , _("Dump problem dir into systemd journal fields")), OPT_STRING('s', "syslog-id" , &syslog_id , "STR" , _("Define SYSLOG_IDENTIFIER systemd journal field")), OPT_BOOL( 'D', NULL , NULL , _("Debug")), OPT_END() }; unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); unsigned dump_opt = DUMP_NONE; if (opts & OPT_p) { if (dump && strcmp(dump, "NONE") == 0) /* PASS */; else if (dump && strcmp(dump, "ESSENTIAL") == 0) dump_opt = DUMP_ESSENTIAL; else if (dump && strcmp(dump, "FULL") == 0) dump_opt = DUMP_FULL; else { error_msg("Parameter --dump takes NONE|ESSENTIAL|FULL values"); show_usage_and_die(program_usage_string, program_options); } } export_abrt_envvars(0); problem_data_t *problem_data = create_problem_data_for_reporting(dump_dir_name); if (!problem_data) xfunc_die(); /* create_problem_data_for_reporting already emitted error msg */ problem_formatter_t *pf = problem_formatter_new(); if (fmt_file) { if (problem_formatter_load_file(pf, fmt_file)) error_msg_and_die("Invalid format file: %s", fmt_file); } else { if (problem_formatter_load_string(pf, PROBLEM_REPORT_DEFAULT_TEMPLATE)) error_msg_and_die("BUG: Invalid default problem report format string"); } problem_report_settings_t report_settings = problem_formatter_get_settings(pf); report_settings.prs_shortbt_max_frames = 5; report_settings.prs_shortbt_max_text_size = 0; /* always short bt */ problem_formatter_set_settings(pf, report_settings); /* Modify problem_data to meet reporter's needs */ /* We want to have only binary name in problem report assigned to executable element */ const char *exe = problem_data_get_content_or_NULL(problem_data, FILENAME_EXECUTABLE); char *binary_name = NULL; if (exe) binary_name = strrchr(exe, '/') + 1; if (binary_name) problem_data_add_text_noteditable(problem_data, BINARY_NAME, binary_name); /* crash_function element is neeeded by systemd journal messages, save ??, if it doesn't exist */ const char *crash_function = problem_data_get_content_or_NULL(problem_data, FILENAME_CRASH_FUNCTION); if (!crash_function) problem_data_add_text_noteditable(problem_data, "crash_function", "??"); /* Add SYSLOG_IDENTIFIER into problem data */ if (syslog_id || (syslog_id = getenv("REPORTER_JOURNAL_SYSLOG_ID"))) problem_data_add_text_noteditable(problem_data, SYSLOG_ID, syslog_id); /* Add MESSAGE_ID into problem data */ if (message_id) problem_data_add_text_noteditable(problem_data, MESSAGE_ID, message_id); /* Generating of problem report */ problem_report_t *pr = NULL; if (problem_formatter_generate_report(pf, problem_data, &pr)) error_msg_and_die("Failed to format bug report from problem data"); /* Debug */ if (opts & OPT_D) { log("Message: %s\n" "\n" "%s" "\n" , problem_report_get_summary(pr) , problem_report_get_description(pr) ); problem_data_free(problem_data); problem_report_free(pr); problem_formatter_free(pf); return 0; } msg_content_t *msg_c = create_journal_message(problem_data, pr, dump_opt); /* post journal message */ sd_journal_sendv(msg_content_get_data(msg_c), msg_content_get_size(msg_c)); msg_content_free(msg_c); problem_data_free(problem_data); problem_formatter_free(pf); problem_report_free(pr); return 0; }
int main(int argc, char* argv[]) { /* The small core field we allocate on the stack, to keep things simple */ char *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL, *core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL, *core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL, *core_slice = NULL; /* The larger ones we allocate on the heap */ _cleanup_free_ char *core_timestamp = NULL, *core_message = NULL, *coredump_data = NULL, *core_owner_uid = NULL, *core_open_fds = NULL, *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL, *core_environ = NULL; _cleanup_free_ char *exe = NULL, *comm = NULL, *filename = NULL; const char *info[_INFO_LEN]; _cleanup_close_ int coredump_fd = -1; struct iovec iovec[26]; uint64_t coredump_size; int r, j = 0; uid_t uid, owner_uid; gid_t gid; pid_t pid; char *t; const char *p; /* Make sure we never enter a loop */ prctl(PR_SET_DUMPABLE, 0); /* First, log to a safe place, since we don't know what * crashed and it might be journald which we'd rather not log * to then. */ log_set_target(LOG_TARGET_KMSG); log_open(); if (argc < INFO_COMM + 1) { log_error("Not enough arguments passed from kernel (%d, expected %d).", argc - 1, INFO_COMM + 1 - 1); r = -EINVAL; goto finish; } /* Ignore all parse errors */ parse_config(); log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage)); log_debug("Selected compression %s.", yes_no(arg_compress)); r = parse_uid(argv[INFO_UID + 1], &uid); if (r < 0) { log_error("Failed to parse UID."); goto finish; } r = parse_pid(argv[INFO_PID + 1], &pid); if (r < 0) { log_error("Failed to parse PID."); goto finish; } r = parse_gid(argv[INFO_GID + 1], &gid); if (r < 0) { log_error("Failed to parse GID."); goto finish; } if (get_process_comm(pid, &comm) < 0) { log_warning("Failed to get COMM, falling back to the command line."); comm = strv_join(argv + INFO_COMM + 1, " "); } if (get_process_exe(pid, &exe) < 0) log_warning("Failed to get EXE."); info[INFO_PID] = argv[INFO_PID + 1]; info[INFO_UID] = argv[INFO_UID + 1]; info[INFO_GID] = argv[INFO_GID + 1]; info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1]; info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1]; info[INFO_COMM] = comm; info[INFO_EXE] = exe; if (cg_pid_get_unit(pid, &t) >= 0) { if (streq(t, SPECIAL_JOURNALD_SERVICE)) { free(t); /* If we are journald, we cut things short, * don't write to the journal, but still * create a coredump. */ if (arg_storage != COREDUMP_STORAGE_NONE) arg_storage = COREDUMP_STORAGE_EXTERNAL; r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size); if (r < 0) goto finish; r = maybe_remove_external_coredump(filename, coredump_size); if (r < 0) goto finish; log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename); goto finish; } core_unit = strjoina("COREDUMP_UNIT=", t); free(t); } else if (cg_pid_get_user_unit(pid, &t) >= 0) { core_unit = strjoina("COREDUMP_USER_UNIT=", t); free(t); } if (core_unit) IOVEC_SET_STRING(iovec[j++], core_unit); /* OK, now we know it's not the journal, hence we can make use * of it now. */ log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_open(); core_pid = strjoina("COREDUMP_PID=", info[INFO_PID]); IOVEC_SET_STRING(iovec[j++], core_pid); core_uid = strjoina("COREDUMP_UID=", info[INFO_UID]); IOVEC_SET_STRING(iovec[j++], core_uid); core_gid = strjoina("COREDUMP_GID=", info[INFO_GID]); IOVEC_SET_STRING(iovec[j++], core_gid); core_signal = strjoina("COREDUMP_SIGNAL=", info[INFO_SIGNAL]); IOVEC_SET_STRING(iovec[j++], core_signal); if (sd_pid_get_session(pid, &t) >= 0) { core_session = strjoina("COREDUMP_SESSION=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_session); } if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) { r = asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid); if (r > 0) IOVEC_SET_STRING(iovec[j++], core_owner_uid); } if (sd_pid_get_slice(pid, &t) >= 0) { core_slice = strjoina("COREDUMP_SLICE=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_slice); } if (comm) { core_comm = strjoina("COREDUMP_COMM=", comm); IOVEC_SET_STRING(iovec[j++], core_comm); } if (exe) { core_exe = strjoina("COREDUMP_EXE=", exe); IOVEC_SET_STRING(iovec[j++], core_exe); } if (get_process_cmdline(pid, 0, false, &t) >= 0) { core_cmdline = strjoina("COREDUMP_CMDLINE=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_cmdline); } if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) { core_cgroup = strjoina("COREDUMP_CGROUP=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_cgroup); } if (compose_open_fds(pid, &t) >= 0) { core_open_fds = strappend("COREDUMP_OPEN_FDS=", t); free(t); if (core_open_fds) IOVEC_SET_STRING(iovec[j++], core_open_fds); } p = procfs_file_alloca(pid, "status"); if (read_full_file(p, &t, NULL) >= 0) { core_proc_status = strappend("COREDUMP_PROC_STATUS=", t); free(t); if (core_proc_status) IOVEC_SET_STRING(iovec[j++], core_proc_status); } p = procfs_file_alloca(pid, "maps"); if (read_full_file(p, &t, NULL) >= 0) { core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t); free(t); if (core_proc_maps) IOVEC_SET_STRING(iovec[j++], core_proc_maps); } p = procfs_file_alloca(pid, "limits"); if (read_full_file(p, &t, NULL) >= 0) { core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t); free(t); if (core_proc_limits) IOVEC_SET_STRING(iovec[j++], core_proc_limits); } p = procfs_file_alloca(pid, "cgroup"); if (read_full_file(p, &t, NULL) >=0) { core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t); free(t); if (core_proc_cgroup) IOVEC_SET_STRING(iovec[j++], core_proc_cgroup); } if (get_process_cwd(pid, &t) >= 0) { core_cwd = strjoina("COREDUMP_CWD=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_cwd); } if (get_process_root(pid, &t) >= 0) { core_root = strjoina("COREDUMP_ROOT=", t); free(t); IOVEC_SET_STRING(iovec[j++], core_root); } if (get_process_environ(pid, &t) >= 0) { core_environ = strappend("COREDUMP_ENVIRON=", t); free(t); if (core_environ) IOVEC_SET_STRING(iovec[j++], core_environ); } core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL); if (core_timestamp) IOVEC_SET_STRING(iovec[j++], core_timestamp); IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); IOVEC_SET_STRING(iovec[j++], "PRIORITY=2"); /* Vacuum before we write anything again */ coredump_vacuum(-1, arg_keep_free, arg_max_use); /* Always stream the coredump to disk, if that's possible */ r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size); if (r < 0) /* skip whole core dumping part */ goto log; /* If we don't want to keep the coredump on disk, remove it * now, as later on we will lack the privileges for * it. However, we keep the fd to it, so that we can still * process it and log it. */ r = maybe_remove_external_coredump(filename, coredump_size); if (r < 0) goto finish; if (r == 0) { const char *coredump_filename; coredump_filename = strjoina("COREDUMP_FILENAME=", filename); IOVEC_SET_STRING(iovec[j++], coredump_filename); } /* Vacuum again, but exclude the coredump we just created */ coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use); /* Now, let's drop privileges to become the user who owns the * segfaulted process and allocate the coredump memory under * the user's uid. This also ensures that the credentials * journald will see are the ones of the coredumping user, * thus making sure the user gets access to the core * dump. Let's also get rid of all capabilities, if we run as * root, we won't need them anymore. */ r = drop_privileges(uid, gid, 0); if (r < 0) { log_error_errno(r, "Failed to drop privileges: %m"); goto finish; } #ifdef HAVE_ELFUTILS /* Try to get a strack trace if we can */ if (coredump_size <= arg_process_size_max) { _cleanup_free_ char *stacktrace = NULL; r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace); if (r >= 0) core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL); else if (r == -EINVAL) log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno())); else log_warning_errno(r, "Failed to generate stack trace: %m"); } if (!core_message) #endif log: core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL); if (core_message) IOVEC_SET_STRING(iovec[j++], core_message); /* Optionally store the entire coredump in the journal */ if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) && coredump_size <= arg_journal_size_max) { size_t sz = 0; /* Store the coredump itself in the journal */ r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz); if (r >= 0) { iovec[j].iov_base = coredump_data; iovec[j].iov_len = sz; j++; } } r = sd_journal_sendv(iovec, j); if (r < 0) log_error_errno(r, "Failed to log coredump: %m"); finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int k_sd_journal_send_xavp(str *rname) { struct _sr_xavp *rxavp, *nxavp; int cnt, buflen, i, ret; struct iovec *logv; rxavp = xavp_get(rname, NULL); if (!rxavp || rxavp->val.type != SR_XTYPE_XAVP) { LM_ERR("not a valid xavp: %.*s?\n", rname->len, rname->s); } /* first, count xavp nodes */ for (nxavp = rxavp->val.v.xavp, cnt = 0; nxavp; nxavp = nxavp->next, cnt++); if (cnt == 0) { /* nothing to log? */ LM_NOTICE("empty xavp: %.*s?, no log event was sent to journald\n", rname->len, rname->s); return 1; } logv = pkg_malloc(cnt * sizeof (struct iovec)); if (!logv) { LM_ERR("failed to allocate pkg memory\n"); return -1; } ret = -1; for (nxavp = rxavp->val.v.xavp, cnt = 0; nxavp; nxavp = nxavp->next, cnt++) { if (nxavp->val.type == SR_XTYPE_INT) { buflen = snprintf(NULL, 0, "%.*s=%d", nxavp->name.len, nxavp->name.s, nxavp->val.v.i); logv[cnt].iov_base = pkg_malloc(buflen + 1/*snprintf's trailing \0*/); if (!logv[cnt].iov_base ) { LM_ERR("failed to allocate pkg memory\n"); goto free; } logv[cnt].iov_len = buflen; snprintf(logv[cnt].iov_base, buflen + 1, "%.*s=%d", nxavp->name.len, nxavp->name.s, nxavp->val.v.i); } else if (nxavp->val.type == SR_XTYPE_STR) { buflen = nxavp->name.len + 1 + nxavp->val.v.s.len; logv[cnt].iov_base = pkg_malloc(buflen); if (!logv[cnt].iov_base) { LM_ERR("failed to allocate pkg memory\n"); goto free; } logv[cnt].iov_len = buflen; memcpy(logv[cnt].iov_base, nxavp->name.s, nxavp->name.len); ((char*)logv[cnt].iov_base)[nxavp->name.len] = '='; memcpy(((char*)(logv[cnt].iov_base)) + nxavp->name.len + 1, nxavp->val.v.s.s, nxavp->val.v.s.len); } else { LM_NOTICE("unsupported type %d for field %.*s, skipped...\n", nxavp->val.type, nxavp->name.len, nxavp->name.s); logv[cnt].iov_len = 0; logv[cnt].iov_base = NULL; } LM_DBG("added io slice %d: %.*s\n", cnt, (int)logv[cnt].iov_len, (char*)logv[cnt].iov_base); } if (sd_journal_sendv(logv, cnt) != 0) { LM_ERR("sd_journal_sendv() failed\n"); } else { ret = 1; } free: for (i = 0 ; i < cnt ; i++) { if (logv[i].iov_base) pkg_free(logv[i].iov_base); } pkg_free(logv); return ret; }
_public_ int sd_journal_sendv(const struct iovec *iov, int n) { PROTECT_ERRNO; int fd, r; _cleanup_close_ int buffer_fd = -1; struct iovec *w; uint64_t *l; int i, j = 0; static const union sockaddr_union sa = { .un.sun_family = AF_UNIX, .un.sun_path = "/run/systemd/journal/socket", }; struct msghdr mh = { .msg_name = (struct sockaddr*) &sa.sa, .msg_namelen = SOCKADDR_UN_LEN(sa.un), }; ssize_t k; bool have_syslog_identifier = false; bool seal = true; assert_return(iov, -EINVAL); assert_return(n > 0, -EINVAL); w = newa(struct iovec, n * 5 + 3); l = newa(uint64_t, n); for (i = 0; i < n; i++) { char *c, *nl; if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) return -EINVAL; c = memchr(iov[i].iov_base, '=', iov[i].iov_len); if (_unlikely_(!c || c == iov[i].iov_base)) return -EINVAL; have_syslog_identifier = have_syslog_identifier || (c == (char *) iov[i].iov_base + 17 && startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER")); nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len); if (nl) { if (_unlikely_(nl < c)) return -EINVAL; /* Already includes a newline? Bummer, then * let's write the variable name, then a * newline, then the size (64bit LE), followed * by the data and a final newline */ w[j].iov_base = iov[i].iov_base; w[j].iov_len = c - (char*) iov[i].iov_base; j++; IOVEC_SET_STRING(w[j++], "\n"); l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1); w[j].iov_base = &l[i]; w[j].iov_len = sizeof(uint64_t); j++; w[j].iov_base = c + 1; w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1; j++; } else /* Nothing special? Then just add the line and * append a newline */ w[j++] = iov[i]; IOVEC_SET_STRING(w[j++], "\n"); } if (!have_syslog_identifier && string_is_safe(program_invocation_short_name)) { /* Implicitly add program_invocation_short_name, if it * is not set explicitly. We only do this for * program_invocation_short_name, and nothing else * since everything else is much nicer to retrieve * from the outside. */ IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER="); IOVEC_SET_STRING(w[j++], program_invocation_short_name); IOVEC_SET_STRING(w[j++], "\n"); } fd = journal_fd(); if (_unlikely_(fd < 0)) return fd; mh.msg_iov = w; mh.msg_iovlen = j; k = sendmsg(fd, &mh, MSG_NOSIGNAL); if (k >= 0) return 0; /* Fail silently if the journal is not available */ if (errno == ENOENT) return 0; if (errno != EMSGSIZE && errno != ENOBUFS) return -errno; /* Message doesn't fit... Let's dump the data in a memfd or * temporary file and just pass a file descriptor of it to the * other side. * * For the temporary files we use /dev/shm instead of /tmp * here, since we want this to be a tmpfs, and one that is * available from early boot on and where unprivileged users * can create files. */ buffer_fd = memfd_new(NULL); if (buffer_fd < 0) { if (buffer_fd == -ENOSYS) { buffer_fd = open_tmpfile_unlinkable("/dev/shm", O_RDWR | O_CLOEXEC); if (buffer_fd < 0) return buffer_fd; seal = false; } else return buffer_fd; } n = writev(buffer_fd, w, j); if (n < 0) return -errno; if (seal) { r = memfd_set_sealed(buffer_fd); if (r < 0) return r; } r = send_one_fd_sa(fd, buffer_fd, mh.msg_name, mh.msg_namelen, 0); if (r == -ENOENT) /* Fail silently if the journal is not available */ return 0; return r; } static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) { PROTECT_ERRNO; size_t n, k; k = isempty(message) ? 0 : strlen(message) + 2; n = 8 + k + 256 + 1; for (;;) { char buffer[n]; char* j; errno = 0; j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k); if (errno == 0) { char error[sizeof("ERRNO=")-1 + DECIMAL_STR_MAX(int) + 1]; if (j != buffer + 8 + k) memmove(buffer + 8 + k, j, strlen(j)+1); memcpy(buffer, "MESSAGE=", 8); if (k > 0) { memcpy(buffer + 8, message, k - 2); memcpy(buffer + 8 + k - 2, ": ", 2); } xsprintf(error, "ERRNO=%i", _saved_errno_); assert_cc(3 == LOG_ERR); IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3"); IOVEC_SET_STRING(iov[skip+1], buffer); IOVEC_SET_STRING(iov[skip+2], error); return sd_journal_sendv(iov, skip + 3); } if (errno != ERANGE) return -errno; n *= 2; } } _public_ int sd_journal_perror(const char *message) { struct iovec iovec[3]; return fill_iovec_perror_and_send(message, 0, iovec); } _public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) { static const union sockaddr_union sa = { .un.sun_family = AF_UNIX, .un.sun_path = "/run/systemd/journal/stdout", }; _cleanup_close_ int fd = -1; char *header; size_t l; int r; assert_return(priority >= 0, -EINVAL); assert_return(priority <= 7, -EINVAL); fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); if (fd < 0) return -errno; r = connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)); if (r < 0) return -errno; if (shutdown(fd, SHUT_RD) < 0) return -errno; fd_inc_sndbuf(fd, SNDBUF_SIZE); if (!identifier) identifier = ""; l = strlen(identifier); header = alloca(l + 1 + 1 + 2 + 2 + 2 + 2 + 2); memcpy(header, identifier, l); header[l++] = '\n'; header[l++] = '\n'; /* unit id */ header[l++] = '0' + priority; header[l++] = '\n'; header[l++] = '0' + !!level_prefix; header[l++] = '\n'; header[l++] = '0'; header[l++] = '\n'; header[l++] = '0'; header[l++] = '\n'; header[l++] = '0'; header[l++] = '\n'; r = loop_write(fd, header, l, false); if (r < 0) return r; r = fd; fd = -1; return r; } _public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) { int r; va_list ap; va_start(ap, format); r = sd_journal_printv_with_location(priority, file, line, func, format, ap); va_end(ap); return r; } _public_ int sd_journal_printv_with_location(int priority, const char *file, const char *line, const char *func, const char *format, va_list ap) { char buffer[8 + LINE_MAX], p[sizeof("PRIORITY=")-1 + DECIMAL_STR_MAX(int) + 1]; struct iovec iov[5]; char *f; assert_return(priority >= 0, -EINVAL); assert_return(priority <= 7, -EINVAL); assert_return(format, -EINVAL); xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK); memcpy(buffer, "MESSAGE=", 8); vsnprintf(buffer+8, sizeof(buffer) - 8, format, ap); /* Strip trailing whitespace, keep prefixing whitespace */ (void) strstrip(buffer); /* Suppress empty lines */ if (isempty(buffer+8)) return 0; /* func is initialized from __func__ which is not a macro, but * a static const char[], hence cannot easily be prefixed with * CODE_FUNC=, hence let's do it manually here. */ ALLOCA_CODE_FUNC(f, func); zero(iov); IOVEC_SET_STRING(iov[0], buffer); IOVEC_SET_STRING(iov[1], p); IOVEC_SET_STRING(iov[2], file); IOVEC_SET_STRING(iov[3], line); IOVEC_SET_STRING(iov[4], f); return sd_journal_sendv(iov, ELEMENTSOF(iov)); }
_public_ int sd_journal_sendv(const struct iovec *iov, int n) { PROTECT_ERRNO; int fd; struct iovec *w; uint64_t *l; int i, j = 0; struct sockaddr_un sa = { .sun_family = AF_UNIX, .sun_path = JOURNAL_RUNDIR "/socket", }; struct msghdr mh = { .msg_name = &sa, .msg_namelen = offsetof(struct sockaddr_un, sun_path) + strlen(sa.sun_path), }; ssize_t k; union { struct cmsghdr cmsghdr; uint8_t buf[CMSG_SPACE(sizeof(int))]; } control; bool have_syslog_identifier = false; assert_return(iov, -EINVAL); assert_return(n > 0, -EINVAL); w = alloca(sizeof(struct iovec) * n * 5 + 3); l = alloca(sizeof(uint64_t) * n); for (i = 0; i < n; i++) { char *c, *nl; if (_unlikely_(!iov[i].iov_base || iov[i].iov_len <= 1)) return -EINVAL; c = memchr(iov[i].iov_base, '=', iov[i].iov_len); if (_unlikely_(!c || c == iov[i].iov_base)) return -EINVAL; have_syslog_identifier = have_syslog_identifier || (c == (char *) iov[i].iov_base + 17 && startswith(iov[i].iov_base, "SYSLOG_IDENTIFIER")); nl = memchr(iov[i].iov_base, '\n', iov[i].iov_len); if (nl) { if (_unlikely_(nl < c)) return -EINVAL; /* Already includes a newline? Bummer, then * let's write the variable name, then a * newline, then the size (64bit LE), followed * by the data and a final newline */ w[j].iov_base = iov[i].iov_base; w[j].iov_len = c - (char*) iov[i].iov_base; j++; IOVEC_SET_STRING(w[j++], "\n"); l[i] = htole64(iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1); w[j].iov_base = &l[i]; w[j].iov_len = sizeof(uint64_t); j++; w[j].iov_base = c + 1; w[j].iov_len = iov[i].iov_len - (c - (char*) iov[i].iov_base) - 1; j++; } else /* Nothing special? Then just add the line and * append a newline */ w[j++] = iov[i]; IOVEC_SET_STRING(w[j++], "\n"); } if (!have_syslog_identifier) { /* Implicitly add program_invocation_short_name, if it * is not set explicitly. We only do this for * program_invocation_short_name, and nothing else * since everything else is much nicer to retrieve * from the outside. */ IOVEC_SET_STRING(w[j++], "SYSLOG_IDENTIFIER="); IOVEC_SET_STRING(w[j++], program_invocation_short_name); IOVEC_SET_STRING(w[j++], "\n"); } fd = journal_fd(); if (_unlikely_(fd < 0)) return fd; mh.msg_iov = w; mh.msg_iovlen = j; k = sendmsg(fd, &mh, MSG_NOSIGNAL); if (k >= 0) return 0; /* Fail silently if the journal is not available */ if (errno == ENOENT) return 0; if (errno != EMSGSIZE && errno != ENOBUFS) return -errno; return 0; } static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) { PROTECT_ERRNO; size_t n, k; k = isempty(message) ? 0 : strlen(message) + 2; n = 8 + k + 256 + 1; for (;;) { char buffer[n]; char* j; errno = 0; j = strerror_r(_saved_errno_, buffer + 8 + k, n - 8 - k); if (errno == 0) { char error[6 + 10 + 1]; /* for a 32bit value */ if (j != buffer + 8 + k) memmove(buffer + 8 + k, j, strlen(j)+1); memcpy(buffer, "MESSAGE=", 8); if (k > 0) { memcpy(buffer + 8, message, k - 2); memcpy(buffer + 8 + k - 2, ": ", 2); } snprintf(error, sizeof(error), "ERRNO=%u", _saved_errno_); char_array_0(error); IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3"); IOVEC_SET_STRING(iov[skip+1], buffer); IOVEC_SET_STRING(iov[skip+2], error); return sd_journal_sendv(iov, skip + 3); } if (errno != ERANGE) return -errno; n *= 2; } } _public_ int sd_journal_perror(const char *message) { struct iovec iovec[3]; return fill_iovec_perror_and_send(message, 0, iovec); }
int main(int argc, char **argv) { static const char *metric = NULL; static const char *metric_description = NULL; static const char *identifier = NULL; static const char *priority_str = NULL; static gboolean finished = FALSE; static gboolean shutdown = FALSE; int priority = LOG_INFO; static GOptionEntry entries[] = { { "identifier", 't', 0, G_OPTION_ARG_STRING, &identifier, "Source of the log message", "IDENTIFIER" }, { "priority", 'p', 0, G_OPTION_ARG_STRING, &priority_str, "Priority (emerg|alert|crit|err|warning|notice|info|debug|0..7) - default info", "PRIORITY" }, { "metric", 0, 0, G_OPTION_ARG_STRING, &metric, "Log a metric", "NAME=VALUE[UNITS]" }, { "metric-description", 0, 0, G_OPTION_ARG_STRING, &metric_description, "Description of metric", "DESC" }, { "finished", 0, 0, G_OPTION_ARG_NONE, &finished, "Indicate that a task has finished" }, { "shutdown", 0, 0, G_OPTION_ARG_NONE, &shutdown, "Indicate that that the system is shutting down" }, }; GOptionContext *context; GError *error = NULL; GArray *send_iov; int i; context = g_option_context_new ("FIELD1=VALUE1 FIELD2=VALUE2..."); g_option_context_add_main_entries (context, entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { g_printerr ("option parsing failed: %s\n", error->message); return 1; } send_offsets = g_array_new (FALSE, FALSE, sizeof (SendOffset)); buffer = g_string_new (NULL); if (identifier != NULL) add_fieldf("SYSLOG_IDENTIFIER=%s", identifier); if (priority_str != NULL) { for (i = 0; priorities[i]; i++) { if (strcmp (priorities[i], priority_str) == 0) { priority = i; break; } } if (priorities[i] == NULL) { if (priority_str[0] >= '0' && priority_str[0] <= '7' && priority_str[1] == 0) { priority = priority_str[0] - '0'; } else { g_printerr ("Unknown priority '%s'\n", priority_str); return 1; } } } add_fieldf("PRIORITY=%d", priority); if ((metric ? 1 : 0) + (finished ? 1 : 0) + (shutdown ? 1 : 0) > 1) { g_printerr ("Only one of --metric, --finished, and --shutdown can be specified\n"); return 1; } if (metric) { const char *equals; char *metric_name; char *metric_value; const char *metric_units = NULL; char *endptr; double value G_GNUC_UNUSED; equals = strchr (metric, '='); if (equals == NULL) { g_printerr ("--metric argument should be of the form NAME=VALUE[UNITS]\n"); return 1; } metric_name = g_strndup (metric, equals - metric); value = g_ascii_strtod (equals + 1, &endptr); if (endptr == equals + 1) { g_printerr ("--metric argument should be of the form NAME=VALUE[UNITS]\n"); return 1; } metric_value = g_strndup (equals + 1, endptr - (equals + 1)); if (*endptr) metric_units = endptr; add_fieldf ("MESSAGE_ID=5eb90e0f00a247d68d95f630814de243"); add_fieldf ("METRIC_NAME=%s", metric_name); add_fieldf ("METRIC_VALUE=%s", metric_value); if (metric_units) add_fieldf ("METRIC_UNITS=%s", metric_units); } if (metric_description) { if (!metric) { g_printerr("--metric-description requires --metric\n"); return 1; } add_fieldf("METRIC_DESCRIPTION=%s", metric); } if (metric_description) add_fieldf("MESSAGE=%s (%s)", metric, metric_description); else if (metric) add_fieldf("MESSAGE=%s", metric); if (finished) { add_fieldf ("MESSAGE_ID=26a5224162874504864dfa03bf255c8d"); add_fieldf ("MESSAGE=Finished"); } if (shutdown) { add_fieldf ("MESSAGE_ID=545cc8baba1d4493916a334258c83be0"); add_fieldf ("MESSAGE=System shutdown"); } for (i = 1; i < argc; i++) { const char *equals = strchr (argv[i], '='); const char *p; if (equals == NULL) { g_printerr ("argument '%s' should be of the form FIELD=VALUE\n", argv[i]); return 1; } for (p = argv[i]; p != equals; p++) { if (!((*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || (p != argv[i] && *p == '_'))) { g_printerr ("Field name should consist of upper-case letters, digits, and underscores, and not start with an underscore\n"); return 1; } } add_field (argv[i]); } send_iov = g_array_new (FALSE, FALSE, sizeof (struct iovec)); for (i = 0; i < send_offsets->len; i++) { SendOffset *offset = &g_array_index (send_offsets, SendOffset, i); struct iovec iov; iov.iov_base = buffer->str + offset->offset; iov.iov_len = offset->len; g_array_append_val (send_iov, iov); } sd_journal_sendv ((struct iovec *)send_iov->data, send_iov->len); return 0; }