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