]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/switch_root.c
2 * switchroot.c - switch to new root directory and start init.
4 * Copyright 2002-2008 Red Hat, Inc. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * Peter Jones <pjones@redhat.com>
21 * Jeremy Katz <katzj@redhat.com>
23 #include <sys/mount.h>
24 #include <sys/types.h>
26 #include <sys/param.h>
46 /* remove all files/directories below dirName -- don't cross mountpoints */
47 static int recursiveRemove(char *dirName
)
54 if (!(dir
= opendir(dirName
))) {
55 printf("error opening %s: %m\n", dirName
);
61 if (fstat(dfd
, &rb
)) {
62 printf("unable to stat %s: %m\n", dirName
);
70 if (!(d
= readdir(dir
))) {
72 printf("error reading from %s: %m\n", dirName
);
75 break; /* end of directory */
78 if (!strcmp(d
->d_name
, ".") || !strcmp(d
->d_name
, ".."))
81 if (d
->d_type
== DT_DIR
) {
84 if (fstatat(dfd
, d
->d_name
, &sb
, AT_SYMLINK_NOFOLLOW
)) {
85 printf("failed to stat %s/%s: %m\n",
90 /* remove subdirectories if device is same as dir */
91 if (sb
.st_dev
== rb
.st_dev
) {
92 char subdir
[ strlen(dirName
) +
93 strlen(d
->d_name
) + 2 ];
95 sprintf(subdir
, "%s/%s", dirName
, d
->d_name
);
96 recursiveRemove(subdir
);
101 if (unlinkat(dfd
, d
->d_name
,
102 d
->d_type
== DT_DIR
? AT_REMOVEDIR
: 0))
103 printf("failed to unlink %s/%s: %m\n", dirName
, d
->d_name
);
106 rc
= 0; /* success */
114 static int switchroot(const char *newroot
)
116 /* Don't try to unmount the old "/", there's no way to do it. */
117 const char *umounts
[] = { "/dev", "/proc", "/sys", NULL
};
121 for (i
= 0; umounts
[i
] != NULL
; i
++) {
122 char newmount
[PATH_MAX
];
123 strcpy(newmount
, newroot
);
124 strcat(newmount
, umounts
[i
]);
125 if (mount(umounts
[i
], newmount
, NULL
, MS_MOVE
, NULL
) < 0) {
126 fprintf(stderr
, "Error mount moving old %s %s %m\n",
127 umounts
[i
], newmount
);
128 fprintf(stderr
, "Forcing unmount of %s\n", umounts
[i
]);
129 umount2(umounts
[i
], MNT_FORCE
);
133 if (chdir(newroot
) < 0) {
135 fprintf(stderr
, "switchroot: chdir failed: %m\n");
139 recursiveRemove("/");
140 if (mount(newroot
, "/", NULL
, MS_MOVE
, NULL
) < 0) {
142 fprintf(stderr
, "switchroot: mount failed: %m\n");
149 fprintf(stderr
, "switchroot: chroot failed: %m\n");
156 static void usage(FILE *output
)
158 fprintf(output
, "usage: switchroot <newrootdir> <init> <args to init>\n");
159 if (output
== stderr
)
164 int main(int argc
, char *argv
[])
166 char *newroot
= argv
[1];
167 char *init
= argv
[2];
168 char **initargs
= &argv
[2];
170 if (newroot
== NULL
|| newroot
[0] == '\0' ||
171 init
== NULL
|| init
[0] == '\0' ) {
175 if (switchroot(newroot
) < 0) {
176 fprintf(stderr
, "switchroot has failed. Sorry.\n");
179 if (access(initargs
[0], X_OK
))
180 fprintf(stderr
, "WARNING: can't access %s\n", initargs
[0]);
182 /* get session leader */
184 /* set controlling terminal */
185 ioctl (0, TIOCSCTTY
, 1);
187 execv(initargs
[0], initargs
);