+ return rc < 0 ? rc : joblen;
+}
+
+/*
+ * jobid_interpret_string()
+ *
+ * Interpret the jobfmt string to expand specified fields, like coredumps do:
+ * %e = executable
+ * %g = gid
+ * %h = hostname
+ * %j = jobid from environment
+ * %p = pid
+ * %u = uid
+ *
+ * Unknown escape strings are dropped. Other characters are copied through,
+ * excluding whitespace (to avoid making jobid parsing difficult).
+ *
+ * Return: -EOVERFLOW if the expanded string does not fit within @joblen
+ * 0 for success
+ */
+static int jobid_interpret_string(const char *jobfmt, char *jobid,
+ ssize_t joblen)
+{
+ char c;
+
+ while ((c = *jobfmt++) && joblen > 1) {
+ char f;
+ int l;
+
+ if (isspace(c)) /* Don't allow embedded spaces */
+ continue;
+
+ if (c != '%') {
+ *jobid = c;
+ joblen--;
+ jobid++;
+ continue;
+ }
+
+ switch ((f = *jobfmt++)) {
+ case 'e': /* executable name */
+ l = snprintf(jobid, joblen, "%s", current_comm());
+ break;
+ case 'g': /* group ID */
+ l = snprintf(jobid, joblen, "%u",
+ from_kgid(&init_user_ns, current_fsgid()));
+ break;
+ case 'h': /* hostname */
+ l = snprintf(jobid, joblen, "%s",
+ init_utsname()->nodename);
+ break;
+ case 'j': /* jobid stored in process environment */
+ l = jobid_get_from_cache(jobid, joblen);
+ if (l < 0)
+ l = 0;
+ break;
+ case 'p': /* process ID */
+ l = snprintf(jobid, joblen, "%u", current_pid());
+ break;
+ case 'u': /* user ID */
+ l = snprintf(jobid, joblen, "%u",
+ from_kuid(&init_user_ns, current_fsuid()));
+ break;
+ case '\0': /* '%' at end of format string */
+ l = 0;
+ goto out;
+ default: /* drop unknown %x format strings */
+ l = 0;
+ break;
+ }
+ jobid += l;
+ joblen -= l;
+ }
+ /*
+ * This points at the end of the buffer, so long as jobid is always
+ * incremented the same amount as joblen is decremented.
+ */
+out:
+ jobid[joblen - 1] = '\0';
+
+ return joblen < 0 ? -EOVERFLOW : 0;