Merge lp:~csurbhi/upstart/upstart-add-pivot-handling into lp:upstart
- upstart-add-pivot-handling
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Scott James Remnant | Pending | ||
Review via email: mp+64723@code.launchpad.net |
Commit message
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!
- 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
1 | === modified file 'dbus/com.ubuntu.Upstart.xml' | |||
2 | --- dbus/com.ubuntu.Upstart.xml 2010-12-10 07:18:34 +0000 | |||
3 | +++ dbus/com.ubuntu.Upstart.xml 2011-07-15 17:51:29 +0000 | |||
4 | @@ -3,7 +3,7 @@ | |||
5 | 3 | 3 | ||
6 | 4 | com.ubuntu.Upstart.xml - interface definition for manager object | 4 | com.ubuntu.Upstart.xml - interface definition for manager object |
7 | 5 | 5 | ||
9 | 6 | Copyright © 2009 Canonical Ltd. | 6 | Copyright © 2009-2011 Canonical Ltd. |
10 | 7 | Author: Scott James Remnant <scott@netsplit.com>. | 7 | Author: Scott James Remnant <scott@netsplit.com>. |
11 | 8 | 8 | ||
12 | 9 | This file is free software; Canonical Ltd gives unlimited permission | 9 | This file is free software; Canonical Ltd gives unlimited permission |
13 | @@ -57,6 +57,12 @@ | |||
14 | 57 | <arg name="file" type="h" direction="in" /> | 57 | <arg name="file" type="h" direction="in" /> |
15 | 58 | </method> | 58 | </method> |
16 | 59 | 59 | ||
17 | 60 | <!-- Pivot to new rootfs and execute new init --> | ||
18 | 61 | <method name="PivotToNewRootfs"> | ||
19 | 62 | <arg name="rootfs" type="s" direction="in" /> | ||
20 | 63 | <arg name="init" type="s" direction="in" /> | ||
21 | 64 | </method> | ||
22 | 65 | |||
23 | 60 | <!-- Basic information about Upstart --> | 66 | <!-- Basic information about Upstart --> |
24 | 61 | <property name="version" type="s" access="read" /> | 67 | <property name="version" type="s" access="read" /> |
25 | 62 | <property name="log_priority" type="s" access="readwrite" /> | 68 | <property name="log_priority" type="s" access="readwrite" /> |
26 | 63 | 69 | ||
27 | === modified file 'init/Makefile.am' | |||
28 | --- init/Makefile.am 2011-05-15 12:53:17 +0000 | |||
29 | +++ init/Makefile.am 2011-07-15 17:51:29 +0000 | |||
30 | @@ -51,6 +51,7 @@ | |||
31 | 51 | parse_conf.c parse_conf.h \ | 51 | parse_conf.c parse_conf.h \ |
32 | 52 | conf.c conf.h \ | 52 | conf.c conf.h \ |
33 | 53 | control.c control.h \ | 53 | control.c control.h \ |
34 | 54 | pivot.c pivot.h \ | ||
35 | 54 | errors.h | 55 | errors.h |
36 | 55 | nodist_init_SOURCES = \ | 56 | nodist_init_SOURCES = \ |
37 | 56 | $(com_ubuntu_Upstart_OUTPUTS) \ | 57 | $(com_ubuntu_Upstart_OUTPUTS) \ |
38 | @@ -159,7 +160,7 @@ | |||
39 | 159 | system.o environ.o process.o \ | 160 | system.o environ.o process.o \ |
40 | 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 \ |
41 | 161 | parse_job.o parse_conf.o conf.o control.o \ | 162 | parse_job.o parse_conf.o conf.o control.o \ |
43 | 162 | session.o \ | 163 | session.o pivot.o \ |
44 | 163 | com.ubuntu.Upstart.o \ | 164 | com.ubuntu.Upstart.o \ |
45 | 164 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ | 165 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
46 | 165 | $(NIH_LIBS) \ | 166 | $(NIH_LIBS) \ |
47 | @@ -171,7 +172,7 @@ | |||
48 | 171 | system.o environ.o process.o \ | 172 | system.o environ.o process.o \ |
49 | 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 \ |
50 | 173 | parse_job.o parse_conf.o conf.o control.o \ | 174 | parse_job.o parse_conf.o conf.o control.o \ |
52 | 174 | session.o \ | 175 | session.o pivot.o \ |
53 | 175 | com.ubuntu.Upstart.o \ | 176 | com.ubuntu.Upstart.o \ |
54 | 176 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ | 177 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
55 | 177 | $(NIH_LIBS) \ | 178 | $(NIH_LIBS) \ |
56 | @@ -183,7 +184,7 @@ | |||
57 | 183 | system.o environ.o process.o \ | 184 | system.o environ.o process.o \ |
58 | 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 \ |
59 | 185 | parse_job.o parse_conf.o conf.o control.o \ | 186 | parse_job.o parse_conf.o conf.o control.o \ |
61 | 186 | session.o \ | 187 | session.o pivot.o \ |
62 | 187 | com.ubuntu.Upstart.o \ | 188 | com.ubuntu.Upstart.o \ |
63 | 188 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ | 189 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
64 | 189 | $(NIH_LIBS) \ | 190 | $(NIH_LIBS) \ |
65 | @@ -195,7 +196,7 @@ | |||
66 | 195 | system.o environ.o process.o \ | 196 | system.o environ.o process.o \ |
67 | 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 \ |
68 | 197 | parse_job.o parse_conf.o conf.o control.o \ | 198 | parse_job.o parse_conf.o conf.o control.o \ |
70 | 198 | session.o \ | 199 | session.o pivot.o \ |
71 | 199 | com.ubuntu.Upstart.o \ | 200 | com.ubuntu.Upstart.o \ |
72 | 200 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ | 201 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
73 | 201 | $(NIH_LIBS) \ | 202 | $(NIH_LIBS) \ |
74 | @@ -207,7 +208,7 @@ | |||
75 | 207 | system.o environ.o process.o \ | 208 | system.o environ.o process.o \ |
76 | 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 \ |
77 | 209 | parse_job.o parse_conf.o conf.o control.o \ | 210 | parse_job.o parse_conf.o conf.o control.o \ |
79 | 210 | session.o \ | 211 | session.o pivot.o \ |
80 | 211 | com.ubuntu.Upstart.o \ | 212 | com.ubuntu.Upstart.o \ |
81 | 212 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ | 213 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
82 | 213 | $(NIH_LIBS) \ | 214 | $(NIH_LIBS) \ |
83 | @@ -219,7 +220,7 @@ | |||
84 | 219 | system.o environ.o process.o \ | 220 | system.o environ.o process.o \ |
85 | 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 \ |
86 | 221 | parse_job.o parse_conf.o conf.o control.o \ | 222 | parse_job.o parse_conf.o conf.o control.o \ |
88 | 222 | session.o \ | 223 | session.o pivot.o \ |
89 | 223 | com.ubuntu.Upstart.o \ | 224 | com.ubuntu.Upstart.o \ |
90 | 224 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ | 225 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
91 | 225 | $(NIH_LIBS) \ | 226 | $(NIH_LIBS) \ |
92 | @@ -231,7 +232,7 @@ | |||
93 | 231 | system.o environ.o process.o \ | 232 | system.o environ.o process.o \ |
94 | 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 \ |
95 | 233 | parse_job.o parse_conf.o conf.o control.o \ | 234 | parse_job.o parse_conf.o conf.o control.o \ |
97 | 234 | session.o \ | 235 | session.o pivot.o \ |
98 | 235 | com.ubuntu.Upstart.o \ | 236 | com.ubuntu.Upstart.o \ |
99 | 236 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ | 237 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
100 | 237 | $(NIH_LIBS) \ | 238 | $(NIH_LIBS) \ |
101 | @@ -243,7 +244,7 @@ | |||
102 | 243 | system.o environ.o process.o \ | 244 | system.o environ.o process.o \ |
103 | 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 \ |
104 | 245 | parse_job.o parse_conf.o conf.o control.o \ | 246 | parse_job.o parse_conf.o conf.o control.o \ |
106 | 246 | session.o \ | 247 | session.o pivot.o \ |
107 | 247 | com.ubuntu.Upstart.o \ | 248 | com.ubuntu.Upstart.o \ |
108 | 248 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ | 249 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
109 | 249 | $(NIH_LIBS) \ | 250 | $(NIH_LIBS) \ |
110 | @@ -255,7 +256,7 @@ | |||
111 | 255 | system.o environ.o process.o \ | 256 | system.o environ.o process.o \ |
112 | 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 \ |
113 | 257 | parse_job.o parse_conf.o conf.o control.o \ | 258 | parse_job.o parse_conf.o conf.o control.o \ |
115 | 258 | session.o \ | 259 | session.o pivot.o \ |
116 | 259 | com.ubuntu.Upstart.o \ | 260 | com.ubuntu.Upstart.o \ |
117 | 260 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ | 261 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
118 | 261 | $(NIH_LIBS) \ | 262 | $(NIH_LIBS) \ |
119 | @@ -267,7 +268,7 @@ | |||
120 | 267 | system.o environ.o process.o \ | 268 | system.o environ.o process.o \ |
121 | 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 \ |
122 | 269 | parse_job.o parse_conf.o conf.o control.o \ | 270 | parse_job.o parse_conf.o conf.o control.o \ |
124 | 270 | session.o \ | 271 | session.o pivot.o \ |
125 | 271 | com.ubuntu.Upstart.o \ | 272 | com.ubuntu.Upstart.o \ |
126 | 272 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ | 273 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
127 | 273 | $(NIH_LIBS) \ | 274 | $(NIH_LIBS) \ |
128 | @@ -279,7 +280,7 @@ | |||
129 | 279 | system.o environ.o process.o \ | 280 | system.o environ.o process.o \ |
130 | 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 \ |
131 | 281 | parse_job.o parse_conf.o conf.o control.o \ | 282 | parse_job.o parse_conf.o conf.o control.o \ |
133 | 282 | session.o \ | 283 | session.o pivot.o \ |
134 | 283 | com.ubuntu.Upstart.o \ | 284 | com.ubuntu.Upstart.o \ |
135 | 284 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ | 285 | com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \ |
136 | 285 | $(NIH_LIBS) \ | 286 | $(NIH_LIBS) \ |
137 | 286 | 287 | ||
138 | === modified file 'init/conf.c' | |||
139 | --- init/conf.c 2011-06-06 17:05:11 +0000 | |||
140 | +++ init/conf.c 2011-07-15 17:51:29 +0000 | |||
141 | @@ -1186,6 +1186,41 @@ | |||
142 | 1186 | return NULL; | 1186 | return NULL; |
143 | 1187 | } | 1187 | } |
144 | 1188 | 1188 | ||
145 | 1189 | /* | ||
146 | 1190 | * delete_conf_watches: | ||
147 | 1191 | * | ||
148 | 1192 | * This function is called to delete the notification handlers registered | ||
149 | 1193 | * against the configuration directories/files. | ||
150 | 1194 | */ | ||
151 | 1195 | void delete_conf_watches () | ||
152 | 1196 | { | ||
153 | 1197 | NihList * watches; | ||
154 | 1198 | NihWatch * watch; | ||
155 | 1199 | NihWatchHandle *handle; | ||
156 | 1200 | NIH_LIST_FOREACH (conf_sources, iter) { | ||
157 | 1201 | ConfSource *source = (ConfSource *) iter; | ||
158 | 1202 | if (! source) | ||
159 | 1203 | return; | ||
160 | 1204 | if(source->path) { | ||
161 | 1205 | nih_debug ("freeing source for path: %s", source->path); | ||
162 | 1206 | } | ||
163 | 1207 | /* remove the notification watches */ | ||
164 | 1208 | watch = source->watch; | ||
165 | 1209 | if (watch) { | ||
166 | 1210 | watches = & (watch->watches); | ||
167 | 1211 | if (watches) { | ||
168 | 1212 | NIH_LIST_FOREACH (watches, wh) { | ||
169 | 1213 | handle = (NihWatchHandle *)wh; | ||
170 | 1214 | inotify_rm_watch (watch->fd, handle->wd); | ||
171 | 1215 | } | ||
172 | 1216 | } | ||
173 | 1217 | close (watch->fd); | ||
174 | 1218 | nih_free (source); | ||
175 | 1219 | } | ||
176 | 1220 | } | ||
177 | 1221 | } | ||
178 | 1222 | |||
179 | 1223 | |||
180 | 1189 | #ifdef DEBUG | 1224 | #ifdef DEBUG |
181 | 1190 | 1225 | ||
182 | 1191 | size_t | 1226 | size_t |
183 | 1192 | 1227 | ||
184 | === modified file 'init/conf.h' | |||
185 | --- init/conf.h 2011-06-06 12:52:08 +0000 | |||
186 | +++ init/conf.h 2011-07-15 17:51:29 +0000 | |||
187 | @@ -129,6 +129,7 @@ | |||
188 | 129 | 129 | ||
189 | 130 | char *toggle_conf_name (const void *parent, const char *path) | 130 | char *toggle_conf_name (const void *parent, const char *path) |
190 | 131 | __attribute__ ((warn_unused_result, malloc)); | 131 | __attribute__ ((warn_unused_result, malloc)); |
191 | 132 | void delete_conf_watches (void); | ||
192 | 132 | 133 | ||
193 | 133 | #ifdef DEBUG | 134 | #ifdef DEBUG |
194 | 134 | 135 | ||
195 | 135 | 136 | ||
196 | === modified file 'init/control.c' | |||
197 | --- init/control.c 2011-06-15 13:20:41 +0000 | |||
198 | +++ init/control.c 2011-07-15 17:51:29 +0000 | |||
199 | @@ -54,6 +54,7 @@ | |||
200 | 54 | #include "conf.h" | 54 | #include "conf.h" |
201 | 55 | #include "control.h" | 55 | #include "control.h" |
202 | 56 | #include "errors.h" | 56 | #include "errors.h" |
203 | 57 | #include "pivot.h" | ||
204 | 57 | 58 | ||
205 | 58 | #include "com.ubuntu.Upstart.h" | 59 | #include "com.ubuntu.Upstart.h" |
206 | 59 | 60 | ||
207 | @@ -613,6 +614,40 @@ | |||
208 | 613 | return 0; | 614 | return 0; |
209 | 614 | } | 615 | } |
210 | 615 | 616 | ||
211 | 617 | /** | ||
212 | 618 | * control_pivot_to_new_rootfs: | ||
213 | 619 | * @data: not used, | ||
214 | 620 | * @message: D-Bus connection and message received, | ||
215 | 621 | * @rootfs: dir to chroot to | ||
216 | 622 | * @init: new init to spawn on chrooting to rootfs | ||
217 | 623 | * This shall be filled in by pivot_to_new_rootfs () | ||
218 | 624 | * | ||
219 | 625 | * Called to change the root filesystem to a requested @rootfs, after which the | ||
220 | 626 | * requested @init should be executed. This function changes the root | ||
221 | 627 | * filesystem only when "/" is on initramfs and the @rootfs is the real rootfs | ||
222 | 628 | * to be switched to. On changing the root filesystem as requested, this | ||
223 | 629 | * function releases memory by deleting the contents of the memory based | ||
224 | 630 | * initramfs before executing @init. If @rootfs or @init are not valid, the | ||
225 | 631 | * org.freedesktop.DBus.Error.InvalidArg error will be returned immediately. | ||
226 | 632 | * If this function fails before freeing the contents of the initramfs then | ||
227 | 633 | * the pivot_failed event is generated. If this function fails after the | ||
228 | 634 | * contents of the initramfs have been freed then failure handling is no more | ||
229 | 635 | * possible. | ||
230 | 636 | * | ||
231 | 637 | * Returns: does not return on success, negative value on raised error. | ||
232 | 638 | **/ | ||
233 | 639 | int | ||
234 | 640 | control_pivot_to_new_rootfs (void *data, | ||
235 | 641 | NihDBusMessage *message, | ||
236 | 642 | const char *rootfs, | ||
237 | 643 | const char *init) | ||
238 | 644 | { | ||
239 | 645 | nih_assert (message != NULL); | ||
240 | 646 | nih_assert (rootfs != NULL); | ||
241 | 647 | nih_assert (init != NULL); | ||
242 | 648 | |||
243 | 649 | return pivot_to_new_rootfs (message, rootfs, init); | ||
244 | 650 | } | ||
245 | 616 | 651 | ||
246 | 617 | /** | 652 | /** |
247 | 618 | * control_get_version: | 653 | * control_get_version: |
248 | 619 | 654 | ||
249 | === modified file 'init/control.h' | |||
250 | --- init/control.h 2011-06-06 17:05:11 +0000 | |||
251 | +++ init/control.h 2011-07-15 17:51:29 +0000 | |||
252 | @@ -72,6 +72,9 @@ | |||
253 | 72 | const char *name, char * const *env, | 72 | const char *name, char * const *env, |
254 | 73 | int wait) | 73 | int wait) |
255 | 74 | __attribute__ ((warn_unused_result)); | 74 | __attribute__ ((warn_unused_result)); |
256 | 75 | int control_pivot_to_new_rootfs (void *data, NihDBusMessage *message, | ||
257 | 76 | const char *rootfs, const char *init) | ||
258 | 77 | __attribute__ ((warn_unused_result)); | ||
259 | 75 | int control_emit_event_with_file (void *data, NihDBusMessage *message, | 78 | int control_emit_event_with_file (void *data, NihDBusMessage *message, |
260 | 76 | const char *name, char * const *env, | 79 | const char *name, char * const *env, |
261 | 77 | int wait, int file) | 80 | int wait, int file) |
262 | 78 | 81 | ||
263 | === modified file 'init/events.h' | |||
264 | --- init/events.h 2009-06-23 09:29:35 +0000 | |||
265 | +++ init/events.h 2011-07-15 17:51:29 +0000 | |||
266 | @@ -1,6 +1,6 @@ | |||
267 | 1 | /* upstart | 1 | /* upstart |
268 | 2 | * | 2 | * |
270 | 3 | * Copyright © 2009 Canonical Ltd. | 3 | * Copyright © 2009-2011 Canonical Ltd. |
271 | 4 | * Author: Scott James Remnant <scott@netsplit.com>. | 4 | * Author: Scott James Remnant <scott@netsplit.com>. |
272 | 5 | * | 5 | * |
273 | 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
274 | @@ -93,5 +93,12 @@ | |||
275 | 93 | **/ | 93 | **/ |
276 | 94 | #define JOB_STOPPED_EVENT "stopped" | 94 | #define JOB_STOPPED_EVENT "stopped" |
277 | 95 | 95 | ||
278 | 96 | /** | ||
279 | 97 | * PIVOT_FAILED_EVENT: | ||
280 | 98 | * | ||
281 | 99 | * Name of the event we generate once the pivot event fails to change the | ||
282 | 100 | * root filesystem. | ||
283 | 101 | **/ | ||
284 | 102 | #define PIVOT_FAILED_EVENT "pivot-failed" | ||
285 | 96 | 103 | ||
286 | 97 | #endif /* INIT_EVENTS_H */ | 104 | #endif /* INIT_EVENTS_H */ |
287 | 98 | 105 | ||
288 | === modified file 'init/paths.h' | |||
289 | --- init/paths.h 2011-06-06 12:52:08 +0000 | |||
290 | +++ init/paths.h 2011-07-15 17:51:29 +0000 | |||
291 | @@ -177,4 +177,12 @@ | |||
292 | 177 | (IS_CONF_EXT_STD(period) || \ | 177 | (IS_CONF_EXT_STD(period) || \ |
293 | 178 | IS_CONF_EXT_OVERRIDE(period)) | 178 | IS_CONF_EXT_OVERRIDE(period)) |
294 | 179 | 179 | ||
295 | 180 | /** | ||
296 | 181 | * Kernel command line arguments path | ||
297 | 182 | * | ||
298 | 183 | * This file stores the kernel command line arguments which are read for | ||
299 | 184 | * executing a new requested init using the pivot command from initramfs. | ||
300 | 185 | **/ | ||
301 | 186 | #define PROC_CMDLINE "/proc/cmdline" | ||
302 | 187 | |||
303 | 180 | #endif /* INIT_PATHS_H */ | 188 | #endif /* INIT_PATHS_H */ |
304 | 181 | 189 | ||
305 | === added file 'init/pivot.c' | |||
306 | --- init/pivot.c 1970-01-01 00:00:00 +0000 | |||
307 | +++ init/pivot.c 2011-07-15 17:51:29 +0000 | |||
308 | @@ -0,0 +1,616 @@ | |||
309 | 1 | /* upstart | ||
310 | 2 | * | ||
311 | 3 | * pivot.c - Pivot command handling | ||
312 | 4 | * | ||
313 | 5 | * Copyright © 2011 Canonical Ltd. | ||
314 | 6 | * Author: Surbhi A. Palande <surbhi.palande@ubuntu.com>. | ||
315 | 7 | * | ||
316 | 8 | * This program is free software; you can redistribute it and/or modify | ||
317 | 9 | * it under the terms of the GNU General Public License version 2, as | ||
318 | 10 | * published by the Free Software Foundation. | ||
319 | 11 | * | ||
320 | 12 | * This program is distributed in the hope that it will be useful, | ||
321 | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
322 | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
323 | 15 | * GNU General Public License for more details. | ||
324 | 16 | * | ||
325 | 17 | * You should have received a copy of the GNU General Public License along | ||
326 | 18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
327 | 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
328 | 20 | */ | ||
329 | 21 | |||
330 | 22 | #include "pivot.h" | ||
331 | 23 | #include "conf.h" | ||
332 | 24 | |||
333 | 25 | /* | ||
334 | 26 | * @get_complete_path: | ||
335 | 27 | * | ||
336 | 28 | * @dirname: absolute path of the parent directory. | ||
337 | 29 | * @dirent_name: name of the directory entry whose full path is constructed by | ||
338 | 30 | * using the parent directories absolute path i.e @dirname | ||
339 | 31 | * | ||
340 | 32 | * This function is called for getting an absolute path of a directory entry given | ||
341 | 33 | * the parent directories absolute path. | ||
342 | 34 | * | ||
343 | 35 | * Returns: the absolute path on success. On failure returns NULL. | ||
344 | 36 | */ | ||
345 | 37 | static char * | ||
346 | 38 | get_complete_path (const char * dirname, const char * dirent_name) | ||
347 | 39 | { | ||
348 | 40 | char * full_path = NULL; | ||
349 | 41 | |||
350 | 42 | nih_assert (dirname != NULL); | ||
351 | 43 | nih_assert (dirent_name != NULL); | ||
352 | 44 | |||
353 | 45 | full_path = nih_strdup (NULL, dirname); | ||
354 | 46 | if (full_path) { | ||
355 | 47 | if (dirname [strlen(dirname) - 1] != '/') { | ||
356 | 48 | full_path = nih_strcat (&full_path, NULL, "/"); | ||
357 | 49 | } | ||
358 | 50 | if (full_path) | ||
359 | 51 | full_path = nih_strcat (&full_path, NULL, dirent_name); | ||
360 | 52 | } | ||
361 | 53 | return full_path; | ||
362 | 54 | } | ||
363 | 55 | |||
364 | 56 | /* | ||
365 | 57 | * @del_dir: | ||
366 | 58 | * | ||
367 | 59 | * @dirname: directory whose contents need to be deleted. | ||
368 | 60 | * | ||
369 | 61 | * This function is called to free the contents of memory by deleting the | ||
370 | 62 | * memory based members of @dirname. It does not delete the contents of a | ||
371 | 63 | * member directory in case it is a mount point for other file systems which | ||
372 | 64 | * are not memory based. This function assumes that "/" is a memory based | ||
373 | 65 | * filesystem and uses this information to find out whether the underlying | ||
374 | 66 | * device of a member directory is the same as that of "/" or not. | ||
375 | 67 | * | ||
376 | 68 | * | ||
377 | 69 | * Returns: On success returns 0 while on failure it raises the | ||
378 | 70 | * org.freedesktop.DBus.Error.InvalidArg error and exits out of upstart as | ||
379 | 71 | * recovery of a pivot command is not possible. | ||
380 | 72 | */ | ||
381 | 73 | static int | ||
382 | 74 | del_dir (const char * dirname) | ||
383 | 75 | { | ||
384 | 76 | struct dirent * dirent; | ||
385 | 77 | struct stat rst, cst; | ||
386 | 78 | DIR * dirp; | ||
387 | 79 | char * path = NULL; | ||
388 | 80 | int ret = 0; | ||
389 | 81 | |||
390 | 82 | nih_assert (dirname != NULL); | ||
391 | 83 | |||
392 | 84 | ret = stat ("/", &rst); | ||
393 | 85 | if (ret) { | ||
394 | 86 | nih_debug ("Could not stat /"); | ||
395 | 87 | goto error; | ||
396 | 88 | } | ||
397 | 89 | dirp = opendir (dirname); | ||
398 | 90 | if (!dirp) { | ||
399 | 91 | ret = -1; | ||
400 | 92 | goto error; | ||
401 | 93 | } | ||
402 | 94 | while ((dirent = readdir (dirp)) != NULL) { | ||
403 | 95 | if (!strcmp (dirent->d_name, ".") || | ||
404 | 96 | (!strcmp (dirent->d_name, ".."))) { | ||
405 | 97 | continue; | ||
406 | 98 | } | ||
407 | 99 | path = get_complete_path (dirname, dirent->d_name); | ||
408 | 100 | if (!path) { | ||
409 | 101 | ret = -1; | ||
410 | 102 | goto cleanup; | ||
411 | 103 | } | ||
412 | 104 | switch (dirent->d_type) { | ||
413 | 105 | case DT_DIR: | ||
414 | 106 | ret = stat (path, &cst); | ||
415 | 107 | /* Free the contents of only the memory based | ||
416 | 108 | * file systems but not of any other mounted | ||
417 | 109 | * file systems if any. | ||
418 | 110 | */ | ||
419 | 111 | if (!ret && dev_match (rst.st_dev, cst.st_dev)) { | ||
420 | 112 | ret = del_dir (path); | ||
421 | 113 | if (!ret) { | ||
422 | 114 | nih_debug ("Removing dir: %s", path); | ||
423 | 115 | ret = rmdir (path); | ||
424 | 116 | } | ||
425 | 117 | } | ||
426 | 118 | break; | ||
427 | 119 | default: | ||
428 | 120 | nih_debug ("Removing file: %s", path); | ||
429 | 121 | ret = unlink (path); | ||
430 | 122 | break; | ||
431 | 123 | } | ||
432 | 124 | nih_free (path); | ||
433 | 125 | if (ret) | ||
434 | 126 | break; | ||
435 | 127 | } | ||
436 | 128 | cleanup: | ||
437 | 129 | closedir (dirp); | ||
438 | 130 | error: | ||
439 | 131 | if (ret) { | ||
440 | 132 | nih_assert (errno != 0); | ||
441 | 133 | switch (errno) { | ||
442 | 134 | case ENOMEM: | ||
443 | 135 | nih_error_raise_no_memory (); | ||
444 | 136 | break; | ||
445 | 137 | default: | ||
446 | 138 | nih_error_raise (errno, strerror (errno)); | ||
447 | 139 | break; | ||
448 | 140 | } | ||
449 | 141 | nih_fatal (_("Could not delete the contents of initramfs: %s"), strerror (errno)); | ||
450 | 142 | exit (1); | ||
451 | 143 | } | ||
452 | 144 | return 0; | ||
453 | 145 | } | ||
454 | 146 | |||
455 | 147 | /** | ||
456 | 148 | * pivot_emit_failed_event: | ||
457 | 149 | * | ||
458 | 150 | * @argv: The arguments to be passed to the new requested init for execution. | ||
459 | 151 | * | ||
460 | 152 | * This function generates a new event "pivot_failed". It is used to indicate | ||
461 | 153 | * that the initcl pivot command failed to chroot to the new rootfs. | ||
462 | 154 | * | ||
463 | 155 | * Returns: on success returns the PIVOT_FAILED_EVENT and on failure returns | ||
464 | 156 | * NULL. | ||
465 | 157 | **/ | ||
466 | 158 | Event * | ||
467 | 159 | pivot_emit_failed_event (char ** argv) | ||
468 | 160 | { | ||
469 | 161 | Event *event; | ||
470 | 162 | |||
471 | 163 | event = NIH_MUST (event_new (NULL, PIVOT_FAILED_EVENT, argv)); | ||
472 | 164 | if (!event) { | ||
473 | 165 | nih_debug ("Could not emit %s", PIVOT_FAILED_EVENT); | ||
474 | 166 | nih_free (argv); | ||
475 | 167 | return NULL; | ||
476 | 168 | } | ||
477 | 169 | return event; | ||
478 | 170 | } | ||
479 | 171 | |||
480 | 172 | /** | ||
481 | 173 | * @are_we_on_ramfs(): | ||
482 | 174 | * | ||
483 | 175 | * This function is called to check if the current root filesystem is based on | ||
484 | 176 | * a memory based filesystem. | ||
485 | 177 | * | ||
486 | 178 | * Returns: TRUE if the root filesystem is memory based, else returns FALSE. | ||
487 | 179 | **/ | ||
488 | 180 | static int | ||
489 | 181 | are_we_on_ramfs () | ||
490 | 182 | { | ||
491 | 183 | int ret = 0; | ||
492 | 184 | struct stat st; | ||
493 | 185 | struct statfs sfs; | ||
494 | 186 | |||
495 | 187 | /* Make sure we're on a ramfs */ | ||
496 | 188 | /* 1. The initramfs should have /init */ | ||
497 | 189 | ret = stat ("/init", &st); | ||
498 | 190 | if (ret) { | ||
499 | 191 | if (errno == ENOMEM) | ||
500 | 192 | nih_error_raise_no_memory (); | ||
501 | 193 | else | ||
502 | 194 | nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, | ||
503 | 195 | _("/ may not be on initramfs")); | ||
504 | 196 | return FALSE; | ||
505 | 197 | } | ||
506 | 198 | if (!S_ISREG (st.st_mode)) { | ||
507 | 199 | nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, | ||
508 | 200 | _("/ may not be on initramfs")); | ||
509 | 201 | return FALSE; | ||
510 | 202 | } | ||
511 | 203 | /* Make sure that the statistics of / indicate that its a memory based | ||
512 | 204 | * filesystem and not a disk based one */ | ||
513 | 205 | ret = statfs ("/", &sfs); | ||
514 | 206 | if (ret) { | ||
515 | 207 | switch(errno) { | ||
516 | 208 | case ENOMEM: | ||
517 | 209 | nih_error_raise_no_memory (); | ||
518 | 210 | break; | ||
519 | 211 | default: | ||
520 | 212 | nih_dbus_error_raise_printf (DBUS_ERROR_FAILED, | ||
521 | 213 | _("Cannot verify if we are in the initramfs")); | ||
522 | 214 | break; | ||
523 | 215 | } | ||
524 | 216 | return FALSE; | ||
525 | 217 | } | ||
526 | 218 | if (sfs.f_type != (long) RAMFS_MAGIC && sfs.f_type != (long) TMPFS_MAGIC) { | ||
527 | 219 | nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, | ||
528 | 220 | _("/ is not a memory based filesystem")); | ||
529 | 221 | return FALSE; | ||
530 | 222 | } | ||
531 | 223 | return TRUE; | ||
532 | 224 | } | ||
533 | 225 | |||
534 | 226 | /** | ||
535 | 227 | * is_rootfs_ok: | ||
536 | 228 | * | ||
537 | 229 | * @rootfs: specifies a path to a filesytem. | ||
538 | 230 | * | ||
539 | 231 | * This function checks if the @rootfs exists, if its on based on a different | ||
540 | 232 | * device/filesystem than that of the "/" and also if its a directory. | ||
541 | 233 | * | ||
542 | 234 | * Returns: TRUE if @rootfs is on a different filesystem than /. Else returns | ||
543 | 235 | * FALSE. | ||
544 | 236 | **/ | ||
545 | 237 | static int | ||
546 | 238 | is_rootfs_ok (const char * rootfs) | ||
547 | 239 | { | ||
548 | 240 | int ret = 0; | ||
549 | 241 | struct stat rst, cst; | ||
550 | 242 | |||
551 | 243 | nih_assert (rootfs != NULL); | ||
552 | 244 | /* Make sure the requested rootfs is not the same filesystem | ||
553 | 245 | as the current("/") root filesystem */ | ||
554 | 246 | ret = stat ("/", &rst); | ||
555 | 247 | if (ret) { | ||
556 | 248 | if (errno == ENOMEM) | ||
557 | 249 | nih_error_raise_no_memory (); | ||
558 | 250 | else | ||
559 | 251 | nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, | ||
560 | 252 | _("Could not stat /")); | ||
561 | 253 | return FALSE; | ||
562 | 254 | } | ||
563 | 255 | ret = stat (rootfs, &cst); | ||
564 | 256 | if (ret) { | ||
565 | 257 | if (errno == ENOMEM) | ||
566 | 258 | nih_error_raise_no_memory (); | ||
567 | 259 | else | ||
568 | 260 | nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, | ||
569 | 261 | _("Could not stat requested rootfs:%s dir"), | ||
570 | 262 | rootfs); | ||
571 | 263 | return FALSE; | ||
572 | 264 | } | ||
573 | 265 | if (dev_match (rst.st_dev, cst.st_dev)) { | ||
574 | 266 | nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, | ||
575 | 267 | _("new rootfs: %s requested is not a different " | ||
576 | 268 | "filesystem than /"), rootfs); | ||
577 | 269 | return FALSE; | ||
578 | 270 | } | ||
579 | 271 | if (!S_ISDIR (cst.st_mode)) { | ||
580 | 272 | nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, | ||
581 | 273 | _("new rootfs: %s requested is not a directory"), | ||
582 | 274 | rootfs); | ||
583 | 275 | return FALSE; | ||
584 | 276 | } | ||
585 | 277 | return TRUE; | ||
586 | 278 | } | ||
587 | 279 | |||
588 | 280 | /** | ||
589 | 281 | * @is_init_ok: | ||
590 | 282 | * | ||
591 | 283 | * @init: process that shall be perhaps executed. | ||
592 | 284 | * | ||
593 | 285 | * This function checks if the requested @init exists and if so then checks | ||
594 | 286 | * if it is a regular file which could be executed. This is called before the | ||
595 | 287 | * execution of init is attempted. | ||
596 | 288 | * | ||
597 | 289 | * Returns: TRUE when @init is a regular file else returns FALSE | ||
598 | 290 | **/ | ||
599 | 291 | static int | ||
600 | 292 | is_init_ok (const char * init) | ||
601 | 293 | { | ||
602 | 294 | struct stat st; | ||
603 | 295 | int ret = 0; | ||
604 | 296 | |||
605 | 297 | nih_assert (init != NULL); | ||
606 | 298 | /* Check if the requested init exists */ | ||
607 | 299 | ret = stat (init, &st); | ||
608 | 300 | if (ret) { | ||
609 | 301 | switch (errno) { | ||
610 | 302 | case ENOMEM: | ||
611 | 303 | nih_error_raise_no_memory (); | ||
612 | 304 | break; | ||
613 | 305 | default: | ||
614 | 306 | nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, | ||
615 | 307 | _("The requested init: %s may not be correct"), | ||
616 | 308 | init); | ||
617 | 309 | break; | ||
618 | 310 | } | ||
619 | 311 | ret = FALSE; | ||
620 | 312 | } | ||
621 | 313 | else if (!S_ISREG (st.st_mode)) { | ||
622 | 314 | nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, | ||
623 | 315 | _("The requested init: %s is not a regular " | ||
624 | 316 | "file"), init); | ||
625 | 317 | ret = FALSE; | ||
626 | 318 | } else { | ||
627 | 319 | if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH)) { | ||
628 | 320 | ret = TRUE; | ||
629 | 321 | } else { | ||
630 | 322 | nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, | ||
631 | 323 | _("The requested init: %s is not an " | ||
632 | 324 | "executable"), init); | ||
633 | 325 | } | ||
634 | 326 | } | ||
635 | 327 | return ret; | ||
636 | 328 | } | ||
637 | 329 | |||
638 | 330 | /* | ||
639 | 331 | * @get_init_args: | ||
640 | 332 | * | ||
641 | 333 | * @init: The init that will be executed by calling an execvp later. | ||
642 | 334 | * | ||
643 | 335 | * This function is called to get the command line arguments for executing | ||
644 | 336 | * @init. @init is the first argument of this command line array. The rest of | ||
645 | 337 | * the arguments are collected from PROC_CMDLINE which stores the arguments | ||
646 | 338 | * specified at boot time. | ||
647 | 339 | * | ||
648 | 340 | * Returns: the address of the array with the command line arguments on success. | ||
649 | 341 | * On failure returns NULL | ||
650 | 342 | */ | ||
651 | 343 | static char ** | ||
652 | 344 | get_init_args(const char * root, const char * init) | ||
653 | 345 | { | ||
654 | 346 | |||
655 | 347 | char ** env = NULL; | ||
656 | 348 | FILE * cmdline = NULL; | ||
657 | 349 | char ** tokens = NULL; | ||
658 | 350 | int i=0; | ||
659 | 351 | char line[PAGESZ]; | ||
660 | 352 | |||
661 | 353 | nih_assert (root != NULL); | ||
662 | 354 | nih_assert (init != NULL); | ||
663 | 355 | |||
664 | 356 | /* Create the argv for execv(). The first argument is the "init" you | ||
665 | 357 | * want to execute. The command line arguments to be passed to this | ||
666 | 358 | * init are copied from PROC_CMDLINE | ||
667 | 359 | */ | ||
668 | 360 | env = nih_str_array_new (NULL); | ||
669 | 361 | if (!env) | ||
670 | 362 | goto error; | ||
671 | 363 | if (! nih_str_array_add (&env, NULL, NULL, init)) | ||
672 | 364 | goto cleanup; | ||
673 | 365 | /* If the procfs is moved before this call then the /proc/cmdline will | ||
674 | 366 | * be found in @root/PROC_CMDLINE | ||
675 | 367 | */ | ||
676 | 368 | cmdline = fopen (PROC_CMDLINE, "r"); | ||
677 | 369 | if (!cmdline) | ||
678 | 370 | goto cleanup; | ||
679 | 371 | if (!fgets (line, sizeof line, cmdline)) | ||
680 | 372 | goto cleanup; | ||
681 | 373 | tokens = nih_str_split (env, line, " ", 1); | ||
682 | 374 | if (!tokens) | ||
683 | 375 | goto cleanup; | ||
684 | 376 | for ( i=0 ; tokens [i] != NULL; i++) { | ||
685 | 377 | if ((tokens [i][0] == '-') && (tokens [i][1]='-')) { | ||
686 | 378 | /* argument to init */ | ||
687 | 379 | if (!nih_str_array_add (&env, NULL, NULL, tokens[i])) | ||
688 | 380 | goto cleanup; | ||
689 | 381 | } | ||
690 | 382 | } | ||
691 | 383 | fclose (cmdline); | ||
692 | 384 | return env; | ||
693 | 385 | cleanup: | ||
694 | 386 | if (cmdline) | ||
695 | 387 | fclose (cmdline); | ||
696 | 388 | nih_free (env); | ||
697 | 389 | error: | ||
698 | 390 | switch (errno) { | ||
699 | 391 | case ENOMEM: | ||
700 | 392 | nih_error_raise_no_memory (); | ||
701 | 393 | break; | ||
702 | 394 | default: | ||
703 | 395 | nih_dbus_error_raise_printf (DBUS_ERROR_FAILED, | ||
704 | 396 | "Failed to open %s", PROC_CMDLINE); | ||
705 | 397 | break; | ||
706 | 398 | } | ||
707 | 399 | return NULL; | ||
708 | 400 | } | ||
709 | 401 | |||
710 | 402 | |||
711 | 403 | /* | ||
712 | 404 | * @move_mounts: | ||
713 | 405 | * | ||
714 | 406 | * @origin: virtual fs to be moved from "/" | ||
715 | 407 | * @rootfs: root filesystem where the @origin should be moved to. | ||
716 | 408 | * | ||
717 | 409 | * This function is intended to move the virtual filesystem @origin from "/" | ||
718 | 410 | * to the real @rootfs. This is a necessary step before we move root from "/" | ||
719 | 411 | * to the real @rootfs. This function should be called to move /dev, /sys and | ||
720 | 412 | * /proc to a corresponding mountpoint in @rootfs | ||
721 | 413 | * | ||
722 | 414 | * Returns: On success returns 0 and on failure returns -1 | ||
723 | 415 | * | ||
724 | 416 | */ | ||
725 | 417 | static int | ||
726 | 418 | move_mounts(const char * origin, const char * rootfs) | ||
727 | 419 | { | ||
728 | 420 | char * path = NULL; | ||
729 | 421 | int ret = 0; | ||
730 | 422 | |||
731 | 423 | path = nih_strdup (NULL, rootfs); | ||
732 | 424 | if (path) { | ||
733 | 425 | if (origin[0] != '/') | ||
734 | 426 | path = nih_strcat (&path, NULL, "/"); | ||
735 | 427 | if (path) { | ||
736 | 428 | path = nih_strcat (&path, NULL, origin); | ||
737 | 429 | /* Move the devfs to the new root filesystem */ | ||
738 | 430 | if (path) | ||
739 | 431 | ret = mount (origin, path, NULL, MS_MOVE, NULL); | ||
740 | 432 | } | ||
741 | 433 | } | ||
742 | 434 | if (ret || !path) { | ||
743 | 435 | if (errno == ENOMEM) | ||
744 | 436 | nih_error_raise_no_memory (); | ||
745 | 437 | nih_dbus_error_raise_printf (DBUS_ERROR_FAILED, | ||
746 | 438 | _("Cannot move %s to %s"), origin, rootfs); | ||
747 | 439 | ret = -1; | ||
748 | 440 | } | ||
749 | 441 | if (path) | ||
750 | 442 | nih_free (path); | ||
751 | 443 | return ret; | ||
752 | 444 | } | ||
753 | 445 | |||
754 | 446 | /* | ||
755 | 447 | * send_reply: | ||
756 | 448 | * @message: Dbus connection and message received. We use this for sending a | ||
757 | 449 | * reply. | ||
758 | 450 | * | ||
759 | 451 | * This function is used to send a reply back to the initctl command before we | ||
760 | 452 | * execvp the requested init. We do not want to return to the middleware but | ||
761 | 453 | * instead execvp the requested init. By not returning to the middleware we | ||
762 | 454 | * need to ourself send a reply explicitly to initctl so that it can exit. | ||
763 | 455 | */ | ||
764 | 456 | static void | ||
765 | 457 | send_reply (NihDBusMessage *message) | ||
766 | 458 | { | ||
767 | 459 | DBusMessageIter iter; | ||
768 | 460 | DBusMessage * reply; | ||
769 | 461 | |||
770 | 462 | nih_assert (message != NULL); | ||
771 | 463 | |||
772 | 464 | do { | ||
773 | 465 | __label__ enomem; | ||
774 | 466 | |||
775 | 467 | /* Construct the reply message. */ | ||
776 | 468 | reply = dbus_message_new_method_return (message->message); | ||
777 | 469 | if (! reply) | ||
778 | 470 | goto enomem; | ||
779 | 471 | dbus_message_iter_init_append (reply, &iter); | ||
780 | 472 | enomem: __attribute__ ((unused)); | ||
781 | 473 | } while (! reply); | ||
782 | 474 | /* Send the reply, appending it to the outgoing queue. */ | ||
783 | 475 | NIH_MUST (dbus_connection_send (message->connection, reply, NULL)); | ||
784 | 476 | dbus_message_unref (reply); | ||
785 | 477 | return; | ||
786 | 478 | } | ||
787 | 479 | |||
788 | 480 | /** | ||
789 | 481 | * pivot_to_new_rootfs: | ||
790 | 482 | * @message: D-Bus connection and message received, | ||
791 | 483 | * @rootfs: dir to chroot to | ||
792 | 484 | * @init: new init to spawn on chrooting to rootfs | ||
793 | 485 | * | ||
794 | 486 | * Called to change the root filesystem to a requested @rootfs, after which the | ||
795 | 487 | * requested @init should be executed. This function changes the root | ||
796 | 488 | * filesystem only when "/" is on initramfs and the @rootfs is the real rootfs | ||
797 | 489 | * to be switched to. On changing the root filesystem as requested, this | ||
798 | 490 | * function releases memory by deleting the contents of the memory based | ||
799 | 491 | * initramfs before executing @init. If @rootfs or @init are not valid, the | ||
800 | 492 | * org.freedesktop.DBus.Error.InvalidArg error will be returned immediately. | ||
801 | 493 | * If this function fails before freeing the contents of the initramfs then | ||
802 | 494 | * the pivot_failed event is generated. If this function fails after the | ||
803 | 495 | * contents of the initramfs have been freed then failure handling is no more | ||
804 | 496 | * possible. | ||
805 | 497 | * | ||
806 | 498 | * Returns: does not return on success, negative value on raised error. | ||
807 | 499 | **/ | ||
808 | 500 | int | ||
809 | 501 | pivot_to_new_rootfs (NihDBusMessage *message, | ||
810 | 502 | const char *rootfs, | ||
811 | 503 | const char *init) | ||
812 | 504 | { | ||
813 | 505 | char ** env; | ||
814 | 506 | int ret = 0; | ||
815 | 507 | |||
816 | 508 | nih_assert (message != NULL); | ||
817 | 509 | nih_assert (rootfs != NULL); | ||
818 | 510 | nih_assert (init != NULL); | ||
819 | 511 | |||
820 | 512 | /* Verify that the rootfs dir name is valid */ | ||
821 | 513 | if (! strlen (rootfs)) { | ||
822 | 514 | nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, | ||
823 | 515 | _("Rootfs dir name may not be empty string")); | ||
824 | 516 | pivot_emit_failed_event (NULL); | ||
825 | 517 | return -1; | ||
826 | 518 | } | ||
827 | 519 | /* Verify that the init name is valid */ | ||
828 | 520 | if (! strlen (init)) { | ||
829 | 521 | nih_dbus_error_raise_printf (DBUS_ERROR_INVALID_ARGS, | ||
830 | 522 | _("Name of init may not be empty string")); | ||
831 | 523 | pivot_emit_failed_event (NULL); | ||
832 | 524 | return -1; | ||
833 | 525 | } | ||
834 | 526 | /* Before you free up the initramfs memory by deleting files in the | ||
835 | 527 | * initramfs, make sure: | ||
836 | 528 | * 1. That the current root filesystem is memory based. | ||
837 | 529 | * 2. That you are trying to pivot to a different than the current filesystem. | ||
838 | 530 | */ | ||
839 | 531 | if (!are_we_on_ramfs ()) { | ||
840 | 532 | pivot_emit_failed_event (NULL); | ||
841 | 533 | return -1; | ||
842 | 534 | } | ||
843 | 535 | /* Make sure the requested rootfs is not the same filesystem | ||
844 | 536 | as the current("/") root filesystem */ | ||
845 | 537 | if (!is_rootfs_ok (rootfs)) { | ||
846 | 538 | pivot_emit_failed_event (NULL); | ||
847 | 539 | return -1; | ||
848 | 540 | } | ||
849 | 541 | /* Create the argv for execv(). The first argument is the "init" you | ||
850 | 542 | * want to execute. The command line arguments to be passed to this | ||
851 | 543 | * init are copied from /proc/cmdline. | ||
852 | 544 | */ | ||
853 | 545 | env = get_init_args (rootfs, init); | ||
854 | 546 | if (!env) { | ||
855 | 547 | pivot_emit_failed_event (NULL); | ||
856 | 548 | return -1; | ||
857 | 549 | } | ||
858 | 550 | delete_conf_watches (); | ||
859 | 551 | /* Move the virtual filesystem to the new rootfs. This is needed for | ||
860 | 552 | * making @rootfs as the new root filesystem | ||
861 | 553 | */ | ||
862 | 554 | /* 1. Move the sysfs to the new root filesystem */ | ||
863 | 555 | if (move_mounts ("/sys", rootfs)) { | ||
864 | 556 | pivot_emit_failed_event (env); | ||
865 | 557 | nih_free (env); | ||
866 | 558 | return -1; | ||
867 | 559 | } | ||
868 | 560 | /* 2. Move the procfs to the new root filesystem */ | ||
869 | 561 | if (move_mounts ("/proc", rootfs)) { | ||
870 | 562 | pivot_emit_failed_event (env); | ||
871 | 563 | nih_free (env); | ||
872 | 564 | return -1; | ||
873 | 565 | } | ||
874 | 566 | |||
875 | 567 | /* First, change to the new root directory */ | ||
876 | 568 | ret = chdir (rootfs); | ||
877 | 569 | if (ret) { | ||
878 | 570 | nih_dbus_error_raise_printf (DBUS_ERROR_FAILED, | ||
879 | 571 | _("Cannot change to newly requested rootfs dir")); | ||
880 | 572 | pivot_emit_failed_event (env); | ||
881 | 573 | nih_free (env); | ||
882 | 574 | return -1; | ||
883 | 575 | } | ||
884 | 576 | /* Check if the requested init exists */ | ||
885 | 577 | if (!is_init_ok (init)) { | ||
886 | 578 | ret = chdir ("/"); | ||
887 | 579 | pivot_emit_failed_event (env); | ||
888 | 580 | nih_free (env); | ||
889 | 581 | return -1; | ||
890 | 582 | } | ||
891 | 583 | send_reply (message); | ||
892 | 584 | nih_signal_reset (); | ||
893 | 585 | /* After this point you cannot recover from a initramfs console */ | ||
894 | 586 | /* Hopefully we are sure we are in the initramfs and so safe to free | ||
895 | 587 | * the memory now by freeing up the rambased filesystem's contents*/ | ||
896 | 588 | del_dir ("/"); | ||
897 | 589 | /* Overmount the root with the request root filesystem*/ | ||
898 | 590 | ret = mount (".", "/", NULL, MS_MOVE, NULL); | ||
899 | 591 | if (ret) { | ||
900 | 592 | if(errno == ENOMEM) { | ||
901 | 593 | nih_error_raise_no_memory(); | ||
902 | 594 | } | ||
903 | 595 | nih_fatal (_("Cannot mount the requested rootfs")); | ||
904 | 596 | exit (1); | ||
905 | 597 | |||
906 | 598 | } | ||
907 | 599 | nih_debug ("Mounted the new root filesystem "); | ||
908 | 600 | /* chroot, chdir to the new root filesystem*/ | ||
909 | 601 | if (chroot (".")) { | ||
910 | 602 | nih_fatal (_("Could not chroot to the new requested root filesystem")); | ||
911 | 603 | exit (1); | ||
912 | 604 | |||
913 | 605 | } | ||
914 | 606 | if (chdir ("/")) { | ||
915 | 607 | nih_fatal (_("Could not chdir to the new requested root filesystem")); | ||
916 | 608 | exit (1); | ||
917 | 609 | } | ||
918 | 610 | /* Spawn init */ | ||
919 | 611 | nih_debug ("About to execute new requested init: %s", init); | ||
920 | 612 | execvp (init, env); | ||
921 | 613 | nih_fatal (_("Could not execute the new init in the requested rootfs")); | ||
922 | 614 | exit (1); | ||
923 | 615 | } | ||
924 | 616 | |||
925 | 0 | 617 | ||
926 | === added file 'init/pivot.h' | |||
927 | --- init/pivot.h 1970-01-01 00:00:00 +0000 | |||
928 | +++ init/pivot.h 2011-07-15 17:51:29 +0000 | |||
929 | @@ -0,0 +1,66 @@ | |||
930 | 1 | /* upstart | ||
931 | 2 | * | ||
932 | 3 | * pivot.h - Pivot command handling definitions | ||
933 | 4 | * | ||
934 | 5 | * Copyright © 2011 Canonical Ltd. | ||
935 | 6 | * Author: Surbhi A. Palande <surbhi.palande@ubuntu.com>. | ||
936 | 7 | * | ||
937 | 8 | * This program is free software; you can redistribute it and/or modify | ||
938 | 9 | * it under the terms of the GNU General Public License version 2, as | ||
939 | 10 | * published by the Free Software Foundation. | ||
940 | 11 | * | ||
941 | 12 | * This program is distributed in the hope that it will be useful, | ||
942 | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
943 | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
944 | 15 | * GNU General Public License for more details. | ||
945 | 16 | * | ||
946 | 17 | * You should have received a copy of the GNU General Public License along | ||
947 | 18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
948 | 19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
949 | 20 | */ | ||
950 | 21 | |||
951 | 22 | |||
952 | 23 | #include <sys/mount.h> | ||
953 | 24 | #include <sys/stat.h> | ||
954 | 25 | #include <sys/types.h> | ||
955 | 26 | #include <dirent.h> | ||
956 | 27 | #include <sys/vfs.h> | ||
957 | 28 | #include <unistd.h> | ||
958 | 29 | #include <fcntl.h> | ||
959 | 30 | #include <stdio.h> | ||
960 | 31 | #include <string.h> | ||
961 | 32 | #include <sys/types.h> | ||
962 | 33 | #include <sys/wait.h> | ||
963 | 34 | |||
964 | 35 | #include <nih/macros.h> | ||
965 | 36 | #include <nih/alloc.h> | ||
966 | 37 | #include <nih/string.h> | ||
967 | 38 | #include <nih/main.h> | ||
968 | 39 | #include <nih/logging.h> | ||
969 | 40 | #include <nih/error.h> | ||
970 | 41 | #include <nih/errors.h> | ||
971 | 42 | #include <nih-dbus/dbus_error.h> | ||
972 | 43 | |||
973 | 44 | #include <linux/magic.h> | ||
974 | 45 | #include <linux/fs.h> | ||
975 | 46 | |||
976 | 47 | #include "system.h" | ||
977 | 48 | #include "paths.h" | ||
978 | 49 | #include "events.h" | ||
979 | 50 | |||
980 | 51 | /* | ||
981 | 52 | * This macro is used for checking if the major and minor numbers of two | ||
982 | 53 | * devices are the same. | ||
983 | 54 | * | ||
984 | 55 | * @devid1: is a dev_t type id of a device | ||
985 | 56 | * @devid2: is a dev_t type id of another device | ||
986 | 57 | * | ||
987 | 58 | * Returns TRUE if the device ids match, else FALSE | ||
988 | 59 | */ | ||
989 | 60 | #define dev_match(devid1, devid2) ((major (devid1) == major (devid2)) && (minor (devid1) == minor (devid2))) | ||
990 | 61 | |||
991 | 62 | |||
992 | 63 | #define PAGESZ getpagesize() | ||
993 | 64 | |||
994 | 65 | Event * pivot_emit_failed_event (char ** argv); | ||
995 | 66 | int pivot_to_new_rootfs (NihDBusMessage *message, const char *rootfs, const char *init); | ||
996 | 0 | 67 | ||
997 | === modified file 'init/tests/test_control.c' | |||
998 | --- init/tests/test_control.c 2011-06-06 17:05:11 +0000 | |||
999 | +++ init/tests/test_control.c 2011-07-15 17:51:29 +0000 | |||
1000 | @@ -2,7 +2,7 @@ | |||
1001 | 2 | * | 2 | * |
1002 | 3 | * test_dbus.c - test suite for init/dbus.c | 3 | * test_dbus.c - test suite for init/dbus.c |
1003 | 4 | * | 4 | * |
1005 | 5 | * Copyright © 2010 Canonical Ltd. | 5 | * Copyright © 2010-2011 Canonical Ltd. |
1006 | 6 | * Author: Scott James Remnant <scott@netsplit.com>. | 6 | * Author: Scott James Remnant <scott@netsplit.com>. |
1007 | 7 | * | 7 | * |
1008 | 8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
1009 | @@ -60,6 +60,7 @@ | |||
1010 | 60 | #include "conf.h" | 60 | #include "conf.h" |
1011 | 61 | #include "control.h" | 61 | #include "control.h" |
1012 | 62 | #include "errors.h" | 62 | #include "errors.h" |
1013 | 63 | #include "events.h" | ||
1014 | 63 | 64 | ||
1015 | 64 | 65 | ||
1016 | 65 | extern const char *control_server_address; | 66 | extern const char *control_server_address; |
1017 | @@ -2176,6 +2177,108 @@ | |||
1018 | 2176 | nih_log_priority = NIH_LOG_UNKNOWN; | 2177 | nih_log_priority = NIH_LOG_UNKNOWN; |
1019 | 2177 | } | 2178 | } |
1020 | 2178 | 2179 | ||
1021 | 2180 | void | ||
1022 | 2181 | test_pivot_root (void) | ||
1023 | 2182 | { | ||
1024 | 2183 | NihDBusMessage *message = NULL; | ||
1025 | 2184 | char *rootfs = NULL; | ||
1026 | 2185 | char *init = NULL; | ||
1027 | 2186 | NihError *err; | ||
1028 | 2187 | NihDBusError *dbus_err; | ||
1029 | 2188 | int ret = 0; | ||
1030 | 2189 | JobClass *class = NULL; | ||
1031 | 2190 | Job *job; | ||
1032 | 2191 | |||
1033 | 2192 | /* Check that the function returns the package string as a newly | ||
1034 | 2193 | * allocated child of the message structure. | ||
1035 | 2194 | */ | ||
1036 | 2195 | TEST_FUNCTION ("control_pivot_to_new_rootfs"); | ||
1037 | 2196 | nih_error_init (); | ||
1038 | 2197 | job_class_init (); | ||
1039 | 2198 | |||
1040 | 2199 | TEST_ALLOC_FAIL { | ||
1041 | 2200 | TEST_ALLOC_SAFE { | ||
1042 | 2201 | message = nih_new (NULL, NihDBusMessage); | ||
1043 | 2202 | message->connection = NULL; | ||
1044 | 2203 | message->message = NULL; | ||
1045 | 2204 | |||
1046 | 2205 | /* Case 1: Invalid ROOTFS and Invalid INIT */ | ||
1047 | 2206 | rootfs = nih_strdup (NULL, "/tea"); | ||
1048 | 2207 | init = nih_strdup (NULL, "/biscuit"); | ||
1049 | 2208 | class = job_class_new (NULL, "test", NULL); | ||
1050 | 2209 | class->task = TRUE; | ||
1051 | 2210 | class->process[PROCESS_MAIN] = process_new (class->process); | ||
1052 | 2211 | class->process[PROCESS_MAIN]->command = "echo"; | ||
1053 | 2212 | class->start_on = event_operator_new ( | ||
1054 | 2213 | class, EVENT_MATCH, PIVOT_FAILED_EVENT, NULL); | ||
1055 | 2214 | nih_hash_add (job_classes, &class->entry); | ||
1056 | 2215 | } | ||
1057 | 2216 | |||
1058 | 2217 | |||
1059 | 2218 | ret = control_pivot_to_new_rootfs (NULL, message, rootfs, | ||
1060 | 2219 | init); | ||
1061 | 2220 | if (ret < 0) { | ||
1062 | 2221 | TEST_EQ (ret, -1); | ||
1063 | 2222 | err = nih_error_get (); | ||
1064 | 2223 | TEST_ALLOC_SIZE (err, sizeof (NihDBusError)); | ||
1065 | 2224 | |||
1066 | 2225 | TEST_EQ (err->number, NIH_DBUS_ERROR); | ||
1067 | 2226 | dbus_err = (NihDBusError *)err; | ||
1068 | 2227 | TEST_EQ_STR (dbus_err->name, DBUS_ERROR_INVALID_ARGS); | ||
1069 | 2228 | nih_free (dbus_err); | ||
1070 | 2229 | |||
1071 | 2230 | } | ||
1072 | 2231 | |||
1073 | 2232 | event_poll(); | ||
1074 | 2233 | /* a pivot_failed event should be created by the dummy init | ||
1075 | 2234 | * and dummy rootfs. We try to start a job on that*/ | ||
1076 | 2235 | TEST_ALLOC_SAFE { | ||
1077 | 2236 | TEST_HASH_NOT_EMPTY (class->instances); | ||
1078 | 2237 | job = (Job *)nih_hash_lookup (class->instances, ""); | ||
1079 | 2238 | |||
1080 | 2239 | TEST_EQ (job->goal, JOB_START); | ||
1081 | 2240 | |||
1082 | 2241 | waitpid (job->pid[PROCESS_MAIN], NULL, 0); | ||
1083 | 2242 | nih_free (rootfs); | ||
1084 | 2243 | nih_free (init); | ||
1085 | 2244 | |||
1086 | 2245 | /* Case 2: valid ROOTFS and valid INIT. Rootfs not different | ||
1087 | 2246 | * than current FS */ | ||
1088 | 2247 | rootfs = nih_strdup (NULL, "/"); | ||
1089 | 2248 | init = nih_strdup (NULL, "/sbin/init"); | ||
1090 | 2249 | } | ||
1091 | 2250 | |||
1092 | 2251 | ret = control_pivot_to_new_rootfs (NULL, message, rootfs, | ||
1093 | 2252 | init); | ||
1094 | 2253 | if (ret < 0) { | ||
1095 | 2254 | TEST_EQ (ret, -1); | ||
1096 | 2255 | err = nih_error_get (); | ||
1097 | 2256 | TEST_ALLOC_SIZE (err, sizeof (NihDBusError)); | ||
1098 | 2257 | |||
1099 | 2258 | TEST_EQ (err->number, NIH_DBUS_ERROR); | ||
1100 | 2259 | dbus_err = (NihDBusError *)err; | ||
1101 | 2260 | TEST_EQ_STR (dbus_err->name, DBUS_ERROR_INVALID_ARGS); | ||
1102 | 2261 | nih_free (dbus_err); | ||
1103 | 2262 | |||
1104 | 2263 | } | ||
1105 | 2264 | |||
1106 | 2265 | event_poll(); | ||
1107 | 2266 | /* a pivot_failed event should be created by the dummy init | ||
1108 | 2267 | * and dummy rootfs. We try to start a job on that*/ | ||
1109 | 2268 | TEST_ALLOC_SAFE { | ||
1110 | 2269 | TEST_HASH_NOT_EMPTY (class->instances); | ||
1111 | 2270 | job = (Job *)nih_hash_lookup (class->instances, ""); | ||
1112 | 2271 | |||
1113 | 2272 | TEST_EQ (job->goal, JOB_START); | ||
1114 | 2273 | |||
1115 | 2274 | waitpid (job->pid[PROCESS_MAIN], NULL, 0); | ||
1116 | 2275 | nih_free (rootfs); | ||
1117 | 2276 | nih_free (init); | ||
1118 | 2277 | nih_free (class); | ||
1119 | 2278 | } | ||
1120 | 2279 | nih_free (message); | ||
1121 | 2280 | } | ||
1122 | 2281 | } | ||
1123 | 2179 | 2282 | ||
1124 | 2180 | int | 2283 | int |
1125 | 2181 | main (int argc, | 2284 | main (int argc, |
1126 | @@ -2205,5 +2308,7 @@ | |||
1127 | 2205 | test_get_log_priority (); | 2308 | test_get_log_priority (); |
1128 | 2206 | test_set_log_priority (); | 2309 | test_set_log_priority (); |
1129 | 2207 | 2310 | ||
1130 | 2311 | test_pivot_root(); | ||
1131 | 2312 | |||
1132 | 2208 | return 0; | 2313 | return 0; |
1133 | 2209 | } | 2314 | } |
1134 | 2210 | 2315 | ||
1135 | === modified file 'util/initctl.c' | |||
1136 | --- util/initctl.c 2011-06-03 09:37:25 +0000 | |||
1137 | +++ util/initctl.c 2011-07-15 17:51:29 +0000 | |||
1138 | @@ -1,6 +1,6 @@ | |||
1139 | 1 | /* upstart | 1 | /* upstart |
1140 | 2 | * | 2 | * |
1142 | 3 | * Copyright © 2010 Canonical Ltd. | 3 | * Copyright © 2010-2011 Canonical Ltd. |
1143 | 4 | * Author: Scott James Remnant <scott@netsplit.com>. | 4 | * Author: Scott James Remnant <scott@netsplit.com>. |
1144 | 5 | * | 5 | * |
1145 | 6 | * This program is free software; you can redistribute it and/or modify | 6 | * This program is free software; you can redistribute it and/or modify |
1146 | @@ -121,6 +121,7 @@ | |||
1147 | 121 | int log_priority_action (NihCommand *command, char * const *args); | 121 | int log_priority_action (NihCommand *command, char * const *args); |
1148 | 122 | int show_config_action (NihCommand *command, char * const *args); | 122 | int show_config_action (NihCommand *command, char * const *args); |
1149 | 123 | int check_config_action (NihCommand *command, char * const *args); | 123 | int check_config_action (NihCommand *command, char * const *args); |
1150 | 124 | int pivot_action (NihCommand *command, char * const *args); | ||
1151 | 124 | 125 | ||
1152 | 125 | 126 | ||
1153 | 126 | /** | 127 | /** |
1154 | @@ -1202,6 +1203,54 @@ | |||
1155 | 1202 | } | 1203 | } |
1156 | 1203 | 1204 | ||
1157 | 1204 | /** | 1205 | /** |
1158 | 1206 | * pivot_action: | ||
1159 | 1207 | * @command: NihCommand invoked, | ||
1160 | 1208 | * @args: command-line arguments. | ||
1161 | 1209 | * | ||
1162 | 1210 | * This function is called for the "pivot" command. | ||
1163 | 1211 | * | ||
1164 | 1212 | * Returns: 0 on success and 1 on error | ||
1165 | 1213 | **/ | ||
1166 | 1214 | int | ||
1167 | 1215 | pivot_action (NihCommand * command, | ||
1168 | 1216 | char * const *args) | ||
1169 | 1217 | { | ||
1170 | 1218 | nih_local NihDBusProxy *upstart = NULL; | ||
1171 | 1219 | int ret = 1; | ||
1172 | 1220 | NihError * err; | ||
1173 | 1221 | |||
1174 | 1222 | nih_assert (command != NULL); | ||
1175 | 1223 | nih_assert (args != NULL); | ||
1176 | 1224 | |||
1177 | 1225 | if (!args[0]) { | ||
1178 | 1226 | fprintf (stderr, _("%s: missing rootfs \n"), program_name); | ||
1179 | 1227 | nih_main_suggest_help (); | ||
1180 | 1228 | return 1; | ||
1181 | 1229 | } | ||
1182 | 1230 | nih_debug("rootfs: %s", args[0]); | ||
1183 | 1231 | if (!args[1]) { | ||
1184 | 1232 | fprintf (stderr, _("%s: missing init \n"), program_name); | ||
1185 | 1233 | nih_main_suggest_help (); | ||
1186 | 1234 | return 1; | ||
1187 | 1235 | } | ||
1188 | 1236 | nih_debug("init: %s", args[1]); | ||
1189 | 1237 | |||
1190 | 1238 | upstart = upstart_open (NULL); | ||
1191 | 1239 | if (! upstart) | ||
1192 | 1240 | return 1; | ||
1193 | 1241 | |||
1194 | 1242 | ret = upstart_pivot_to_new_rootfs_sync (NULL, upstart, args[0], | ||
1195 | 1243 | args[1]); | ||
1196 | 1244 | if (ret < 0) { | ||
1197 | 1245 | err = nih_error_get (); | ||
1198 | 1246 | nih_error ("Error: %s", err->message); | ||
1199 | 1247 | nih_free (err); | ||
1200 | 1248 | ret = 1; | ||
1201 | 1249 | } | ||
1202 | 1250 | return ret; | ||
1203 | 1251 | } | ||
1204 | 1252 | |||
1205 | 1253 | /** | ||
1206 | 1205 | * show_config_action: | 1254 | * show_config_action: |
1207 | 1206 | * @command: NihCommand invoked, | 1255 | * @command: NihCommand invoked, |
1208 | 1207 | * @args: command-line arguments. | 1256 | * @args: command-line arguments. |
1209 | @@ -2297,6 +2346,15 @@ | |||
1210 | 2297 | }; | 2346 | }; |
1211 | 2298 | 2347 | ||
1212 | 2299 | /** | 2348 | /** |
1213 | 2349 | * pivot_options: | ||
1214 | 2350 | * | ||
1215 | 2351 | * Command-line options accepted for the pivot command. | ||
1216 | 2352 | **/ | ||
1217 | 2353 | NihOption pivot_options[] = { | ||
1218 | 2354 | NIH_OPTION_LAST | ||
1219 | 2355 | }; | ||
1220 | 2356 | |||
1221 | 2357 | /** | ||
1222 | 2300 | * reload_configuration_options: | 2358 | * reload_configuration_options: |
1223 | 2301 | * | 2359 | * |
1224 | 2302 | * Command-line options accepted for the reload-configuration command. | 2360 | * Command-line options accepted for the reload-configuration command. |
1225 | @@ -2365,6 +2423,14 @@ | |||
1226 | 2365 | static NihCommandGroup event_commands = { N_("Event") }; | 2423 | static NihCommandGroup event_commands = { N_("Event") }; |
1227 | 2366 | 2424 | ||
1228 | 2367 | /** | 2425 | /** |
1229 | 2426 | * pivot_group: | ||
1230 | 2427 | * | ||
1231 | 2428 | * Group of commands related to new rootfs and new init. | ||
1232 | 2429 | **/ | ||
1233 | 2430 | static NihCommandGroup pivot_commands = { N_("Rootfs") }; | ||
1234 | 2431 | |||
1235 | 2432 | |||
1236 | 2433 | /** | ||
1237 | 2368 | * commands: | 2434 | * commands: |
1238 | 2369 | * | 2435 | * |
1239 | 2370 | * Commands accepts as the first non-option argument, or program name. | 2436 | * Commands accepts as the first non-option argument, or program name. |
1240 | @@ -2430,6 +2496,14 @@ | |||
1241 | 2430 | "to be included in the event.\n"), | 2496 | "to be included in the event.\n"), |
1242 | 2431 | &event_commands, emit_options, emit_action }, | 2497 | &event_commands, emit_options, emit_action }, |
1243 | 2432 | 2498 | ||
1244 | 2499 | { "pivot", N_("ROOTFS INIT"), | ||
1245 | 2500 | N_("Execute a new init process after changing from a ram based root" | ||
1246 | 2501 | " filesystem to a new root filesystem" ), | ||
1247 | 2502 | N_("ROOTFS is the path of the new root filestem to be changed to" | ||
1248 | 2503 | "INIT is the new init process in the new root filesystem that should be " | ||
1249 | 2504 | "spawned after successfully changing the root filesystem to ROOTFS \n"), | ||
1250 | 2505 | &pivot_commands, pivot_options, pivot_action }, | ||
1251 | 2506 | |||
1252 | 2433 | { "reload-configuration", NULL, | 2507 | { "reload-configuration", NULL, |
1253 | 2434 | N_("Reload the configuration of the init daemon."), | 2508 | N_("Reload the configuration of the init daemon."), |
1254 | 2435 | NULL, | 2509 | NULL, |