# Process identity Six variables expose what the operating system thinks of this process: its name, its PID, and its real-and-effective user and group IDs. They are most useful in scripts that need to act based on *who is running them*, drop privileges after a privileged operation, or distinguish parent from child after a [`fork`](../perlfunc/fork.md). | Variable | What it holds | Mutable | |------------|--------------------------------------|------------------| | `$0` | Program name (and `ps` display) | yes | | `$$` | Current process PID | no (read-only) | | `$<` | Real UID | yes (privileged) | | `$>` | Effective UID | yes (privileged) | | `$(` | Real GID (plus supplementaries) | yes (privileged) | | `$)` | Effective GID (plus supplementaries) | yes (privileged) | ## `$0` — program name The name of the program being executed, as passed in `argv[0]`: ```perl print "Started by: $0\n"; # e.g. "/usr/local/bin/myscript.pl" ``` Assigning to `$0` changes how the process appears in `ps` output and similar listings — handy for long-running scripts that fork and want each child to be identifiable: ```perl $0 = "myserver: worker pid $$"; # appears in `ps` as that string ``` The change writes into the area of process memory that `ps` reads on Linux. Older Unix variants and Windows have different rules; PetaPerl follows perl5’s behaviour exactly. Reading `$0` always returns the current value, including any modifications you have made. `$0` is **not** the program name as the *script* sees it — for that, see [`@ARGV`](args-env-inc.md) (which has `$0` as the companion at index `[-1]` of the original `argv`, not as `@ARGV[0]`). ## `$$` — process ID Read-only. The PID of the current process. ```perl print "Running as PID $$\n"; open my $log, '>>', "/var/log/myapp.log" or die $!; print $log "[$$] starting...\n"; ``` After `fork`, the child sees a different `$$` from the parent — this is the standard way to tell which side of the fork you are on: ```perl my $pid = fork; defined $pid or die "fork: $!"; if ($pid == 0) { # child print "child: my pid is $$\n"; exit 0; } # parent print "parent: my pid is $$, child is $pid\n"; waitpid $pid, 0; ``` The English alias `$PROCESS_ID` (and the redundant `$PID`) work the same as `$$`. To get the *parent’s* PID, use [`getppid`](../perlfunc/getppid.md). ## Real vs effective IDs — what they mean Every Unix process has *two* user IDs and *two* group IDs: - The **real** UID/GID is who you are — usually the user who invoked the program. - The **effective** UID/GID is what the kernel checks for permission decisions — typically the same as real, but different for *setuid* and *setgid* programs. When you run a setuid-root binary, the kernel sets the effective UID to root (the file’s owner) but leaves the real UID as your own. The program can then act as root for the privileged operation, and either *drop privileges* by setting effective back to real, or *check who really invoked it* by reading the real UID. ## `$<` — real UID ```perl print "Invoked by user with UID $<\n"; ``` `$<` is the real UID. It almost never changes during a process’s lifetime; the cases where it can are very limited (only `root` can change it, and only via specific syscalls). Mnemonic: *the UID you came **from***. ## `$>` — effective UID ```perl print "Privileges currently effective: UID $>\n"; ``` `$>` is the effective UID — the one that matters for permission checks. In a setuid program, this is initially the file owner’s UID; in an ordinary program, it equals `$<`. Mnemonic: *the UID you went **to***. ### The classic setuid pattern A setuid-root helper that needs to do *one* privileged operation and then drop privileges so the rest of the script runs as the real user: ```perl #!/usr/bin/perl use strict; use warnings; # Privileged work first — we still have effective root. open my $secret, '<', '/etc/some-restricted-file' or die "open: $!"; my $config = do { local $/; <$secret> }; close $secret; # Drop privileges. From now on, both real and effective UID # are the invoking user's, so any subsequent open/system call # is checked against the real user. $> = $<; # set effective UID to real UID $) = $(; # set effective GID to real GID # Now run the rest of the script as the real user. do_user_work($config); ``` Permanent privilege drop **must** set effective before real (or both at once via `POSIX::setuid()`); on most systems setting real first will lock you out of restoring effective. Check [`$!`](error.md) after each assignment — the kernel rejects unauthorised changes: ```perl $> = $<; die "could not drop privileges: $!" if $> != $<; ``` ### Swapping real and effective When you want to *temporarily* switch the effective ID for a single operation and then restore it: ```perl my $saved_uid = $>; $> = $<; # become real user my $ok = open(my $fh, '<', $user_path); $> = $saved_uid; # back to effective $ok or die "open $user_path: $!"; ``` This works only on systems supporting `setreuid()` — most modern Unixes, including Linux. `POSIX::seteuid()` from the [`POSIX`](../../POSIX.md) module is the explicit and portable spelling. ## `$(` — real GID (with supplementary groups) `$(` returns the real GID followed by every *supplementary group* the process belongs to, all space-separated: ```perl print "Real GID list: $(\n"; # e.g. "1000 1000 4 27 100 999" # primary + supplementaries my @groups = split ' ', $(; my $primary = $groups[0]; ``` The leading number is the primary GID; the rest are supplementary groups (from `/etc/group`). Assigning to `$(` sets the GID; the syntax accepts a single number: ```perl $( = 100; # become primary GID 100 ``` ## `$)` — effective GID (with supplementary groups) Same shape as `$(`, but for the effective GID: ```perl print "Effective GID list: $)\n"; # Drop both real and effective GID to a specific gid: $( = $) = "$gid $gid"; ``` Permission checks use the effective GID and supplementaries; the real GID list is informational. ## When you actually use these Day-to-day Perl code does not touch UIDs and GIDs. The realistic use cases are: 1. **Setuid scripts** that need to drop privileges. Standard idiom shown above. 2. **Daemon startup** that runs as root to bind a privileged port, then drops privileges before serving requests: ```perl socket(my $srv, ...) or die $!; bind($srv, sockaddr_in(80, INADDR_ANY)) or die $!; listen($srv, SOMAXCONN) or die $!; # Now drop to nobody:nogroup before accepting connections. my (undef, undef, $u, $g) = getpwnam('nobody'); $) = "$g $g"; $( = $g; $> = $u; $< = $u; ``` 3. **Privilege check** in a script that should refuse to run as root: `die "do not run me as root\n" if $< == 0`. ## Tainted-mode interaction Under [`-T`](../../../guide/oneliner/switches.md), Perl notices when the real and effective IDs differ (i.e. the script is setuid) and turns on extra checks: certain operations refuse tainted arguments, and the search path for `system()` and `exec()` is constrained. The relevance here is that whether `-T` is on is decided based on `$<` vs `$>` at startup. ## See also - [`getppid`](../perlfunc/getppid.md) — the *parent’s* PID, paired with `$$`. - [`fork`](../perlfunc/fork.md) — after which `$$` differs in parent and child. - [`getpwuid`](../perlfunc/getpwuid.md), [`getgrgid`](../perlfunc/getgrgid.md) — turn the numeric IDs into user and group names. - [`POSIX::setuid`](../../POSIX.md) — the portable, explicit way to change UIDs together. - [Error variables](error.md) — `$!` after an `$<` / `$>` assignment tells you why the kernel refused.