]>
Commit | Line | Data |
---|---|---|
e9df7e1a CB |
1 | /* |
2 | * lxc: linux Container library | |
3 | * | |
4 | * (C) Copyright IBM Corp. 2007, 2008 | |
5 | * | |
6 | * Authors: | |
7 | * Daniel Lezcano <daniel.lezcano at free.fr> | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | */ | |
23 | ||
24 | #define _GNU_SOURCE | |
25 | #include <grp.h> | |
26 | #include <sched.h> | |
27 | #include <stdio.h> | |
28 | #include <stdlib.h> | |
29 | #include <stdint.h> | |
30 | #include <string.h> | |
31 | #include <unistd.h> | |
32 | #include <sys/types.h> | |
33 | #include <sys/mount.h> | |
34 | ||
e9df7e1a | 35 | #include "log.h" |
28d832c4 CB |
36 | #include "rsync.h" |
37 | #include "storage.h" | |
e9df7e1a CB |
38 | #include "utils.h" |
39 | ||
10bc1861 | 40 | lxc_log_define(rsync, lxc); |
e9df7e1a CB |
41 | |
42 | /* the bulk of this needs to become a common helper */ | |
43 | int do_rsync(const char *src, const char *dest) | |
44 | { | |
45 | // call out to rsync | |
46 | pid_t pid; | |
47 | char *s; | |
48 | size_t l; | |
49 | ||
50 | pid = fork(); | |
51 | if (pid < 0) | |
52 | return -1; | |
53 | if (pid > 0) | |
54 | return wait_for_pid(pid); | |
55 | ||
56 | l = strlen(src) + 2; | |
57 | s = malloc(l); | |
58 | if (!s) | |
59 | exit(1); | |
60 | strcpy(s, src); | |
61 | s[l-2] = '/'; | |
62 | s[l-1] = '\0'; | |
63 | ||
4f142fad | 64 | execlp("rsync", "rsync", "-aHXS", "--delete", s, dest, (char *)NULL); |
e9df7e1a CB |
65 | exit(1); |
66 | } | |
67 | ||
68 | int rsync_delta(struct rsync_data_char *data) | |
69 | { | |
70 | if (setgid(0) < 0) { | |
71 | ERROR("Failed to setgid to 0"); | |
72 | return -1; | |
73 | } | |
74 | if (setgroups(0, NULL) < 0) | |
75 | WARN("Failed to clear groups"); | |
76 | if (setuid(0) < 0) { | |
77 | ERROR("Failed to setuid to 0"); | |
78 | return -1; | |
79 | } | |
80 | if (do_rsync(data->src, data->dest) < 0) { | |
81 | ERROR("rsyncing %s to %s", data->src, data->dest); | |
82 | return -1; | |
83 | } | |
84 | ||
85 | return 0; | |
86 | } | |
87 | ||
88 | int rsync_delta_wrapper(void *data) | |
89 | { | |
90 | struct rsync_data_char *arg = data; | |
91 | return rsync_delta(arg); | |
92 | } | |
93 | ||
94 | int rsync_rootfs(struct rsync_data *data) | |
95 | { | |
10bc1861 | 96 | struct lxc_storage *orig = data->orig, *new = data->new; |
e9df7e1a CB |
97 | |
98 | if (unshare(CLONE_NEWNS) < 0) { | |
99 | SYSERROR("unshare CLONE_NEWNS"); | |
100 | return -1; | |
101 | } | |
102 | if (detect_shared_rootfs()) { | |
103 | if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL)) { | |
104 | SYSERROR("Failed to make / rslave"); | |
105 | ERROR("Continuing..."); | |
106 | } | |
107 | } | |
108 | ||
109 | // If not a snapshot, copy the fs. | |
110 | if (orig->ops->mount(orig) < 0) { | |
111 | ERROR("failed mounting %s onto %s", orig->src, orig->dest); | |
112 | return -1; | |
113 | } | |
114 | if (new->ops->mount(new) < 0) { | |
115 | ERROR("failed mounting %s onto %s", new->src, new->dest); | |
116 | return -1; | |
117 | } | |
118 | if (setgid(0) < 0) { | |
119 | ERROR("Failed to setgid to 0"); | |
120 | return -1; | |
121 | } | |
122 | if (setgroups(0, NULL) < 0) | |
123 | WARN("Failed to clear groups"); | |
124 | if (setuid(0) < 0) { | |
125 | ERROR("Failed to setuid to 0"); | |
126 | return -1; | |
127 | } | |
128 | if (do_rsync(orig->dest, new->dest) < 0) { | |
129 | ERROR("rsyncing %s to %s", orig->src, new->src); | |
130 | return -1; | |
131 | } | |
132 | ||
133 | return 0; | |
134 | } | |
135 | ||
136 | int rsync_rootfs_wrapper(void *data) | |
137 | { | |
138 | struct rsync_data *arg = data; | |
139 | return rsync_rootfs(arg); | |
140 | } | |
301faec2 CB |
141 | |
142 | /* new helpers */ | |
143 | int lxc_rsync_exec_wrapper(void *data) | |
144 | { | |
145 | struct rsync_data *arg = data; | |
146 | return lxc_rsync(arg); | |
147 | } | |
148 | ||
149 | int lxc_rsync_exec(const char *src, const char *dest) | |
150 | { | |
151 | int ret; | |
152 | size_t l; | |
153 | char *s; | |
154 | ||
155 | l = strlen(src) + 2; | |
156 | s = malloc(l); | |
157 | if (!s) | |
158 | return -1; | |
159 | ||
160 | ret = snprintf(s, l, "%s", src); | |
161 | if (ret < 0 || (size_t)ret >= l) | |
162 | return -1; | |
163 | ||
164 | s[l - 2] = '/'; | |
165 | s[l - 1] = '\0'; | |
166 | ||
167 | execlp("rsync", "rsync", "-aHXS", "--delete", s, dest, (char *)NULL); | |
168 | return -1; | |
169 | } | |
170 | ||
171 | int lxc_rsync(struct rsync_data *data) | |
172 | { | |
173 | int ret; | |
10bc1861 | 174 | struct lxc_storage *orig = data->orig, *new = data->new; |
301faec2 CB |
175 | char *dest, *src; |
176 | ||
177 | ret = unshare(CLONE_NEWNS); | |
178 | if (ret < 0) { | |
179 | SYSERROR("Failed to unshare CLONE_NEWNS"); | |
180 | return -1; | |
181 | } | |
182 | ||
183 | ret = detect_shared_rootfs(); | |
184 | if (ret) { | |
185 | ret = mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL); | |
186 | if (ret < 0) | |
187 | SYSERROR("Failed to make \"/\" a slave mount"); | |
188 | } | |
189 | ||
190 | ret = orig->ops->mount(orig); | |
191 | if (ret < 0) { | |
192 | ERROR("Failed mounting \"%s\" on \"%s\"", orig->src, orig->dest); | |
193 | return -1; | |
194 | } | |
195 | ||
196 | ret = new->ops->mount(new); | |
197 | if (ret < 0) { | |
198 | ERROR("Failed mounting \"%s\" onto \"%s\"", new->src, new->dest); | |
199 | return -1; | |
200 | } | |
201 | ||
202 | ret = lxc_switch_uid_gid(0, 0); | |
203 | if (ret < 0) | |
204 | return -1; | |
205 | ret = lxc_setgroups(0, NULL); | |
206 | if (ret < 0) | |
207 | return -1; | |
208 | ||
209 | src = lxc_storage_get_path(orig->dest, orig->type); | |
210 | dest = lxc_storage_get_path(new->dest, new->type); | |
211 | ||
212 | ret = lxc_rsync_exec(src, dest); | |
213 | if (ret < 0) { | |
214 | ERROR("Failed to rsync from \"%s\" into \"%s\"", src, dest); | |
215 | return -1; | |
216 | } | |
217 | ||
218 | return 0; | |
219 | } |