Esempio n. 1
0
_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;
}
Esempio n. 2
0
/**
 * 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
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
_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);
}
Esempio n. 5
0
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;
}
Esempio n. 6
0
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));
}
Esempio n. 7
0
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;
}
Esempio n. 8
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);
}
Esempio n. 9
0
_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);
}
Esempio n. 10
0
File: logger.c Progetto: alisw/uuid
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;
}
Esempio n. 11
0
_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;
}
Esempio n. 12
0
_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);
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
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;
}
Esempio n. 15
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;
}
Esempio n. 16
0
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;
}
Esempio n. 17
0
_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));
}
Esempio n. 18
0
_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);
}
Esempio n. 19
0
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;
}