diff options
author | Tito Ragusa <farmatito@tiscali.it> | 2014-03-31 16:39:26 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2014-03-31 16:39:26 +0200 |
commit | a3f326cd6619cadb44cb4bb051b1d4e54bcd3477 (patch) | |
tree | d14296cbe3ff31c322e825b842d5aac868b92fee | |
parent | faa9e94db619d1110061687278cde93a651e69de (diff) | |
download | busybox-w32-a3f326cd6619cadb44cb4bb051b1d4e54bcd3477.tar.gz busybox-w32-a3f326cd6619cadb44cb4bb051b1d4e54bcd3477.tar.bz2 busybox-w32-a3f326cd6619cadb44cb4bb051b1d4e54bcd3477.zip |
swapon/swapoff: size reduction, cleanup, fixes, improvements
1) real swapon/swapoff handles also devices on the commandline with -a;
2) xstat(device) in swap_enable_disable aborts on error when cycling through
fstab so some devices are not handled;
3) duplicated code for ENABLE_FEATURE_SWAPON_DISCARD and
ENABLE_FEATURE_SWAPON_PRI was moved to functions.
4) silence some error messages with -a;
5) minor cleanups and code refactoring reduced the size as per bloat-check:
6) I also added support for /proc/swaps handling to swapoff:
"When the -a flag is given, swapping is disabled on all known swap devices
and files (as found in /proc/swaps or /etc/fstab)."
So now swapoff first cycles through /proc/swaps and then through fstab
to swapoff all devices.
function old new delta
set_discard_flag - 106 +106
swap_enable_disable 147 238 +91
set_priority_flag - 79 +79
retrieve_file_data 470 467 -3
swap_on_off_main 638 418 -220
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 1/2 up/down: 276/-223) Total: 53 bytes
Signed-off-by: Tito Ragusa <farmatito@tiscali.it>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | util-linux/swaponoff.c | 276 |
1 files changed, 161 insertions, 115 deletions
diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c index a7ad6db79..acdb67729 100644 --- a/util-linux/swaponoff.c +++ b/util-linux/swaponoff.c | |||
@@ -63,90 +63,142 @@ struct globals { | |||
63 | } FIX_ALIASING; | 63 | } FIX_ALIASING; |
64 | #define G (*(struct globals*)&bb_common_bufsiz1) | 64 | #define G (*(struct globals*)&bb_common_bufsiz1) |
65 | #define g_flags (G.flags) | 65 | #define g_flags (G.flags) |
66 | #define save_g_flags() int save_g_flags = g_flags | ||
67 | #define restore_g_flags() g_flags = save_g_flags | ||
66 | #else | 68 | #else |
67 | #define g_flags 0 | 69 | #define g_flags 0 |
70 | #define save_g_flags() ((void)0) | ||
71 | #define restore_g_flags() ((void)0) | ||
68 | #endif | 72 | #endif |
69 | #define INIT_G() do { } while (0) | 73 | #define INIT_G() do { } while (0) |
70 | 74 | ||
75 | #define do_swapoff (applet_name[5] == 'f') | ||
76 | |||
77 | /* Command line options */ | ||
78 | enum { | ||
79 | OPTBIT_a, /* -a all */ | ||
80 | IF_FEATURE_SWAPON_DISCARD( OPTBIT_d ,) /* -d discard */ | ||
81 | IF_FEATURE_SWAPON_PRI ( OPTBIT_p ,) /* -p priority */ | ||
82 | OPT_a = 1 << OPTBIT_a, | ||
83 | OPT_d = IF_FEATURE_SWAPON_DISCARD((1 << OPTBIT_d)) + 0, | ||
84 | OPT_p = IF_FEATURE_SWAPON_PRI ((1 << OPTBIT_p)) + 0, | ||
85 | }; | ||
86 | |||
87 | #define OPT_ALL (option_mask32 & OPT_a) | ||
88 | #define OPT_DISCARD (option_mask32 & OPT_d) | ||
89 | #define OPT_PRIO (option_mask32 & OPT_p) | ||
90 | |||
71 | static int swap_enable_disable(char *device) | 91 | static int swap_enable_disable(char *device) |
72 | { | 92 | { |
73 | int status; | 93 | int err = 0; |
94 | int quiet = 0; | ||
74 | struct stat st; | 95 | struct stat st; |
75 | 96 | ||
76 | resolve_mount_spec(&device); | 97 | resolve_mount_spec(&device); |
77 | xstat(device, &st); | ||
78 | |||
79 | #if ENABLE_DESKTOP | ||
80 | /* test for holes */ | ||
81 | if (S_ISREG(st.st_mode)) | ||
82 | if (st.st_blocks * (off_t)512 < st.st_size) | ||
83 | bb_error_msg("warning: swap file has holes"); | ||
84 | #endif | ||
85 | 98 | ||
86 | if (applet_name[5] == 'n') | 99 | if (do_swapoff) { |
87 | status = swapon(device, g_flags); | 100 | err = swapoff(device); |
88 | else | 101 | /* Don't complain on OPT_ALL if not a swap device or if it doesn't exist */ |
89 | status = swapoff(device); | 102 | quiet = (OPT_ALL && (errno == EINVAL || errno == ENOENT)); |
103 | } else { | ||
104 | /* swapon */ | ||
105 | err = stat(device, &st); | ||
106 | if (!err) { | ||
107 | if (ENABLE_DESKTOP && S_ISREG(st.st_mode)) { | ||
108 | if (st.st_blocks * (off_t)512 < st.st_size) { | ||
109 | bb_error_msg("%s: file has holes", device); | ||
110 | return 1; | ||
111 | } | ||
112 | } | ||
113 | err = swapon(device, g_flags); | ||
114 | /* Don't complain on swapon -a if device is already in use */ | ||
115 | quiet = (OPT_ALL && errno == EBUSY); | ||
116 | } | ||
117 | } | ||
90 | 118 | ||
91 | if (status != 0) { | 119 | if (err) { |
92 | bb_simple_perror_msg(device); | 120 | if (!quiet) |
121 | bb_simple_perror_msg(device); | ||
93 | return 1; | 122 | return 1; |
94 | } | 123 | } |
95 | |||
96 | return 0; | 124 | return 0; |
97 | } | 125 | } |
98 | 126 | ||
99 | static int do_em_all(void) | 127 | #if ENABLE_FEATURE_SWAPON_DISCARD |
128 | static void set_discard_flag(char *s) | ||
100 | { | 129 | { |
101 | struct mntent *m; | 130 | /* Unset the flag first to allow fstab options to override */ |
102 | FILE *f; | 131 | /* options set on the command line */ |
103 | int err; | 132 | g_flags = (g_flags & ~SWAP_FLAG_DISCARD_MASK) | SWAP_FLAG_DISCARD; |
104 | #ifdef G | 133 | |
105 | int cl_flags = g_flags; | 134 | if (!s) /* No optional policy value on the commandline */ |
135 | return; | ||
136 | /* Skip prepended '=' */ | ||
137 | if (*s == '=') | ||
138 | s++; | ||
139 | /* For fstab parsing: remove other appended options */ | ||
140 | *strchrnul(s, ',') = '\0'; | ||
141 | |||
142 | if (strcmp(s, "once") == 0) | ||
143 | g_flags |= SWAP_FLAG_DISCARD_ONCE; | ||
144 | if (strcmp(s, "pages") == 0) | ||
145 | g_flags |= SWAP_FLAG_DISCARD_PAGES; | ||
146 | } | ||
147 | #else | ||
148 | #define set_discard_flag(s) ((void)0) | ||
149 | #endif | ||
150 | |||
151 | #if ENABLE_FEATURE_SWAPON_PRI | ||
152 | static void set_priority_flag(char *s) | ||
153 | { | ||
154 | unsigned prio; | ||
155 | |||
156 | /* For fstab parsing: remove other appended options */ | ||
157 | *strchrnul(s, ',') = '\0'; | ||
158 | /* Max allowed 32767 (== SWAP_FLAG_PRIO_MASK) */ | ||
159 | prio = bb_strtou(s, NULL, 10); | ||
160 | if (!errno) { | ||
161 | /* Unset the flag first to allow fstab options to override */ | ||
162 | /* options set on the command line */ | ||
163 | g_flags = (g_flags & ~SWAP_FLAG_PRIO_MASK) | SWAP_FLAG_PREFER | | ||
164 | MIN(prio, SWAP_FLAG_PRIO_MASK); | ||
165 | } | ||
166 | } | ||
167 | #else | ||
168 | #define set_priority_flag(s) ((void)0) | ||
106 | #endif | 169 | #endif |
107 | 170 | ||
108 | f = setmntent("/etc/fstab", "r"); | 171 | static int do_em_all_in_fstab(void) |
109 | if (f == NULL) | 172 | { |
110 | bb_perror_msg_and_die("/etc/fstab"); | 173 | struct mntent *m; |
174 | int err = 0; | ||
175 | FILE *f = xfopen_for_read("/etc/fstab"); | ||
111 | 176 | ||
112 | err = 0; | ||
113 | while ((m = getmntent(f)) != NULL) { | 177 | while ((m = getmntent(f)) != NULL) { |
114 | if (strcmp(m->mnt_type, MNTTYPE_SWAP) == 0) { | 178 | if (strcmp(m->mnt_type, MNTTYPE_SWAP) == 0) { |
115 | /* swapon -a should ignore entries with noauto, | 179 | /* swapon -a should ignore entries with noauto, |
116 | * but swapoff -a should process them */ | 180 | * but swapoff -a should process them |
117 | if (applet_name[5] != 'n' | 181 | */ |
118 | || hasmntopt(m, MNTOPT_NOAUTO) == NULL | 182 | if (do_swapoff || hasmntopt(m, MNTOPT_NOAUTO) == NULL) { |
119 | ) { | 183 | /* each swap space might have different flags */ |
120 | #if ENABLE_FEATURE_SWAPON_DISCARD || ENABLE_FEATURE_SWAPON_PRI | 184 | /* save global flags for the next round */ |
121 | char *p; | 185 | save_g_flags(); |
122 | g_flags = cl_flags; /* each swap space might have different flags */ | 186 | if (ENABLE_FEATURE_SWAPON_DISCARD) { |
123 | #if ENABLE_FEATURE_SWAPON_DISCARD | 187 | char *p = hasmntopt(m, "discard"); |
124 | p = hasmntopt(m, "discard"); | 188 | if (p) { |
125 | if (p) { | 189 | /* move to '=' or to end of string */ |
126 | if (p[7] == '=') { | 190 | p += 7; |
127 | if (strncmp(p + 8, "once", 4) == 0 && (p[12] == ',' || p[12] == '\0')) | 191 | set_discard_flag(p); |
128 | g_flags = (g_flags & ~SWAP_FLAG_DISCARD_MASK) | SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_ONCE; | ||
129 | else if (strncmp(p + 8, "pages", 5) == 0 && (p[13] == ',' || p[13] == '\0')) | ||
130 | g_flags = (g_flags & ~SWAP_FLAG_DISCARD_MASK) | SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_PAGES; | ||
131 | } | 192 | } |
132 | else if (p[7] == ',' || p[7] == '\0') | ||
133 | g_flags = (g_flags & ~SWAP_FLAG_DISCARD_MASK) | SWAP_FLAG_DISCARD; | ||
134 | } | 193 | } |
135 | #endif | 194 | if (ENABLE_FEATURE_SWAPON_PRI) { |
136 | #if ENABLE_FEATURE_SWAPON_PRI | 195 | char *p = hasmntopt(m, "pri"); |
137 | p = hasmntopt(m, "pri"); | 196 | if (p) { |
138 | if (p) { | 197 | set_priority_flag(p + 4); |
139 | /* Max allowed 32767 (== SWAP_FLAG_PRIO_MASK) */ | ||
140 | unsigned prio = bb_strtou(p + 4, NULL, 10); | ||
141 | /* We want to allow "NNNN,foo", thus errno == EINVAL is allowed too */ | ||
142 | if (errno != ERANGE) { | ||
143 | g_flags = (g_flags & ~SWAP_FLAG_PRIO_MASK) | SWAP_FLAG_PREFER | | ||
144 | MIN(prio, SWAP_FLAG_PRIO_MASK); | ||
145 | } | 198 | } |
146 | } | 199 | } |
147 | #endif | 200 | err |= swap_enable_disable(m->mnt_fsname); |
148 | #endif | 201 | restore_g_flags(); |
149 | err += swap_enable_disable(m->mnt_fsname); | ||
150 | } | 202 | } |
151 | } | 203 | } |
152 | } | 204 | } |
@@ -157,74 +209,68 @@ static int do_em_all(void) | |||
157 | return err; | 209 | return err; |
158 | } | 210 | } |
159 | 211 | ||
212 | static int do_all_in_proc_swaps(void) | ||
213 | { | ||
214 | char *line; | ||
215 | int err = 0; | ||
216 | FILE *f = fopen_for_read("/proc/swaps"); | ||
217 | /* Don't complain if missing */ | ||
218 | if (f) { | ||
219 | while ((line = xmalloc_fgetline(f)) != NULL) { | ||
220 | if (line[0] == '/') { | ||
221 | *strchrnul(line, ' ') = '\0'; | ||
222 | err |= swap_enable_disable(line); | ||
223 | } | ||
224 | free(line); | ||
225 | } | ||
226 | if (ENABLE_FEATURE_CLEAN_UP) | ||
227 | fclose(f); | ||
228 | } | ||
229 | |||
230 | return err; | ||
231 | } | ||
232 | |||
233 | #define OPTSTR_SWAPON "a" \ | ||
234 | IF_FEATURE_SWAPON_DISCARD("d::") \ | ||
235 | IF_FEATURE_SWAPON_PRI("p:") | ||
236 | |||
160 | int swap_on_off_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 237 | int swap_on_off_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
161 | int swap_on_off_main(int argc UNUSED_PARAM, char **argv) | 238 | int swap_on_off_main(int argc UNUSED_PARAM, char **argv) |
162 | { | 239 | { |
163 | int ret; | 240 | IF_FEATURE_SWAPON_PRI(char *prio;) |
164 | #if ENABLE_FEATURE_SWAPON_DISCARD | 241 | IF_FEATURE_SWAPON_DISCARD(char *discard = NULL;) |
165 | char *discard = NULL; | 242 | int ret = 0; |
166 | #endif | ||
167 | #if ENABLE_FEATURE_SWAPON_PRI | ||
168 | unsigned prio; | ||
169 | #endif | ||
170 | 243 | ||
171 | INIT_G(); | 244 | INIT_G(); |
172 | 245 | ||
173 | #if !ENABLE_FEATURE_SWAPON_DISCARD && !ENABLE_FEATURE_SWAPON_PRI | 246 | getopt32(argv, do_swapoff ? "a" : OPTSTR_SWAPON |
174 | ret = getopt32(argv, "a"); | 247 | IF_FEATURE_SWAPON_DISCARD(, &discard) |
175 | #else | 248 | IF_FEATURE_SWAPON_PRI(, &prio) |
176 | #if ENABLE_FEATURE_SWAPON_PRI | 249 | ); |
177 | if (applet_name[5] == 'n') | ||
178 | opt_complementary = "p+"; | ||
179 | #endif | ||
180 | ret = getopt32(argv, (applet_name[5] == 'n') ? | ||
181 | #if ENABLE_FEATURE_SWAPON_DISCARD | ||
182 | "d::" | ||
183 | #endif | ||
184 | #if ENABLE_FEATURE_SWAPON_PRI | ||
185 | "p:" | ||
186 | #endif | ||
187 | "a" : "a" | ||
188 | #if ENABLE_FEATURE_SWAPON_DISCARD | ||
189 | , &discard | ||
190 | #endif | ||
191 | #if ENABLE_FEATURE_SWAPON_PRI | ||
192 | , &prio | ||
193 | #endif | ||
194 | ); | ||
195 | #endif | ||
196 | |||
197 | #if ENABLE_FEATURE_SWAPON_DISCARD | ||
198 | if (ret & 1) { // -d | ||
199 | if (!discard) | ||
200 | g_flags |= SWAP_FLAG_DISCARD; | ||
201 | else if (strcmp(discard, "once") == 0) | ||
202 | g_flags |= SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_ONCE; | ||
203 | else if (strcmp(discard, "pages") == 0) | ||
204 | g_flags |= SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_PAGES; | ||
205 | else | ||
206 | bb_show_usage(); | ||
207 | } | ||
208 | ret >>= 1; | ||
209 | #endif | ||
210 | #if ENABLE_FEATURE_SWAPON_PRI | ||
211 | if (ret & 1) // -p | ||
212 | g_flags |= SWAP_FLAG_PREFER | | ||
213 | MIN(prio, SWAP_FLAG_PRIO_MASK); | ||
214 | ret >>= 1; | ||
215 | #endif | ||
216 | |||
217 | if (ret /* & 1: not needed */) // -a | ||
218 | return do_em_all(); | ||
219 | 250 | ||
220 | argv += optind; | 251 | argv += optind; |
221 | if (!*argv) | ||
222 | bb_show_usage(); | ||
223 | 252 | ||
224 | /* ret = 0; redundant */ | 253 | if (OPT_DISCARD) { |
225 | do { | 254 | set_discard_flag(discard); |
226 | ret += swap_enable_disable(*argv); | 255 | } |
227 | } while (*++argv); | 256 | if (OPT_PRIO) { |
257 | set_priority_flag(prio); | ||
258 | } | ||
228 | 259 | ||
260 | if (OPT_ALL) { | ||
261 | /* swapoff -a does also /proc/swaps */ | ||
262 | if (do_swapoff) | ||
263 | ret = do_all_in_proc_swaps(); | ||
264 | ret |= do_em_all_in_fstab(); | ||
265 | } else if (!*argv) { | ||
266 | /* if not -a we need at least one arg */ | ||
267 | bb_show_usage(); | ||
268 | } | ||
269 | /* Unset -a now to allow for more messages in swap_enable_disable */ | ||
270 | option_mask32 = option_mask32 & ~OPT_a; | ||
271 | /* Now process devices on the commandline if any */ | ||
272 | while (*argv) { | ||
273 | ret |= swap_enable_disable(*argv++); | ||
274 | } | ||
229 | return ret; | 275 | return ret; |
230 | } | 276 | } |