Most shells written since 1980 support job control, which is implemented by assigning a process group to each process in a pipeline of commands. The process group is set by setpgrp(), which sets the process's pgrp to its pid.
The pgrp is inherited across forks.
So, if your shell is a relatively modern one, a program started by an interactive shell will have getpid() == getpgrp(), and any additional processes forked by that process (say, if it's a shell script or if it calls system()) will have getpid() != getpgrp().
Here's a test program, and its behavior under bash (it will behave the same under ksh93 and tcsh as well):
pp.c
#include <unistd.h>
#include <stdio.h>
main()
{
printf("pid=%d pgrp=%d\n", (int)getpid(), (int)getpgrp());
}
$ ./pp
pid=3164 pgrp=3164
$ ./pp &
[1] 3165
$ pid=3165 pgrp=3165
In a pipeline, the leftmost command is the process group leader. (This isn't documented, but bash, ksh93, and tcsh all do it this way).
$ ls|./pp
pid=3179 pgrp=3178
$ ./pp|cat
pid=3180 pgrp=3180
A program called with system() will have the same pgrp as its parent:
pps.c
#include <stdlib.h>
main()
{
system("./pp");
}
$ ./pps
pid=4610 pgrp=4608
In a shell script, the shell is the process group leader, and any command invoked by it will inherit the pgrp:
pp.sh
#!/bin/sh
./pp
$ ./pp.sh
pid=4501 pgrp=4500
But if the shell script execs a program, the pid doesn't change, and the execed program will be a process group leader, so you probably don't want to do that.
ppe.sh
#!/bin/sh
exec ./pp
$ ./ppe.sh
pid=4504 pgrp=4504
In the unlikely case that the user turns off job control, every command is going to have the same pgrp as the shell:
$ set +m
$ ./pp
pid=4521 pgrp=2990
$ ./pp
pid=4522 pgrp=2990
stty()- if this is what you think of - is not implemented in my Linux.isatty(1)tells you the output goes to a terminal;isatty(0)would tell you about input. Andsystem()can be used with output going to terminal and you can run it from the command line with input coming from files and output going to files. What are you really needing to know? There's an element of an XY Problem here. What is the problem you are trying to solve by determining whether the program was run viasystem()? As you've found,systemis usually implemented so that it runs a shell, perhaps Bash, with-cand 'what you provided as an argument tosystem()'.#! /bin/sh -\nyour-magic-command "$@"and suddenly they're allowed. Perhaps check for a specialENABLE_MAGIC_COMMAND=yesenvironment variable, or a lock file which only thesystem()-calling program can write. If the special arguments are, say, passwords, then an environment variable or named pipe might be how to pass them to asystem()child in a way that a command-line would find difficult – these wouldn't find their way to the history.