Merge lp:~csurbhi/upstart/upstart-add-pivot-handling into lp:upstart

Proposed by Surbhi Palande
Status: Work in progress
Proposed branch: lp:~csurbhi/upstart/upstart-add-pivot-handling
Merge into: lp:upstart
Diff against target: 1254 lines (+972/-15)
12 files modified
dbus/com.ubuntu.Upstart.xml (+7/-1)
init/Makefile.am (+12/-11)
init/conf.c (+35/-0)
init/conf.h (+1/-0)
init/control.c (+35/-0)
init/control.h (+3/-0)
init/events.h (+8/-1)
init/paths.h (+8/-0)
init/pivot.c (+616/-0)
init/pivot.h (+66/-0)
init/tests/test_control.c (+106/-1)
util/initctl.c (+75/-1)
To merge this branch: bzr merge lp:~csurbhi/upstart/upstart-add-pivot-handling
Reviewer Review Type Date Requested Status
Scott James Remnant Pending
Review via email: mp+64723@code.launchpad.net

Description of the change

The pivot command is used for changing the root filesystem in the initramfs from the memory based "/" to the disk based real root filesystem. This command can be issued as follows:

initctl pivot <ROOTFS> <INIT>

where ROOTFS is the root filesystem that we want to move to while in the initramfs. INIT is the first program that we wish to execute once this move to the real root filesystem is made.

This command is intended to be used when upstart is executed in initramfs for making the initramfs event driven.

It is assumed that a user can specify a different ROOTFS, INIT or arguments to this new INIT at the grub command prompt. The console used for logging the messages is /dev/console and is a not a boot argument which can be changed.

This command has no effect when it is executed from a non memory based root filesystem.

This change shall enable upstart to be used as init in the initramfs for making the initramfs event driven. Please do let me know your thoughts on this change.

Thanks!

To post a comment you must log in.
1316. By Surbhi Palande

Initial support to handle a new initctl command: pivot.
Usage: initctl pivot <ROOTFS> <INIT>" "<args>"

This command can be used to change the root filesystem from a initramfs
based rootfs to the new requested <ROOTFS>. On successfully changing the root
filesystem the new <INIT> shall be executed. On failure in handling this
command a pivot-failed event is emitted. This command works as intended
only when fired from initramfs. When fired from any other filesystem, this
command has no effect other than the emission of the "pivot-failed" event.

1317. By Surbhi Palande

Some cleanup related fixes. Expecting one or two more!

1318. By Surbhi Palande

One more typo fix

Unmerged revisions

1318. By Surbhi Palande

One more typo fix

1317. By Surbhi Palande

Some cleanup related fixes. Expecting one or two more!

1316. By Surbhi Palande

Initial support to handle a new initctl command: pivot.
Usage: initctl pivot <ROOTFS> <INIT>" "<args>"

This command can be used to change the root filesystem from a initramfs
based rootfs to the new requested <ROOTFS>. On successfully changing the root
filesystem the new <INIT> shall be executed. On failure in handling this
command a pivot-failed event is emitted. This command works as intended
only when fired from initramfs. When fired from any other filesystem, this
command has no effect other than the emission of the "pivot-failed" event.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'dbus/com.ubuntu.Upstart.xml'
--- dbus/com.ubuntu.Upstart.xml 2010-12-10 07:18:34 +0000
+++ dbus/com.ubuntu.Upstart.xml 2011-07-15 17:51:29 +0000
@@ -3,7 +3,7 @@
33
4 com.ubuntu.Upstart.xml - interface definition for manager object4 com.ubuntu.Upstart.xml - interface definition for manager object
55
6 Copyright © 2009 Canonical Ltd.6 Copyright © 2009-2011 Canonical Ltd.
7 Author: Scott James Remnant <scott@netsplit.com>.7 Author: Scott James Remnant <scott@netsplit.com>.
88
9 This file is free software; Canonical Ltd gives unlimited permission9 This file is free software; Canonical Ltd gives unlimited permission
@@ -57,6 +57,12 @@
57 <arg name="file" type="h" direction="in" />57 <arg name="file" type="h" direction="in" />
58 </method>58 </method>
5959
60 <!-- Pivot to new rootfs and execute new init -->
61 <method name="PivotToNewRootfs">
62 <arg name="rootfs" type="s" direction="in" />
63 <arg name="init" type="s" direction="in" />
64 </method>
65
60 <!-- Basic information about Upstart -->66 <!-- Basic information about Upstart -->
61 <property name="version" type="s" access="read" />67 <property name="version" type="s" access="read" />
62 <property name="log_priority" type="s" access="readwrite" />68 <property name="log_priority" type="s" access="readwrite" />
6369
=== modified file 'init/Makefile.am'
--- init/Makefile.am 2011-05-15 12:53:17 +0000
+++ init/Makefile.am 2011-07-15 17:51:29 +0000
@@ -51,6 +51,7 @@
51 parse_conf.c parse_conf.h \51 parse_conf.c parse_conf.h \
52 conf.c conf.h \52 conf.c conf.h \
53 control.c control.h \53 control.c control.h \
54 pivot.c pivot.h \
54 errors.h55 errors.h
55nodist_init_SOURCES = \56nodist_init_SOURCES = \
56 $(com_ubuntu_Upstart_OUTPUTS) \57 $(com_ubuntu_Upstart_OUTPUTS) \
@@ -159,7 +160,7 @@
159 system.o environ.o process.o \160 system.o environ.o process.o \
160 job_class.o job_process.o job.o event.o event_operator.o blocked.o \161 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
161 parse_job.o parse_conf.o conf.o control.o \162 parse_job.o parse_conf.o conf.o control.o \
162 session.o \163 session.o pivot.o \
163 com.ubuntu.Upstart.o \164 com.ubuntu.Upstart.o \
164 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \165 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
165 $(NIH_LIBS) \166 $(NIH_LIBS) \
@@ -171,7 +172,7 @@
171 system.o environ.o process.o \172 system.o environ.o process.o \
172 job_class.o job_process.o job.o event.o event_operator.o blocked.o \173 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
173 parse_job.o parse_conf.o conf.o control.o \174 parse_job.o parse_conf.o conf.o control.o \
174 session.o \175 session.o pivot.o \
175 com.ubuntu.Upstart.o \176 com.ubuntu.Upstart.o \
176 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \177 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
177 $(NIH_LIBS) \178 $(NIH_LIBS) \
@@ -183,7 +184,7 @@
183 system.o environ.o process.o \184 system.o environ.o process.o \
184 job_class.o job_process.o job.o event.o event_operator.o blocked.o \185 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
185 parse_job.o parse_conf.o conf.o control.o \186 parse_job.o parse_conf.o conf.o control.o \
186 session.o \187 session.o pivot.o \
187 com.ubuntu.Upstart.o \188 com.ubuntu.Upstart.o \
188 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \189 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
189 $(NIH_LIBS) \190 $(NIH_LIBS) \
@@ -195,7 +196,7 @@
195 system.o environ.o process.o \196 system.o environ.o process.o \
196 job_class.o job_process.o job.o event.o event_operator.o blocked.o \197 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
197 parse_job.o parse_conf.o conf.o control.o \198 parse_job.o parse_conf.o conf.o control.o \
198 session.o \199 session.o pivot.o \
199 com.ubuntu.Upstart.o \200 com.ubuntu.Upstart.o \
200 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \201 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
201 $(NIH_LIBS) \202 $(NIH_LIBS) \
@@ -207,7 +208,7 @@
207 system.o environ.o process.o \208 system.o environ.o process.o \
208 job_class.o job_process.o job.o event.o event_operator.o blocked.o \209 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
209 parse_job.o parse_conf.o conf.o control.o \210 parse_job.o parse_conf.o conf.o control.o \
210 session.o \211 session.o pivot.o \
211 com.ubuntu.Upstart.o \212 com.ubuntu.Upstart.o \
212 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \213 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
213 $(NIH_LIBS) \214 $(NIH_LIBS) \
@@ -219,7 +220,7 @@
219 system.o environ.o process.o \220 system.o environ.o process.o \
220 job_class.o job_process.o job.o event.o event_operator.o blocked.o \221 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
221 parse_job.o parse_conf.o conf.o control.o \222 parse_job.o parse_conf.o conf.o control.o \
222 session.o \223 session.o pivot.o \
223 com.ubuntu.Upstart.o \224 com.ubuntu.Upstart.o \
224 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \225 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
225 $(NIH_LIBS) \226 $(NIH_LIBS) \
@@ -231,7 +232,7 @@
231 system.o environ.o process.o \232 system.o environ.o process.o \
232 job_class.o job_process.o job.o event.o event_operator.o blocked.o \233 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
233 parse_job.o parse_conf.o conf.o control.o \234 parse_job.o parse_conf.o conf.o control.o \
234 session.o \235 session.o pivot.o \
235 com.ubuntu.Upstart.o \236 com.ubuntu.Upstart.o \
236 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \237 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
237 $(NIH_LIBS) \238 $(NIH_LIBS) \
@@ -243,7 +244,7 @@
243 system.o environ.o process.o \244 system.o environ.o process.o \
244 job_class.o job_process.o job.o event.o event_operator.o blocked.o \245 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
245 parse_job.o parse_conf.o conf.o control.o \246 parse_job.o parse_conf.o conf.o control.o \
246 session.o \247 session.o pivot.o \
247 com.ubuntu.Upstart.o \248 com.ubuntu.Upstart.o \
248 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \249 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
249 $(NIH_LIBS) \250 $(NIH_LIBS) \
@@ -255,7 +256,7 @@
255 system.o environ.o process.o \256 system.o environ.o process.o \
256 job_class.o job_process.o job.o event.o event_operator.o blocked.o \257 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
257 parse_job.o parse_conf.o conf.o control.o \258 parse_job.o parse_conf.o conf.o control.o \
258 session.o \259 session.o pivot.o \
259 com.ubuntu.Upstart.o \260 com.ubuntu.Upstart.o \
260 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \261 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
261 $(NIH_LIBS) \262 $(NIH_LIBS) \
@@ -267,7 +268,7 @@
267 system.o environ.o process.o \268 system.o environ.o process.o \
268 job_class.o job_process.o job.o event.o event_operator.o blocked.o \269 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
269 parse_job.o parse_conf.o conf.o control.o \270 parse_job.o parse_conf.o conf.o control.o \
270 session.o \271 session.o pivot.o \
271 com.ubuntu.Upstart.o \272 com.ubuntu.Upstart.o \
272 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \273 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
273 $(NIH_LIBS) \274 $(NIH_LIBS) \
@@ -279,7 +280,7 @@
279 system.o environ.o process.o \280 system.o environ.o process.o \
280 job_class.o job_process.o job.o event.o event_operator.o blocked.o \281 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
281 parse_job.o parse_conf.o conf.o control.o \282 parse_job.o parse_conf.o conf.o control.o \
282 session.o \283 session.o pivot.o \
283 com.ubuntu.Upstart.o \284 com.ubuntu.Upstart.o \
284 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \285 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
285 $(NIH_LIBS) \286 $(NIH_LIBS) \
286287
=== modified file 'init/conf.c'
--- init/conf.c 2011-06-06 17:05:11 +0000
+++ init/conf.c 2011-07-15 17:51:29 +0000
@@ -1186,6 +1186,41 @@
1186 return NULL;1186 return NULL;
1187}1187}
11881188
1189/*
1190 * delete_conf_watches:
1191 *
1192 * This function is called to delete the notification handlers registered
1193 * against the configuration directories/files.
1194 */
1195void delete_conf_watches ()
1196{
1197 NihList * watches;
1198 NihWatch * watch;
1199 NihWatchHandle *handle;
1200 NIH_LIST_FOREACH (conf_sources, iter) {
1201 ConfSource *source = (ConfSource *) iter;
1202 if (! source)
1203 return;
1204 if(source->path) {
1205 nih_debug ("freeing source for path: %s", source->path);
1206 }
1207 /* remove the notification watches */
1208 watch = source->watch;
1209 if (watch) {
1210 watches = & (watch->watches);
1211 if (watches) {
1212 NIH_LIST_FOREACH (watches, wh) {
1213 handle = (NihWatchHandle *)wh;
1214 inotify_rm_watch (watch->fd, handle->wd);
1215 }
1216 }
1217 close (watch->fd);
1218 nih_free (source);
1219 }
1220 }
1221}
1222
1223
1189#ifdef DEBUG1224#ifdef DEBUG
11901225
1191size_t1226size_t
11921227
=== modified file 'init/conf.h'
--- init/conf.h 2011-06-06 12:52:08 +0000
+++ init/conf.h 2011-07-15 17:51:29 +0000
@@ -129,6 +129,7 @@
129129
130char *toggle_conf_name (const void *parent, const char *path)130char *toggle_conf_name (const void *parent, const char *path)
131 __attribute__ ((warn_unused_result, malloc));131 __attribute__ ((warn_unused_result, malloc));
132void delete_conf_watches (void);
132133
133#ifdef DEBUG134#ifdef DEBUG
134135
135136
=== modified file 'init/control.c'
--- init/control.c 2011-06-15 13:20:41 +0000
+++ init/control.c 2011-07-15 17:51:29 +0000
@@ -54,6 +54,7 @@
54#include "conf.h"54#include "conf.h"
55#include "control.h"55#include "control.h"
56#include "errors.h"56#include "errors.h"
57#include "pivot.h"
5758
58#include "com.ubuntu.Upstart.h"59#include "com.ubuntu.Upstart.h"
5960
@@ -613,6 +614,40 @@
613 return 0;614 return 0;
614}615}
615616
617/**
618 * control_pivot_to_new_rootfs:
619 * @data: not used,
620 * @message: D-Bus connection and message received,
621 * @rootfs: dir to chroot to
622 * @init: new init to spawn on chrooting to rootfs
623 * This shall be filled in by pivot_to_new_rootfs ()
624 *
625 * Called to change the root filesystem to a requested @rootfs, after which the
626 * requested @init should be executed. This function changes the root
627 * filesystem only when "/" is on initramfs and the @rootfs is the real rootfs
628 * to be switched to. On changing the root filesystem as requested, this
629 * function releases memory by deleting the contents of the memory based
630 * initramfs before executing @init. If @rootfs or @init are not valid, the
631 * org.freedesktop.DBus.Error.InvalidArg error will be returned immediately.
632 * If this function fails before freeing the contents of the initramfs then
633 * the pivot_failed event is generated. If this function fails after the
634 * contents of the initramfs have been freed then failure handling is no more
635 * possible.
636 *
637 * Returns: does not return on success, negative value on raised error.
638 **/
639int
640control_pivot_to_new_rootfs (void *data,
641 NihDBusMessage *message,
642 const char *rootfs,
643 const char *init)
644{
645 nih_assert (message != NULL);
646 nih_assert (rootfs != NULL);
647 nih_assert (init != NULL);
648
649 return pivot_to_new_rootfs (message, rootfs, init);
650}
616651
617/**652/**
618 * control_get_version:653 * control_get_version:
619654
=== modified file 'init/control.h'
--- init/control.h 2011-06-06 17:05:11 +0000
+++ init/control.h 2011-07-15 17:51:29 +0000
@@ -72,6 +72,9 @@
72 const char *name, char * const *env,72 const char *name, char * const *env,
73 int wait)73 int wait)
74 __attribute__ ((warn_unused_result));74 __attribute__ ((warn_unused_result));
75int control_pivot_to_new_rootfs (void *data, NihDBusMessage *message,
76 const char *rootfs, const char *init)
77 __attribute__ ((warn_unused_result));
75int control_emit_event_with_file (void *data, NihDBusMessage *message,78int control_emit_event_with_file (void *data, NihDBusMessage *message,
76 const char *name, char * const *env,79 const char *name, char * const *env,
77 int wait, int file)80 int wait, int file)
7881
=== modified file 'init/events.h'
--- init/events.h 2009-06-23 09:29:35 +0000
+++ init/events.h 2011-07-15 17:51:29 +0000
@@ -1,6 +1,6 @@
1/* upstart1/* upstart
2 *2 *
3 * Copyright © 2009 Canonical Ltd.3 * Copyright © 2009-2011 Canonical Ltd.
4 * Author: Scott James Remnant <scott@netsplit.com>.4 * Author: Scott James Remnant <scott@netsplit.com>.
5 *5 *
6 * This program is free software; you can redistribute it and/or modify6 * This program is free software; you can redistribute it and/or modify
@@ -93,5 +93,12 @@
93 **/93 **/
94#define JOB_STOPPED_EVENT "stopped"94#define JOB_STOPPED_EVENT "stopped"
9595
96/**
97 * PIVOT_FAILED_EVENT:
98 *
99 * Name of the event we generate once the pivot event fails to change the
100 * root filesystem.
101 **/
102#define PIVOT_FAILED_EVENT "pivot-failed"
96103
97#endif /* INIT_EVENTS_H */104#endif /* INIT_EVENTS_H */
98105
=== modified file 'init/paths.h'
--- init/paths.h 2011-06-06 12:52:08 +0000
+++ init/paths.h 2011-07-15 17:51:29 +0000
@@ -177,4 +177,12 @@
177 (IS_CONF_EXT_STD(period) || \177 (IS_CONF_EXT_STD(period) || \
178 IS_CONF_EXT_OVERRIDE(period))178 IS_CONF_EXT_OVERRIDE(period))
179179
180/**
181 * Kernel command line arguments path
182 *
183 * This file stores the kernel command line arguments which are read for
184 * executing a new requested init using the pivot command from initramfs.
185 **/
186#define PROC_CMDLINE "/proc/cmdline"
187
180#endif /* INIT_PATHS_H */188#endif /* INIT_PATHS_H */
181189
=== added file 'init/pivot.c'
--- init/pivot.c 1970-01-01 00:00:00 +0000
+++ init/pivot.c 2011-07-15 17:51:29 +0000
@@ -0,0 +1,616 @@
1/* upstart
2 *
3 * pivot.c - Pivot command handling
4 *
5 * Copyright © 2011 Canonical Ltd.
6 * Author: Surbhi A. Palande <surbhi.palande@ubuntu.com>.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2, as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22#include "pivot.h"
23#include "conf.h"
24
25/*
26 * @get_complete_path:
27 *
28 * @dirname: absolute path of the parent directory.
29 * @dirent_name: name of the directory entry whose full path is constructed by
30 * using the parent directories absolute path i.e @dirname
31 *
32 * This function is called for getting an absolute path of a directory entry given
33 * the parent directories absolute path.
34 *
35 * Returns: the absolute path on success. On failure returns NULL.
36 */
37static char *
38get_complete_path (const char * dirname, const char * dirent_name)
39{
40 char * full_path = NULL;
41
42 nih_assert (dirname != NULL);
43 nih_assert (dirent_name != NULL);
44
45 full_path = nih_strdup (NULL, dirname);
46 if (full_path) {
47 if (dirname [strlen(dirname) - 1] != '/') {
48 full_path = nih_strcat (&full_path, NULL, "/");
49 }
50 if (full_path)
51 full_path = nih_strcat (&full_path, NULL, dirent_name);
52 }
53 return full_path;
54}
55
56/*
57 * @del_dir:
58 *
59 * @dirname: directory whose contents need to be deleted.
60 *
61 * This function is called to free the contents of memory by deleting the
62 * memory based members of @dirname. It does not delete the contents of a
63 * member directory in case it is a mount point for other file systems which
64 * are not memory based. This function assumes that "/" is a memory based
65 * filesystem and uses this information to find out whether the underlying
66 * device of a member directory is the same as that of "/" or not.
67 *
68 *
69 * Returns: On success returns 0 while on failure it raises the
70 * org.freedesktop.DBus.Error.InvalidArg error and exits out of upstart as
71 * recovery of a pivot command is not possible.
72 */
73static int
74del_dir (const char * dirname)
75{
76 struct dirent * dirent;
77 struct stat rst, cst;
78 DIR * dirp;
79 char * path = NULL;
80 int ret = 0;
81
82 nih_assert (dirname != NULL);
83
84 ret = stat ("/", &rst);
85 if (ret) {
86 nih_debug ("Could not stat /");
87 goto error;
88 }
89 dirp = opendir (dirname);
90 if (!dirp) {
91 ret = -1;
92 goto error;
93 }
94 while ((dirent = readdir (dirp)) != NULL) {
95 if (!strcmp (dirent->d_name, ".") ||
96 (!strcmp (dirent->d_name, ".."))) {
97 continue;
98 }
99 path = get_complete_path (dirname, dirent->d_name);
100 if (!path) {
101 ret = -1;
102 goto cleanup;
103 }
104 switch (dirent->d_type) {
105 case DT_DIR:
106 ret = stat (path, &cst);
107 /* Free the contents of only the memory based
108 * file systems but not of any other mounted
109 * file systems if any.
110 */
111 if (!ret && dev_match (rst.st_dev, cst.st_dev)) {
112 ret = del_dir (path);
113 if (!ret) {
114 nih_debug ("Removing dir: %s", path);
115 ret = rmdir (path);
116 }
117 }
118 break;
119 default:
120 nih_debug ("Removing file: %s", path);
121 ret = unlink (path);
122 break;
123 }
124 nih_free (path);
125 if (ret)
126 break;
127 }
128cleanup:
129 closedir (dirp);
130error:
131 if (ret) {
132 nih_assert (errno != 0);
133 switch (errno) {
134 case ENOMEM:
135 nih_error_raise_no_memory ();
136 break;
137 default:
138 nih_error_raise (errno, strerror (errno));
139 break;
140 }
141 nih_fatal (_("Could not delete the contents of initramfs: %s"), strerror (errno));
142 exit (1);
143 }
144 return 0;
145}
146
147/**
148 * pivot_emit_failed_event:
149 *
150 * @argv: The arguments to be passed to the new requested init for execution.
151 *
152 * This function generates a new event "pivot_failed". It is used to indicate
153 * that the initcl pivot command failed to chroot to the new rootfs.
154 *
155 * Returns: on success returns the PIVOT_FAILED_EVENT and on failure returns
156 * NULL.
157 **/
158Event *
159pivot_emit_failed_event (char ** argv)
160{
161 Event *event;
162
163 event = NIH_MUST (event_new (NULL, PIVOT_FAILED_EVENT, argv));
164 if (!event) {
165 nih_debug ("Could not emit %s", PIVOT_FAILED_EVENT);
166 nih_free (argv);
167 return NULL;
168 }
169 return event;
170}
171
172/**
173 * @are_we_on_ramfs():
174 *
175 * This function is called to check if the current root filesystem is based on
176 * a memory based filesystem.
177 *
178 * Returns: TRUE if the root filesystem is memory based, else returns FALSE.
179 **/
180static int
181are_we_on_ramfs ()
182{
183 int ret = 0;
184 struct stat st;
185 struct statfs sfs;
186
187 /* Make sure we're on a ramfs */
188 /* 1. The initramfs should have /init */
189 ret = stat ("/init", &st);
190 if (ret) {
191 if (errno == ENOMEM)
192 nih_error_raise_no_memory ();
193 else
194 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
195 _("/ may not be on initramfs"));
196 return FALSE;
197 }
198 if (!S_ISREG (st.st_mode)) {
199 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
200 _("/ may not be on initramfs"));
201 return FALSE;
202 }
203 /* Make sure that the statistics of / indicate that its a memory based
204 * filesystem and not a disk based one */
205 ret = statfs ("/", &sfs);
206 if (ret) {
207 switch(errno) {
208 case ENOMEM:
209 nih_error_raise_no_memory ();
210 break;
211 default:
212 nih_dbus_error_raise_printf (DBUS_ERROR_FAILED,
213 _("Cannot verify if we are in the initramfs"));
214 break;
215 }
216 return FALSE;
217 }
218 if (sfs.f_type != (long) RAMFS_MAGIC && sfs.f_type != (long) TMPFS_MAGIC) {
219 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
220 _("/ is not a memory based filesystem"));
221 return FALSE;
222 }
223 return TRUE;
224}
225
226/**
227 * is_rootfs_ok:
228 *
229 * @rootfs: specifies a path to a filesytem.
230 *
231 * This function checks if the @rootfs exists, if its on based on a different
232 * device/filesystem than that of the "/" and also if its a directory.
233 *
234 * Returns: TRUE if @rootfs is on a different filesystem than /. Else returns
235 * FALSE.
236 **/
237static int
238is_rootfs_ok (const char * rootfs)
239{
240 int ret = 0;
241 struct stat rst, cst;
242
243 nih_assert (rootfs != NULL);
244 /* Make sure the requested rootfs is not the same filesystem
245 as the current("/") root filesystem */
246 ret = stat ("/", &rst);
247 if (ret) {
248 if (errno == ENOMEM)
249 nih_error_raise_no_memory ();
250 else
251 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
252 _("Could not stat /"));
253 return FALSE;
254 }
255 ret = stat (rootfs, &cst);
256 if (ret) {
257 if (errno == ENOMEM)
258 nih_error_raise_no_memory ();
259 else
260 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
261 _("Could not stat requested rootfs:%s dir"),
262 rootfs);
263 return FALSE;
264 }
265 if (dev_match (rst.st_dev, cst.st_dev)) {
266 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
267 _("new rootfs: %s requested is not a different "
268 "filesystem than /"), rootfs);
269 return FALSE;
270 }
271 if (!S_ISDIR (cst.st_mode)) {
272 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
273 _("new rootfs: %s requested is not a directory"),
274 rootfs);
275 return FALSE;
276 }
277 return TRUE;
278}
279
280/**
281 * @is_init_ok:
282 *
283 * @init: process that shall be perhaps executed.
284 *
285 * This function checks if the requested @init exists and if so then checks
286 * if it is a regular file which could be executed. This is called before the
287 * execution of init is attempted.
288 *
289 * Returns: TRUE when @init is a regular file else returns FALSE
290 **/
291static int
292is_init_ok (const char * init)
293{
294 struct stat st;
295 int ret = 0;
296
297 nih_assert (init != NULL);
298 /* Check if the requested init exists */
299 ret = stat (init, &st);
300 if (ret) {
301 switch (errno) {
302 case ENOMEM:
303 nih_error_raise_no_memory ();
304 break;
305 default:
306 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
307 _("The requested init: %s may not be correct"),
308 init);
309 break;
310 }
311 ret = FALSE;
312 }
313 else if (!S_ISREG (st.st_mode)) {
314 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
315 _("The requested init: %s is not a regular "
316 "file"), init);
317 ret = FALSE;
318 } else {
319 if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH)) {
320 ret = TRUE;
321 } else {
322 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
323 _("The requested init: %s is not an "
324 "executable"), init);
325 }
326 }
327 return ret;
328}
329
330/*
331 * @get_init_args:
332 *
333 * @init: The init that will be executed by calling an execvp later.
334 *
335 * This function is called to get the command line arguments for executing
336 * @init. @init is the first argument of this command line array. The rest of
337 * the arguments are collected from PROC_CMDLINE which stores the arguments
338 * specified at boot time.
339 *
340 * Returns: the address of the array with the command line arguments on success.
341 * On failure returns NULL
342 */
343static char **
344get_init_args(const char * root, const char * init)
345{
346
347 char ** env = NULL;
348 FILE * cmdline = NULL;
349 char ** tokens = NULL;
350 int i=0;
351 char line[PAGESZ];
352
353 nih_assert (root != NULL);
354 nih_assert (init != NULL);
355
356 /* Create the argv for execv(). The first argument is the "init" you
357 * want to execute. The command line arguments to be passed to this
358 * init are copied from PROC_CMDLINE
359 */
360 env = nih_str_array_new (NULL);
361 if (!env)
362 goto error;
363 if (! nih_str_array_add (&env, NULL, NULL, init))
364 goto cleanup;
365 /* If the procfs is moved before this call then the /proc/cmdline will
366 * be found in @root/PROC_CMDLINE
367 */
368 cmdline = fopen (PROC_CMDLINE, "r");
369 if (!cmdline)
370 goto cleanup;
371 if (!fgets (line, sizeof line, cmdline))
372 goto cleanup;
373 tokens = nih_str_split (env, line, " ", 1);
374 if (!tokens)
375 goto cleanup;
376 for ( i=0 ; tokens [i] != NULL; i++) {
377 if ((tokens [i][0] == '-') && (tokens [i][1]='-')) {
378 /* argument to init */
379 if (!nih_str_array_add (&env, NULL, NULL, tokens[i]))
380 goto cleanup;
381 }
382 }
383 fclose (cmdline);
384 return env;
385cleanup:
386 if (cmdline)
387 fclose (cmdline);
388 nih_free (env);
389error:
390 switch (errno) {
391 case ENOMEM:
392 nih_error_raise_no_memory ();
393 break;
394 default:
395 nih_dbus_error_raise_printf (DBUS_ERROR_FAILED,
396 "Failed to open %s", PROC_CMDLINE);
397 break;
398 }
399 return NULL;
400}
401
402
403/*
404 * @move_mounts:
405 *
406 * @origin: virtual fs to be moved from "/"
407 * @rootfs: root filesystem where the @origin should be moved to.
408 *
409 * This function is intended to move the virtual filesystem @origin from "/"
410 * to the real @rootfs. This is a necessary step before we move root from "/"
411 * to the real @rootfs. This function should be called to move /dev, /sys and
412 * /proc to a corresponding mountpoint in @rootfs
413 *
414 * Returns: On success returns 0 and on failure returns -1
415 *
416 */
417static int
418move_mounts(const char * origin, const char * rootfs)
419{
420 char * path = NULL;
421 int ret = 0;
422
423 path = nih_strdup (NULL, rootfs);
424 if (path) {
425 if (origin[0] != '/')
426 path = nih_strcat (&path, NULL, "/");
427 if (path) {
428 path = nih_strcat (&path, NULL, origin);
429 /* Move the devfs to the new root filesystem */
430 if (path)
431 ret = mount (origin, path, NULL, MS_MOVE, NULL);
432 }
433 }
434 if (ret || !path) {
435 if (errno == ENOMEM)
436 nih_error_raise_no_memory ();
437 nih_dbus_error_raise_printf (DBUS_ERROR_FAILED,
438 _("Cannot move %s to %s"), origin, rootfs);
439 ret = -1;
440 }
441 if (path)
442 nih_free (path);
443 return ret;
444}
445
446/*
447 * send_reply:
448 * @message: Dbus connection and message received. We use this for sending a
449 * reply.
450 *
451 * This function is used to send a reply back to the initctl command before we
452 * execvp the requested init. We do not want to return to the middleware but
453 * instead execvp the requested init. By not returning to the middleware we
454 * need to ourself send a reply explicitly to initctl so that it can exit.
455 */
456static void
457send_reply (NihDBusMessage *message)
458{
459 DBusMessageIter iter;
460 DBusMessage * reply;
461
462 nih_assert (message != NULL);
463
464 do {
465 __label__ enomem;
466
467 /* Construct the reply message. */
468 reply = dbus_message_new_method_return (message->message);
469 if (! reply)
470 goto enomem;
471 dbus_message_iter_init_append (reply, &iter);
472 enomem: __attribute__ ((unused));
473 } while (! reply);
474 /* Send the reply, appending it to the outgoing queue. */
475 NIH_MUST (dbus_connection_send (message->connection, reply, NULL));
476 dbus_message_unref (reply);
477 return;
478}
479
480/**
481 * pivot_to_new_rootfs:
482 * @message: D-Bus connection and message received,
483 * @rootfs: dir to chroot to
484 * @init: new init to spawn on chrooting to rootfs
485 *
486 * Called to change the root filesystem to a requested @rootfs, after which the
487 * requested @init should be executed. This function changes the root
488 * filesystem only when "/" is on initramfs and the @rootfs is the real rootfs
489 * to be switched to. On changing the root filesystem as requested, this
490 * function releases memory by deleting the contents of the memory based
491 * initramfs before executing @init. If @rootfs or @init are not valid, the
492 * org.freedesktop.DBus.Error.InvalidArg error will be returned immediately.
493 * If this function fails before freeing the contents of the initramfs then
494 * the pivot_failed event is generated. If this function fails after the
495 * contents of the initramfs have been freed then failure handling is no more
496 * possible.
497 *
498 * Returns: does not return on success, negative value on raised error.
499 **/
500int
501pivot_to_new_rootfs (NihDBusMessage *message,
502 const char *rootfs,
503 const char *init)
504{
505 char ** env;
506 int ret = 0;
507
508 nih_assert (message != NULL);
509 nih_assert (rootfs != NULL);
510 nih_assert (init != NULL);
511
512 /* Verify that the rootfs dir name is valid */
513 if (! strlen (rootfs)) {
514 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
515 _("Rootfs dir name may not be empty string"));
516 pivot_emit_failed_event (NULL);
517 return -1;
518 }
519 /* Verify that the init name is valid */
520 if (! strlen (init)) {
521 nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS,
522 _("Name of init may not be empty string"));
523 pivot_emit_failed_event (NULL);
524 return -1;
525 }
526 /* Before you free up the initramfs memory by deleting files in the
527 * initramfs, make sure:
528 * 1. That the current root filesystem is memory based.
529 * 2. That you are trying to pivot to a different than the current filesystem.
530 */
531 if (!are_we_on_ramfs ()) {
532 pivot_emit_failed_event (NULL);
533 return -1;
534 }
535 /* Make sure the requested rootfs is not the same filesystem
536 as the current("/") root filesystem */
537 if (!is_rootfs_ok (rootfs)) {
538 pivot_emit_failed_event (NULL);
539 return -1;
540 }
541 /* Create the argv for execv(). The first argument is the "init" you
542 * want to execute. The command line arguments to be passed to this
543 * init are copied from /proc/cmdline.
544 */
545 env = get_init_args (rootfs, init);
546 if (!env) {
547 pivot_emit_failed_event (NULL);
548 return -1;
549 }
550 delete_conf_watches ();
551 /* Move the virtual filesystem to the new rootfs. This is needed for
552 * making @rootfs as the new root filesystem
553 */
554 /* 1. Move the sysfs to the new root filesystem */
555 if (move_mounts ("/sys", rootfs)) {
556 pivot_emit_failed_event (env);
557 nih_free (env);
558 return -1;
559 }
560 /* 2. Move the procfs to the new root filesystem */
561 if (move_mounts ("/proc", rootfs)) {
562 pivot_emit_failed_event (env);
563 nih_free (env);
564 return -1;
565 }
566
567 /* First, change to the new root directory */
568 ret = chdir (rootfs);
569 if (ret) {
570 nih_dbus_error_raise_printf (DBUS_ERROR_FAILED,
571 _("Cannot change to newly requested rootfs dir"));
572 pivot_emit_failed_event (env);
573 nih_free (env);
574 return -1;
575 }
576 /* Check if the requested init exists */
577 if (!is_init_ok (init)) {
578 ret = chdir ("/");
579 pivot_emit_failed_event (env);
580 nih_free (env);
581 return -1;
582 }
583 send_reply (message);
584 nih_signal_reset ();
585 /* After this point you cannot recover from a initramfs console */
586 /* Hopefully we are sure we are in the initramfs and so safe to free
587 * the memory now by freeing up the rambased filesystem's contents*/
588 del_dir ("/");
589 /* Overmount the root with the request root filesystem*/
590 ret = mount (".", "/", NULL, MS_MOVE, NULL);
591 if (ret) {
592 if(errno == ENOMEM) {
593 nih_error_raise_no_memory();
594 }
595 nih_fatal (_("Cannot mount the requested rootfs"));
596 exit (1);
597
598 }
599 nih_debug ("Mounted the new root filesystem ");
600 /* chroot, chdir to the new root filesystem*/
601 if (chroot (".")) {
602 nih_fatal (_("Could not chroot to the new requested root filesystem"));
603 exit (1);
604
605 }
606 if (chdir ("/")) {
607 nih_fatal (_("Could not chdir to the new requested root filesystem"));
608 exit (1);
609 }
610 /* Spawn init */
611 nih_debug ("About to execute new requested init: %s", init);
612 execvp (init, env);
613 nih_fatal (_("Could not execute the new init in the requested rootfs"));
614 exit (1);
615}
616
0617
=== added file 'init/pivot.h'
--- init/pivot.h 1970-01-01 00:00:00 +0000
+++ init/pivot.h 2011-07-15 17:51:29 +0000
@@ -0,0 +1,66 @@
1/* upstart
2 *
3 * pivot.h - Pivot command handling definitions
4 *
5 * Copyright © 2011 Canonical Ltd.
6 * Author: Surbhi A. Palande <surbhi.palande@ubuntu.com>.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2, as
10 * published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22
23#include <sys/mount.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <dirent.h>
27#include <sys/vfs.h>
28#include <unistd.h>
29#include <fcntl.h>
30#include <stdio.h>
31#include <string.h>
32#include <sys/types.h>
33#include <sys/wait.h>
34
35#include <nih/macros.h>
36#include <nih/alloc.h>
37#include <nih/string.h>
38#include <nih/main.h>
39#include <nih/logging.h>
40#include <nih/error.h>
41#include <nih/errors.h>
42#include <nih-dbus/dbus_error.h>
43
44#include <linux/magic.h>
45#include <linux/fs.h>
46
47#include "system.h"
48#include "paths.h"
49#include "events.h"
50
51/*
52 * This macro is used for checking if the major and minor numbers of two
53 * devices are the same.
54 *
55 * @devid1: is a dev_t type id of a device
56 * @devid2: is a dev_t type id of another device
57 *
58 * Returns TRUE if the device ids match, else FALSE
59 */
60#define dev_match(devid1, devid2) ((major (devid1) == major (devid2)) && (minor (devid1) == minor (devid2)))
61
62
63#define PAGESZ getpagesize()
64
65Event * pivot_emit_failed_event (char ** argv);
66int pivot_to_new_rootfs (NihDBusMessage *message, const char *rootfs, const char *init);
067
=== modified file 'init/tests/test_control.c'
--- init/tests/test_control.c 2011-06-06 17:05:11 +0000
+++ init/tests/test_control.c 2011-07-15 17:51:29 +0000
@@ -2,7 +2,7 @@
2 *2 *
3 * test_dbus.c - test suite for init/dbus.c3 * test_dbus.c - test suite for init/dbus.c
4 *4 *
5 * Copyright © 2010 Canonical Ltd.5 * Copyright © 2010-2011 Canonical Ltd.
6 * Author: Scott James Remnant <scott@netsplit.com>.6 * Author: Scott James Remnant <scott@netsplit.com>.
7 *7 *
8 * This program is free software; you can redistribute it and/or modify8 * This program is free software; you can redistribute it and/or modify
@@ -60,6 +60,7 @@
60#include "conf.h"60#include "conf.h"
61#include "control.h"61#include "control.h"
62#include "errors.h"62#include "errors.h"
63#include "events.h"
6364
6465
65extern const char *control_server_address;66extern const char *control_server_address;
@@ -2176,6 +2177,108 @@
2176 nih_log_priority = NIH_LOG_UNKNOWN;2177 nih_log_priority = NIH_LOG_UNKNOWN;
2177}2178}
21782179
2180void
2181test_pivot_root (void)
2182{
2183 NihDBusMessage *message = NULL;
2184 char *rootfs = NULL;
2185 char *init = NULL;
2186 NihError *err;
2187 NihDBusError *dbus_err;
2188 int ret = 0;
2189 JobClass *class = NULL;
2190 Job *job;
2191
2192 /* Check that the function returns the package string as a newly
2193 * allocated child of the message structure.
2194 */
2195 TEST_FUNCTION ("control_pivot_to_new_rootfs");
2196 nih_error_init ();
2197 job_class_init ();
2198
2199 TEST_ALLOC_FAIL {
2200 TEST_ALLOC_SAFE {
2201 message = nih_new (NULL, NihDBusMessage);
2202 message->connection = NULL;
2203 message->message = NULL;
2204
2205 /* Case 1: Invalid ROOTFS and Invalid INIT */
2206 rootfs = nih_strdup (NULL, "/tea");
2207 init = nih_strdup (NULL, "/biscuit");
2208 class = job_class_new (NULL, "test", NULL);
2209 class->task = TRUE;
2210 class->process[PROCESS_MAIN] = process_new (class->process);
2211 class->process[PROCESS_MAIN]->command = "echo";
2212 class->start_on = event_operator_new (
2213 class, EVENT_MATCH, PIVOT_FAILED_EVENT, NULL);
2214 nih_hash_add (job_classes, &class->entry);
2215 }
2216
2217
2218 ret = control_pivot_to_new_rootfs (NULL, message, rootfs,
2219 init);
2220 if (ret < 0) {
2221 TEST_EQ (ret, -1);
2222 err = nih_error_get ();
2223 TEST_ALLOC_SIZE (err, sizeof (NihDBusError));
2224
2225 TEST_EQ (err->number, NIH_DBUS_ERROR);
2226 dbus_err = (NihDBusError *)err;
2227 TEST_EQ_STR (dbus_err->name, DBUS_ERROR_INVALID_ARGS);
2228 nih_free (dbus_err);
2229
2230 }
2231
2232 event_poll();
2233 /* a pivot_failed event should be created by the dummy init
2234 * and dummy rootfs. We try to start a job on that*/
2235 TEST_ALLOC_SAFE {
2236 TEST_HASH_NOT_EMPTY (class->instances);
2237 job = (Job *)nih_hash_lookup (class->instances, "");
2238
2239 TEST_EQ (job->goal, JOB_START);
2240
2241 waitpid (job->pid[PROCESS_MAIN], NULL, 0);
2242 nih_free (rootfs);
2243 nih_free (init);
2244
2245 /* Case 2: valid ROOTFS and valid INIT. Rootfs not different
2246 * than current FS */
2247 rootfs = nih_strdup (NULL, "/");
2248 init = nih_strdup (NULL, "/sbin/init");
2249 }
2250
2251 ret = control_pivot_to_new_rootfs (NULL, message, rootfs,
2252 init);
2253 if (ret < 0) {
2254 TEST_EQ (ret, -1);
2255 err = nih_error_get ();
2256 TEST_ALLOC_SIZE (err, sizeof (NihDBusError));
2257
2258 TEST_EQ (err->number, NIH_DBUS_ERROR);
2259 dbus_err = (NihDBusError *)err;
2260 TEST_EQ_STR (dbus_err->name, DBUS_ERROR_INVALID_ARGS);
2261 nih_free (dbus_err);
2262
2263 }
2264
2265 event_poll();
2266 /* a pivot_failed event should be created by the dummy init
2267 * and dummy rootfs. We try to start a job on that*/
2268 TEST_ALLOC_SAFE {
2269 TEST_HASH_NOT_EMPTY (class->instances);
2270 job = (Job *)nih_hash_lookup (class->instances, "");
2271
2272 TEST_EQ (job->goal, JOB_START);
2273
2274 waitpid (job->pid[PROCESS_MAIN], NULL, 0);
2275 nih_free (rootfs);
2276 nih_free (init);
2277 nih_free (class);
2278 }
2279 nih_free (message);
2280 }
2281}
21792282
2180int2283int
2181main (int argc,2284main (int argc,
@@ -2205,5 +2308,7 @@
2205 test_get_log_priority ();2308 test_get_log_priority ();
2206 test_set_log_priority ();2309 test_set_log_priority ();
22072310
2311 test_pivot_root();
2312
2208 return 0;2313 return 0;
2209}2314}
22102315
=== modified file 'util/initctl.c'
--- util/initctl.c 2011-06-03 09:37:25 +0000
+++ util/initctl.c 2011-07-15 17:51:29 +0000
@@ -1,6 +1,6 @@
1/* upstart1/* upstart
2 *2 *
3 * Copyright © 2010 Canonical Ltd.3 * Copyright © 2010-2011 Canonical Ltd.
4 * Author: Scott James Remnant <scott@netsplit.com>.4 * Author: Scott James Remnant <scott@netsplit.com>.
5 *5 *
6 * This program is free software; you can redistribute it and/or modify6 * This program is free software; you can redistribute it and/or modify
@@ -121,6 +121,7 @@
121int log_priority_action (NihCommand *command, char * const *args);121int log_priority_action (NihCommand *command, char * const *args);
122int show_config_action (NihCommand *command, char * const *args);122int show_config_action (NihCommand *command, char * const *args);
123int check_config_action (NihCommand *command, char * const *args);123int check_config_action (NihCommand *command, char * const *args);
124int pivot_action (NihCommand *command, char * const *args);
124125
125126
126/**127/**
@@ -1202,6 +1203,54 @@
1202}1203}
12031204
1204/**1205/**
1206 * pivot_action:
1207 * @command: NihCommand invoked,
1208 * @args: command-line arguments.
1209 *
1210 * This function is called for the "pivot" command.
1211 *
1212 * Returns: 0 on success and 1 on error
1213 **/
1214int
1215pivot_action (NihCommand * command,
1216 char * const *args)
1217{
1218 nih_local NihDBusProxy *upstart = NULL;
1219 int ret = 1;
1220 NihError * err;
1221
1222 nih_assert (command != NULL);
1223 nih_assert (args != NULL);
1224
1225 if (!args[0]) {
1226 fprintf (stderr, _("%s: missing rootfs \n"), program_name);
1227 nih_main_suggest_help ();
1228 return 1;
1229 }
1230 nih_debug("rootfs: %s", args[0]);
1231 if (!args[1]) {
1232 fprintf (stderr, _("%s: missing init \n"), program_name);
1233 nih_main_suggest_help ();
1234 return 1;
1235 }
1236 nih_debug("init: %s", args[1]);
1237
1238 upstart = upstart_open (NULL);
1239 if (! upstart)
1240 return 1;
1241
1242 ret = upstart_pivot_to_new_rootfs_sync (NULL, upstart, args[0],
1243 args[1]);
1244 if (ret < 0) {
1245 err = nih_error_get ();
1246 nih_error ("Error: %s", err->message);
1247 nih_free (err);
1248 ret = 1;
1249 }
1250 return ret;
1251}
1252
1253/**
1205 * show_config_action:1254 * show_config_action:
1206 * @command: NihCommand invoked,1255 * @command: NihCommand invoked,
1207 * @args: command-line arguments.1256 * @args: command-line arguments.
@@ -2297,6 +2346,15 @@
2297};2346};
22982347
2299/**2348/**
2349 * pivot_options:
2350 *
2351 * Command-line options accepted for the pivot command.
2352 **/
2353NihOption pivot_options[] = {
2354 NIH_OPTION_LAST
2355};
2356
2357/**
2300 * reload_configuration_options:2358 * reload_configuration_options:
2301 *2359 *
2302 * Command-line options accepted for the reload-configuration command.2360 * Command-line options accepted for the reload-configuration command.
@@ -2365,6 +2423,14 @@
2365static NihCommandGroup event_commands = { N_("Event") };2423static NihCommandGroup event_commands = { N_("Event") };
23662424
2367/**2425/**
2426 * pivot_group:
2427 *
2428 * Group of commands related to new rootfs and new init.
2429 **/
2430static NihCommandGroup pivot_commands = { N_("Rootfs") };
2431
2432
2433/**
2368 * commands:2434 * commands:
2369 *2435 *
2370 * Commands accepts as the first non-option argument, or program name.2436 * Commands accepts as the first non-option argument, or program name.
@@ -2430,6 +2496,14 @@
2430 "to be included in the event.\n"),2496 "to be included in the event.\n"),
2431 &event_commands, emit_options, emit_action },2497 &event_commands, emit_options, emit_action },
24322498
2499 { "pivot", N_("ROOTFS INIT"),
2500 N_("Execute a new init process after changing from a ram based root"
2501 " filesystem to a new root filesystem" ),
2502 N_("ROOTFS is the path of the new root filestem to be changed to"
2503 "INIT is the new init process in the new root filesystem that should be "
2504 "spawned after successfully changing the root filesystem to ROOTFS \n"),
2505 &pivot_commands, pivot_options, pivot_action },
2506
2433 { "reload-configuration", NULL,2507 { "reload-configuration", NULL,
2434 N_("Reload the configuration of the init daemon."),2508 N_("Reload the configuration of the init daemon."),
2435 NULL,2509 NULL,

Subscribers

People subscribed via source and target branches