TODO: add an item for a chmod optimization
[platform/upstream/coreutils.git] / src / chroot.c
1 /* chroot -- run command or shell with special root directory
2    Copyright (C) 95, 96, 1997, 1999-2004, 2007-2008
3    Free Software Foundation, Inc.
4
5    This program is free software: you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation, either version 3 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18 /* Written by Roland McGrath.  */
19
20 #include <config.h>
21 #include <getopt.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24
25 #include "system.h"
26 #include "error.h"
27 #include "long-options.h"
28 #include "quote.h"
29
30 /* The official name of this program (e.g., no `g' prefix).  */
31 #define PROGRAM_NAME "chroot"
32
33 #define AUTHORS proper_name ("Roland McGrath")
34
35 void
36 usage (int status)
37 {
38   if (status != EXIT_SUCCESS)
39     fprintf (stderr, _("Try `%s --help' for more information.\n"),
40              program_name);
41   else
42     {
43       printf (_("\
44 Usage: %s NEWROOT [COMMAND [ARG]...]\n\
45   or:  %s OPTION\n\
46 "), program_name, program_name);
47       fputs (_("\
48 Run COMMAND with root directory set to NEWROOT.\n\
49 \n\
50 "), stdout);
51       fputs (HELP_OPTION_DESCRIPTION, stdout);
52       fputs (VERSION_OPTION_DESCRIPTION, stdout);
53       fputs (_("\
54 \n\
55 If no command is given, run ``${SHELL} -i'' (default: /bin/sh).\n\
56 "), stdout);
57       emit_bug_reporting_address ();
58     }
59   exit (status);
60 }
61
62 int
63 main (int argc, char **argv)
64 {
65   initialize_main (&argc, &argv);
66   set_program_name (argv[0]);
67   setlocale (LC_ALL, "");
68   bindtextdomain (PACKAGE, LOCALEDIR);
69   textdomain (PACKAGE);
70
71   initialize_exit_failure (EXIT_FAILURE);
72   atexit (close_stdout);
73
74   parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
75                       usage, AUTHORS, (char const *) NULL);
76   if (getopt_long (argc, argv, "+", NULL, NULL) != -1)
77     usage (EXIT_FAILURE);
78
79   if (argc <= optind)
80     {
81       error (0, 0, _("missing operand"));
82       usage (EXIT_FAILURE);
83     }
84
85   if (chroot (argv[optind]) != 0)
86     error (EXIT_FAILURE, errno, _("cannot change root directory to %s"), argv[1]);
87
88   if (chdir ("/"))
89     error (EXIT_FAILURE, errno, _("cannot chdir to root directory"));
90
91   if (argc == optind + 1)
92     {
93       /* No command.  Run an interactive shell.  */
94       char *shell = getenv ("SHELL");
95       if (shell == NULL)
96         shell = "/bin/sh";
97       argv[0] = shell;
98       argv[1] = "-i";
99       argv[2] = NULL;
100     }
101   else
102     {
103       /* The following arguments give the command.  */
104       argv += optind + 1;
105     }
106
107   /* Execute the given command.  */
108   execvp (argv[0], argv);
109
110   {
111     int exit_status = (errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
112     error (0, errno, _("cannot run command %s"), quote (argv[0]));
113     exit (exit_status);
114   }
115 }