+typedef enum CoredumpStorage {
+ COREDUMP_STORAGE_NONE,
+ COREDUMP_STORAGE_EXTERNAL,
+ COREDUMP_STORAGE_JOURNAL,
+ COREDUMP_STORAGE_BOTH,
+ _COREDUMP_STORAGE_MAX,
+ _COREDUMP_STORAGE_INVALID = -1
+} CoredumpStorage;
+
+static CoredumpStorage arg_storage = COREDUMP_STORAGE_EXTERNAL;
+static off_t arg_process_size_max = PROCESS_SIZE_MAX;
+static off_t arg_external_size_max = EXTERNAL_SIZE_MAX;
+static size_t arg_journal_size_max = JOURNAL_SIZE_MAX;
+
+static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = {
+ [COREDUMP_STORAGE_NONE] = "none",
+ [COREDUMP_STORAGE_EXTERNAL] = "external",
+ [COREDUMP_STORAGE_JOURNAL] = "journal",
+ [COREDUMP_STORAGE_BOTH] = "both",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP(coredump_storage, CoredumpStorage);
+static DEFINE_CONFIG_PARSE_ENUM(config_parse_coredump_storage, coredump_storage, CoredumpStorage, "Failed to parse storage setting");
+
+static int parse_config(void) {
+
+ static const ConfigTableItem items[] = {
+ { "Coredump", "ProcessSizeMax", config_parse_iec_off, 0, &arg_process_size_max },
+ { "Coredump", "ExternalSizeMax", config_parse_iec_off, 0, &arg_external_size_max },
+ { "Coredump", "JournalSizeMax", config_parse_iec_size, 0, &arg_journal_size_max },
+ { "Coredump", "Storage", config_parse_coredump_storage, 0, &arg_storage },
+ {}
+ };
+
+ return config_parse(
+ NULL,
+ "/etc/systemd/coredump.conf",
+ NULL,
+ "Coredump\0",
+ config_item_table_lookup,
+ (void*) items,
+ false,
+ false,
+ NULL);
+}
+
+static int fix_acl(int fd, uid_t uid) {
+
+#ifdef HAVE_ACL
+ _cleanup_(acl_freep) acl_t acl = NULL;
+ acl_entry_t entry;
+ acl_permset_t permset;
+
+ if (uid <= SYSTEM_UID_MAX)
+ return 0;
+
+ /* Make sure normal users can read (but not write or delete)
+ * their own coredumps */
+
+ acl = acl_get_fd(fd);
+ if (!acl) {
+ log_error("Failed to get ACL: %m");
+ return -errno;
+ }
+
+ if (acl_create_entry(&acl, &entry) < 0 ||
+ acl_set_tag_type(entry, ACL_USER) < 0 ||
+ acl_set_qualifier(entry, &uid) < 0) {
+ log_error("Failed to patch ACL: %m");
+ return -errno;
+ }
+
+ if (acl_get_permset(entry, &permset) < 0 ||
+ acl_add_perm(permset, ACL_READ) < 0 ||
+ calc_acl_mask_if_needed(&acl) < 0) {
+ log_warning("Failed to patch ACL: %m");
+ return -errno;
+ }
+
+ if (acl_set_fd(fd, acl) < 0) {
+ log_error("Failed to apply ACL: %m");
+ return -errno;
+ }
+#endif
+
+ return 0;
+}
+
+static int fix_xattr(int fd, char *argv[]) {
+ int r = 0;
+
+ /* Attach some metadate to coredumps via extended
+ * attributes. Just because we can. */
+
+ if (!isempty(argv[ARG_PID]))
+ if (fsetxattr(fd, "user.coredump.pid", argv[ARG_PID], strlen(argv[ARG_PID]), XATTR_CREATE) < 0)
+ r = -errno;
+
+ if (!isempty(argv[ARG_UID]))
+ if (fsetxattr(fd, "user.coredump.uid", argv[ARG_UID], strlen(argv[ARG_UID]), XATTR_CREATE) < 0)
+ r = -errno;
+
+ if (!isempty(argv[ARG_GID]))
+ if (fsetxattr(fd, "user.coredump.gid", argv[ARG_GID], strlen(argv[ARG_GID]), XATTR_CREATE) < 0)
+ r = -errno;
+
+ if (!isempty(argv[ARG_SIGNAL]))
+ if (fsetxattr(fd, "user.coredump.signal", argv[ARG_SIGNAL], strlen(argv[ARG_SIGNAL]), XATTR_CREATE) < 0)
+ r = -errno;
+
+ if (!isempty(argv[ARG_TIMESTAMP]))
+ if (fsetxattr(fd, "user.coredump.timestamp", argv[ARG_TIMESTAMP], strlen(argv[ARG_TIMESTAMP]), XATTR_CREATE) < 0)
+ r = -errno;