1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77#include "libbb.h"
78#include "common_bufsiz.h"
79#include <mntent.h>
80#ifndef __BIONIC__
81# include <sys/swap.h>
82#endif
83
84#if ENABLE_FEATURE_SWAPONOFF_LABEL
85# include "volume_id.h"
86#else
87# define resolve_mount_spec(fsname) ((void)0)
88#endif
89
90#ifndef MNTTYPE_SWAP
91# define MNTTYPE_SWAP "swap"
92#endif
93
94#if ENABLE_FEATURE_SWAPON_DISCARD
95#ifndef SWAP_FLAG_DISCARD
96#define SWAP_FLAG_DISCARD 0x10000
97#endif
98#ifndef SWAP_FLAG_DISCARD_ONCE
99#define SWAP_FLAG_DISCARD_ONCE 0x20000
100#endif
101#ifndef SWAP_FLAG_DISCARD_PAGES
102#define SWAP_FLAG_DISCARD_PAGES 0x40000
103#endif
104#define SWAP_FLAG_DISCARD_MASK \
105 (SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_ONCE | SWAP_FLAG_DISCARD_PAGES)
106#endif
107
108
109#if ENABLE_FEATURE_SWAPON_DISCARD || ENABLE_FEATURE_SWAPON_PRI
110struct globals {
111 int flags;
112} FIX_ALIASING;
113#define G (*(struct globals*)bb_common_bufsiz1)
114#define g_flags (G.flags)
115#define save_g_flags() int save_g_flags = g_flags
116#define restore_g_flags() g_flags = save_g_flags
117#else
118#define g_flags 0
119#define save_g_flags() ((void)0)
120#define restore_g_flags() ((void)0)
121#endif
122#define INIT_G() do { setup_common_bufsiz(); } while (0)
123
124#if ENABLE_SWAPOFF
125# if ENABLE_SWAPON
126# define do_swapoff (applet_name[5] == 'f')
127# else
128# define do_swapoff 1
129# endif
130#else
131# define do_swapoff 0
132#endif
133
134
135enum {
136 OPTBIT_a,
137 OPTBIT_e,
138 IF_FEATURE_SWAPON_DISCARD( OPTBIT_d ,)
139 IF_FEATURE_SWAPON_PRI ( OPTBIT_p ,)
140 OPT_a = 1 << OPTBIT_a,
141 OPT_e = 1 << OPTBIT_e,
142 OPT_d = IF_FEATURE_SWAPON_DISCARD((1 << OPTBIT_d)) + 0,
143 OPT_p = IF_FEATURE_SWAPON_PRI ((1 << OPTBIT_p)) + 0,
144};
145
146#define OPT_ALL (option_mask32 & OPT_a)
147#define OPT_DISCARD (option_mask32 & OPT_d)
148#define OPT_IFEXISTS (option_mask32 & OPT_e)
149#define OPT_PRIO (option_mask32 & OPT_p)
150
151static int swap_enable_disable(char *device)
152{
153 int err = 0;
154 int quiet = 0;
155
156 resolve_mount_spec(&device);
157
158 if (do_swapoff) {
159 err = swapoff(device);
160
161 quiet = (OPT_ALL && (errno == EINVAL || errno == ENOENT));
162 } else {
163
164 struct stat st;
165 err = stat(device, &st);
166 if (!err) {
167 if (ENABLE_DESKTOP && S_ISREG(st.st_mode)) {
168 if (st.st_blocks * (off_t)512 < st.st_size) {
169 bb_error_msg("%s: file has holes", device);
170 return 1;
171 }
172 }
173 err = swapon(device, g_flags);
174
175 quiet = (OPT_ALL && errno == EBUSY);
176 }
177
178 if (err && OPT_IFEXISTS && errno == ENOENT)
179 err = 0;
180 }
181
182 if (err && !quiet) {
183 bb_simple_perror_msg(device);
184 return 1;
185 }
186 return 0;
187}
188
189#if ENABLE_FEATURE_SWAPON_DISCARD
190static void set_discard_flag(char *s)
191{
192
193
194 g_flags = (g_flags & ~SWAP_FLAG_DISCARD_MASK) | SWAP_FLAG_DISCARD;
195
196 if (!s)
197 return;
198
199 if (*s == '=')
200 s++;
201
202 *strchrnul(s, ',') = '\0';
203
204 if (strcmp(s, "once") == 0)
205 g_flags |= SWAP_FLAG_DISCARD_ONCE;
206 if (strcmp(s, "pages") == 0)
207 g_flags |= SWAP_FLAG_DISCARD_PAGES;
208}
209#else
210#define set_discard_flag(s) ((void)0)
211#endif
212
213#if ENABLE_FEATURE_SWAPON_PRI
214static void set_priority_flag(char *s)
215{
216 unsigned prio;
217
218
219 *strchrnul(s, ',') = '\0';
220
221 prio = bb_strtou(s, NULL, 10);
222 if (!errno) {
223
224
225 g_flags = (g_flags & ~SWAP_FLAG_PRIO_MASK) | SWAP_FLAG_PREFER |
226 MIN(prio, SWAP_FLAG_PRIO_MASK);
227 }
228}
229#else
230#define set_priority_flag(s) ((void)0)
231#endif
232
233static int do_em_all_in_fstab(void)
234{
235 struct mntent *m;
236 int err = 0;
237 FILE *f = xfopen_for_read("/etc/fstab");
238
239 while ((m = getmntent(f)) != NULL) {
240 if (strcmp(m->mnt_type, MNTTYPE_SWAP) == 0) {
241
242
243
244 if (do_swapoff || hasmntopt(m, MNTOPT_NOAUTO) == NULL) {
245
246
247 save_g_flags();
248 if (ENABLE_FEATURE_SWAPON_DISCARD) {
249 char *p = hasmntopt(m, "discard");
250 if (p) {
251
252 p += 7;
253 set_discard_flag(p);
254 }
255 }
256 if (ENABLE_FEATURE_SWAPON_PRI) {
257 char *p = hasmntopt(m, "pri");
258 if (p) {
259 set_priority_flag(p + 4);
260 }
261 }
262 err |= swap_enable_disable(m->mnt_fsname);
263 restore_g_flags();
264 }
265 }
266 }
267
268 if (ENABLE_FEATURE_CLEAN_UP)
269 endmntent(f);
270
271 return err;
272}
273
274static int do_all_in_proc_swaps(void)
275{
276 char *line;
277 int err = 0;
278 FILE *f = fopen_for_read("/proc/swaps");
279
280 if (f) {
281 while ((line = xmalloc_fgetline(f)) != NULL) {
282 if (line[0] == '/') {
283 *strchrnul(line, ' ') = '\0';
284 err |= swap_enable_disable(line);
285 }
286 free(line);
287 }
288 if (ENABLE_FEATURE_CLEAN_UP)
289 fclose(f);
290 }
291
292 return err;
293}
294
295#define OPTSTR_SWAPON "ae" \
296 IF_FEATURE_SWAPON_DISCARD("d::") \
297 IF_FEATURE_SWAPON_PRI("p:")
298
299int swap_on_off_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
300int swap_on_off_main(int argc UNUSED_PARAM, char **argv)
301{
302 IF_FEATURE_SWAPON_PRI(char *prio;)
303 IF_FEATURE_SWAPON_DISCARD(char *discard = NULL;)
304 int ret = 0;
305
306 INIT_G();
307
308 getopt32(argv, do_swapoff ? "ae" : OPTSTR_SWAPON
309 IF_FEATURE_SWAPON_DISCARD(, &discard)
310 IF_FEATURE_SWAPON_PRI(, &prio)
311 );
312
313 argv += optind;
314
315 if (OPT_DISCARD) {
316 set_discard_flag(discard);
317 }
318 if (OPT_PRIO) {
319 set_priority_flag(prio);
320 }
321
322 if (OPT_ALL) {
323
324 if (do_swapoff)
325 ret = do_all_in_proc_swaps();
326 ret |= do_em_all_in_fstab();
327 } else if (!*argv) {
328
329 bb_show_usage();
330 }
331
332 option_mask32 = option_mask32 & ~OPT_a;
333
334 while (*argv) {
335 ret |= swap_enable_disable(*argv++);
336 }
337 return ret;
338}
339