--- /dev/null
+//po4a: entry man manual
+// Daan De Meyer <daan.j.demeyer@gmail.com>
+// In the public domain.
+= setpgid(1)
+:doctype: manpage
+:man manual: User Commands
+:man source: util-linux {release-version}
+:page-layout: base
+:command: setpgid
+
+== NAME
+
+setpgid - run a program in a new process group
+
+== SYNOPSIS
+
+*setpgid* [options] _program_ [_arguments_]
+
+== DESCRIPTION
+
+*setpgid* runs a program in a new process group.
+
+== OPTIONS
+
+*-f*, *--foreground*::
+Make the new process group the foreground process group of the controlling
+terminal if there is a controlling terminal.
+
+include::man-common/help-version.adoc[]
+
+== AUTHORS
+
+mailto:daan.j.demeyer@gmail.com[Daan De Meyer]
+
+== SEE ALSO
+
+*setpgid*(2)
+
+include::man-common/bugreports.adoc[]
+
+include::man-common/footer.adoc[]
+
+ifdef::translation[]
+include::man-common/translation.adoc[]
+endif::[]
--- /dev/null
+/*
+ * setpgid.c -- execute a command in a new process group
+ * Daan De Meyer <daan.j.demeyer@gmail.com>
+ * In the public domain.
+ */
+
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include "closestream.h"
+
+static void __attribute__((__noreturn__)) usage(void)
+{
+ FILE *out = stdout;
+ fputs(USAGE_HEADER, out);
+ fprintf(out, _(
+ " %s [options] <program> [arguments ...]\n"),
+ program_invocation_short_name);
+
+ fputs(USAGE_SEPARATOR, out);
+ fputs(_("Run a program in a new process group.\n"), out);
+
+ fputs(USAGE_OPTIONS, out);
+ fputs(_(" -f, --foregound Make a foreground process group\n"), out);
+
+ printf(USAGE_HELP_OPTIONS(16));
+
+ printf(USAGE_MAN_TAIL("setpgid(1)"));
+ exit(EXIT_SUCCESS);
+}
+
+int main(int argc, char **argv)
+{
+ int ch, foreground = 0, fd;
+ sigset_t s, old;
+
+ static const struct option longopts[] = {
+ {"foreground", no_argument, NULL, 'f'},
+ {"version", no_argument, NULL, 'V'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, NULL, 0}
+ };
+
+ setlocale(LC_ALL, "");
+ bindtextdomain(PACKAGE, LOCALEDIR);
+ textdomain(PACKAGE);
+ close_stdout_atexit();
+
+ while ((ch = getopt_long(argc, argv, "+Vh", longopts, NULL)) != -1)
+ switch (ch) {
+ case 'f':
+ foreground = 1;
+ break;
+ case 'h':
+ usage();
+ case 'V':
+ print_version(EXIT_SUCCESS);
+ default:
+ errtryhelp(EXIT_FAILURE);
+ }
+
+ if (argc - optind < 1) {
+ warnx(_("no command specified"));
+ errtryhelp(EXIT_FAILURE);
+ }
+
+ if (setpgid(0, 0) < 0)
+ err(EXIT_FAILURE, _("setpgid failed"));
+
+ if (foreground) {
+ fd = open("/dev/tty", O_RDONLY|O_CLOEXEC);
+ if (fd >= 0) {
+ if (sigemptyset(&s) < 0)
+ err(EXIT_FAILURE, _("sigemptyset failed"));
+ if (sigaddset(&s, SIGTTOU) < 0)
+ err(EXIT_FAILURE, _("sigaddset failed"));
+ if (sigprocmask(SIG_BLOCK, &s, &old) < 0)
+ err(EXIT_FAILURE, _("sigprocmask failed"));
+ if (tcsetpgrp(fd, getpgid(0)) < 0)
+ err(EXIT_FAILURE, _("tcsetpgrp failed"));
+ if (sigprocmask(SIG_SETMASK, &old, NULL) < 0)
+ err(EXIT_FAILURE, _("sigprocmask failed"));
+ }
+ }
+
+ execvp(argv[optind], argv + optind);
+ errexec(argv[optind]);
+}
--- /dev/null
+#!/bin/bash
+
+# This file is part of util-linux.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+TS_TOPDIR="${0%/*}/../.."
+TS_DESC="setpgid"
+
+. "$TS_TOPDIR"/functions.sh
+ts_init "$*"
+
+ts_check_test_command "$TS_CMD_SETPGID"
+
+$TS_CMD_SETPGID echo "success" >> $TS_OUTPUT 2>> $TS_ERRLOG
+
+# qemu-user always reports '0' for the pgid field which prevents the test from
+# working so we skip it.
+ts_skip_qemu_user
+
+PGID1="$(awk '{print $5}' /proc/self/stat)"
+PGID2="$($TS_CMD_SETPGID awk '{print $5}' /proc/self/stat)"
+test ! "$PGID1" = "$PGID2" && echo "not equal" >> $TS_OUTPUT
+
+ts_finalize