system(3)
๐ system(3) โ Library Functions Manual ๐
okay bestie, sit down, we're talking about system() โ the libc girlie from the Library Functions Manual section 3. she's the one who runs a shell command for you. iconic behaviour, lowkey chaotic energy, but we love her. ๐ฆ
โจ NAME โจ
system โ execute a shell command ๐ซ
๐ LIBRARY ๐
Standard C library (libc, -lc) ๐ซถ
๐ธ SYNOPSIS ๐ธ
#include <stdlib.h>
int system(const char *command);
๐ DESCRIPTION ๐
so the way system() works is it literally behaves as if it called fork(2) to spawn a child process, and that child runs the shell command you put in command, using execl(3), exactly like this:
execl("/bin/sh", "sh", "-c", command, (char *) NULL);
and then system() comes back to you after the command has fully finished. no ghosting, she waits. โญ
while the command is running, SIGCHLD gets blocked, and SIGINT and SIGQUIT get ignored โ in the process that calls system(), okay? (those signals get handled according to their defaults inside the child process that actually executes the command. different girl, different rules. ๐
)
and if command is NULL? then system() returns a status telling you whether a shell is even available on the system. vibe check for your shell, basically. ๐
๐ฅ RETURN VALUE ๐ฅ
the return value of system() is one of these, and yes, you need to know all of them:
- if
commandisNULL: you get a nonzero value if a shell is available, or0if no shell is available. ๐ - if a child process could not be created, or its status could not be retrieved: the return value is
-1anderrnois set to indicate the error. not the moment, fr. - if a shell could not be executed in the child process: the return value is as though the child shell terminated by calling
_exit(3)with the status127. - if all system calls succeed: the return value is the termination status of the child shell used to execute
command. (and the termination status of a shell is the termination status of the last command it executes. yeah, it's nested like that. ๐ช)
in the last two cases, the return value is a "wait status" that can be examined using the macros described in waitpid(2). (i.e., WIFEXITED(), WEXITSTATUS(), and so on.) ๐
system() does not affect the wait status of any other children. she minds her own business, periodt. ๐
๐ญ ERRORS ๐ญ
system() can fail with any of the same errors as fork(2). yeah. all of them. go read that page bestie.
๐ง ATTRIBUTES ๐ง
for an explanation of the terms used in this section, see attributes(7).
- Interface:
system() - Attribute: Thread safety
- Value:
MT-Safe
so yes, she's MT-Safe. slay. โจ
โญ STANDARDS โญ
C11, POSIX.1-2008. certified, standardised, official. ๐
๐ฆ HISTORY ๐ฆ
POSIX.1-2001, C89. she's been around, she's a legacy icon.
๐ NOTES ๐
system() provides simplicity and convenience: she handles all of the details of calling fork(2), execl(3), and waitpid(2), plus all the necessary manipulations of signals. and on top of that, the shell performs the usual substitutions and I/O redirections for command. so much is happening for you and you didn't even have to ask. ๐ฅน
the main cost of system() is inefficiency: additional system calls are required to create the process that runs the shell and to execute the shell. she's convenient, not free. ๐
if the _XOPEN_SOURCE feature test macro is defined (before including any header files!), then the macros described in waitpid(2) (WEXITSTATUS(), etc.) are made available when including <stdlib.h>. define it early or miss out, no cap.
as mentioned, system() ignores SIGINT and SIGQUIT. this may make programs that call it from a loop uninterruptible, unless they take care themselves to check the exit status of the child. so like, do this:
while (something) {
int ret = system("foo");
if (WIFSIGNALED(ret) &&
(WTERMSIG(ret) == SIGINT || WTERMSIG(ret) == SIGQUIT))
break;
}
see how she checks and breaks out herself? that's the self-care. ๐ซถ
according to POSIX.1, it is unspecified whether handlers registered using pthread_atfork(3) are called during the execution of system(). in the glibc implementation, such handlers are not called. ๐
before glibc 2.1.3, the check for the availability of /bin/sh was not actually performed if command was NULL; instead it was always assumed to be available, and system() always returned 1 in this case. since glibc 2.1.3, this check is performed, because โ even though POSIX.1-2001 requires a conforming implementation to provide a shell โ that shell may not be available or executable if the calling program has previously called chroot(2) (which is not specified by POSIX.1-2001). history lesson, bestie. ๐
it is possible for the shell command to terminate with a status of 127, which yields a system() return value that is indistinguishable from the case where a shell could not be executed in the child process. ๐ yeah. that's a real one. be careful.
๐จ Caveats ๐จ
do NOT usesystem()from a privileged program (a set-user-ID or set-group-ID program, or a program with capabilities) โ because strange values for some environment variables might be used to subvert system integrity. for example,PATHcould be manipulated so that an arbitrary program is executed with privilege. ๐ฑ use theexec(3)family of functions instead โ but notexeclp(3)orexecvp(3)(which also use thePATHenvironment variable to search for an executable). iykyk.
system() will not, in fact, work properly from programs with set-user-ID or set-group-ID privileges on systems on which /bin/sh is bash version 2: as a security measure, bash 2 drops privileges on startup. (Debian uses a different shell, dash(1), which does not do this when invoked as sh.) ๐
any user input that is employed as part of command should be carefully sanitized, to ensure that unexpected shell commands or command options are not executed. such risks are especially grave when using system() from a privileged program. sanitize your inputs, bestie, i'm begging. ๐
๐ BUGS ๐
if the command name starts with a hyphen, sh(1) interprets the command name as an option, and the behavior is undefined. (see the -c option to sh(1).) no cap, undefined. ๐
to work around this problem, prepend the command with a space, as in the following call:
system(" -unfortunate-command-name");
one little space. that's the whole hack. iconic. โจ
๐ SEE ALSO ๐
sh(1), execve(2), fork(2), sigaction(2), sigprocmask(2), wait(2), exec(3), signal(7)
and that's the whole page bestie ๐ โ this was Linux man-pages 6.20, dated 2026-06-05, and it's the system(3) page. go forth and shell out responsibly. mwah ๐
๐ฆ where this page comes from
- arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- ๐ the page's license: Linux-man-pages-copyleft
- Copyright 1993, Thomas Koenig <ig25@rz.uni-karlsruhe.de>
- Copyright 2014, Michael Kerrisk <mtk.manpages@gmail.com>
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms