Merge branch 'master-silence-format-printf-warning' of https://github.com/rgerhards/util-linux
diff --git a/misc-utils/logger.1 b/misc-utils/logger.1
index d0293a8..e972a0a 100644
--- a/misc-utils/logger.1
+++ b/misc-utils/logger.1
@@ -95,7 +95,13 @@
 .B journalctl --output json-pretty
 to see rest of the fields.
 .TP
-.BR \-\--size " \fIsize
+.BR \-\-msgid " \fIMSGID
+Sets the RFC5424 MSGID field. Note that the space character is not permitted
+inside of \fIMSGID\fR. This option is only used if \fB\-\-rfc5424\fR is
+specified as well. Otherwise, it is silently ignored.
+
+.TP
+.BR \-\-size " \fIsize
 Sets the maximum permitted message size to \fIsize\fR. The default
 is 1KiB characters, which is the limit traditionally used and specified
 in RFC 3164. With RFC 5424, this limit has become flexible. A good assumption
diff --git a/misc-utils/logger.c b/misc-utils/logger.c
index 2fd3ddf..9c6d6a2 100644
--- a/misc-utils/logger.c
+++ b/misc-utils/logger.c
@@ -90,6 +90,7 @@
 	OPT_RFC3164,
 	OPT_RFC5424,
 	OPT_SOCKET_ERRORS,
+	OPT_MSGID,
 	OPT_ID
 };
 
@@ -99,6 +100,7 @@
 	pid_t pid;			/* zero when unwanted */
 	char *hdr;			/* the syslog header (based on protocol) */
 	char *tag;
+	char *msgid;
 	char *unix_socket;		/* -u <path> or default to _PATH_DEVLOG */
 	char *server;
 	char *port;
@@ -362,33 +364,52 @@
 	free(hostname);
 }
 
+/* Some field mappings may be controversal, thus I give the reason
+ * why this specific mapping was used:
+ * APP-NAME <-- tag
+ *    Some may argue that "logger" is a better fit, but we think
+ *    this is better inline of what other implementations do. In
+ *    rsyslog, for example, the TAG value is populated from APP-NAME.
+ * PROCID <-- pid
+ *    This is a relatively straightforward interpretation from
+ *    RFC5424, sect. 6.2.6.
+ * MSGID <-- msgid (from --msgid)
+ *    One may argue that the string "logger" would be better suited
+ *    here so that a receiver can identify the sender process.
+ *    However, this does not sound like a good match to RFC5424,
+ *    sect. 6.2.7.
+ * Note that appendix A.1 of RFC5424 does not provide clear guidance
+ * of how these fields should be used. This is the case because the
+ * IETF working group couldn't arrive at a clear agreement when we
+ * specified RFC5424. The rest of the field mappings should be
+ * pretty clear from RFC5424. -- Rainer Gerhards, 2015-03-10
+ */
+#define NILVALUE "-"
 static void syslog_rfc5424_header(struct logger_ctl *const ctl)
 {
-	char *hostname = NULL;
-	char pid[32], time[64], timeq[80];
-	struct timeval tv;
-	struct tm *tm;
-
-	*pid = *time = *timeq = '\0';
 	if (ctl->fd < 0)
 		return;
 
+	char *time;
 	if (ctl->rfc5424_time) {
+		struct timeval tv;
+		struct tm *tm;
 		gettimeofday(&tv, NULL);
 		if ((tm = localtime(&tv.tv_sec)) != NULL) {
 			char fmt[64];
-
 			const size_t i = strftime(fmt, sizeof(fmt),
-					" %Y-%m-%dT%H:%M:%S.%%06u%z ", tm);
+					"%Y-%m-%dT%H:%M:%S.%%06u%z ", tm);
 			/* patch TZ info to comply with RFC3339 (we left SP at end) */
 			fmt[i-1] = fmt[i-2];
 			fmt[i-2] = fmt[i-3];
 			fmt[i-3] = ':';
-			snprintf(time, sizeof(time), fmt, tv.tv_usec);
+			xasprintf(&time, fmt, tv.tv_usec);
 		} else
 			err(EXIT_FAILURE, _("localtime() failed"));
-	}
+	} else
+		time = strdup(NILVALUE);
 
+	char *hostname;
 	if (ctl->rfc5424_host) {
 		hostname = xgethostname();
 		/* Arbitrary looking 'if (var < strlen()) checks originate from
@@ -396,34 +417,50 @@
 		if (255 < strlen(hostname))
 			errx(EXIT_FAILURE, _("hostname '%s' is too long"),
 			     hostname);
-	}
+	} else
+		hostname = strdup(NILVALUE);
 
+	char *const app_name = ctl->tag;
 	if (48 < strlen(ctl->tag))
 		errx(EXIT_FAILURE, _("tag '%s' is too long"), ctl->tag);
 
+	char *procid;
 	if (ctl->pid)
-		snprintf(pid, sizeof(pid), " %d", ctl->pid);
+		xasprintf(&procid, "%d", ctl->pid);
+	else
+		procid = strdup(NILVALUE);
 
+	char *const msgid = strdup((ctl->msgid) ? ctl->msgid : NILVALUE);
+
+	char *structured_data;
 	if (ctl->rfc5424_tq) {
 #ifdef HAVE_NTP_GETTIME
 		struct ntptimeval ntptv;
-
 		if (ntp_gettime(&ntptv) == TIME_OK)
-			snprintf(timeq, sizeof(timeq),
-				 " [timeQuality tzKnown=\"1\" isSynced=\"1\" syncAccuracy=\"%ld\"]",
+			xasprintf(&structured_data,
+				 "[timeQuality tzKnown=\"1\" isSynced=\"1\" syncAccuracy=\"%ld\"]",
 				 ntptv.maxerror);
 		else
 #endif
-			snprintf(timeq, sizeof(timeq),
-				 " [timeQuality tzKnown=\"1\" isSynced=\"0\"]");
+			xasprintf(&structured_data,
+				 "[timeQuality tzKnown=\"1\" isSynced=\"0\"]");
 	}
 
-	xasprintf(&ctl->hdr, "<%d>1%s%s%s %s -%s%s", ctl->pri, time,
-		  hostname ? " " : "",
-		  hostname ? hostname : "",
-		  ctl->tag, pid, timeq);
+	xasprintf(&ctl->hdr, "<%d>1 %s %s %s %s %s %s ",
+		ctl->pri,
+		time,
+		hostname,
+		app_name,
+		procid,
+		msgid,
+		structured_data);
 
+	free(time);
 	free(hostname);
+	/* app_name points to ctl->tag, do NOT free! */
+	free(procid);
+	free(msgid);
+	free(structured_data);
 }
 
 static void parse_rfc5424_flags(struct logger_ctl *ctl, char *optarg)
@@ -612,8 +649,9 @@
 	fputs(_(" -T, --tcp                use TCP only\n"), out);
 	fputs(_(" -d, --udp                use UDP only\n"), out);
 	fputs(_("     --rfc3164            use the obsolete BSD syslog protocol\n"), out);
-	fputs(_("     --rfc5424[=<snip>]   use the syslog protocol (the default);\n"
+	fputs(_("     --rfc5424[=<snip>]   use the syslog protocol (the default for remote);\n"
 		"                            <snip> can be notime, or notq, and/or nohost\n"), out);
+	fputs(_("     --msgid              set rfc5424 MSGID field, ignored for non-rfc5424 format\n"), out);
 	fputs(_(" -u, --socket <socket>    write to this Unix socket\n"), out);
 	fputs(_("     --socket-errors[=<on|off|auto>]\n"
 		"                          print connection errors when using Unix sockets\n"), out);
@@ -648,6 +686,7 @@
 		.server = NULL,
 		.port = NULL,
 		.hdr = NULL,
+		.msgid = NULL,
 		.socket_type = ALL_TYPES,
 		.max_message_size = 1024,
 		.rfc5424_time = 1,
@@ -679,6 +718,7 @@
 		{ "rfc3164",	no_argument,  0, OPT_RFC3164 },
 		{ "rfc5424",	optional_argument,  0, OPT_RFC5424 },
 		{ "size",       required_argument,  0, 'S' },
+		{ "msgid",      required_argument,  0, OPT_MSGID },
 		{ "skip-empty", no_argument,  0, 'e' },
 #ifdef HAVE_LIBSYSTEMD
 		{ "journald",   optional_argument,  0, OPT_JOURNALD },
@@ -759,6 +799,11 @@
 			if (optarg)
 				parse_rfc5424_flags(&ctl, optarg);
 			break;
+		case OPT_MSGID:
+			if(strchr(optarg, ' '))
+					err(EXIT_FAILURE, _("--msgid cannot contain space"));
+			ctl.msgid = optarg;
+			break;
 #ifdef HAVE_LIBSYSTEMD
 		case OPT_JOURNALD:
 			if (optarg) {
diff --git a/tests/expected/sfdisk/gpt-write-dump b/tests/expected/sfdisk/gpt-write-dump
index 03b5e1f..bc4a7b9 100644
--- a/tests/expected/sfdisk/gpt-write-dump
+++ b/tests/expected/sfdisk/gpt-write-dump
@@ -2,6 +2,8 @@
 label-id: 3B8559DB-33AF-43E9-BEFC-C331D829B539
 device: <removed>
 unit: sectors
+first-lba: 2048
+last-lba: 102366
 
 <removed>1 : start=        2048, size=        6144, type=44479540-F297-41B2-9AF7-D131D5F0458A, uuid=4DD6948A-44F8-4E6C-8BDC-064F740704F8
 <removed>2 : start=        8192, size=        6144, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=44B51DEF-5F04-465A-91AA-2889A62D8E49