blob: 963139adb6f8dc618076e13c307d1f59c994c1d4
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * Mini swapon/swapoff implementation for busybox |
4 | * |
5 | * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> |
6 | * |
7 | * Licensed under GPLv2, see file LICENSE in this source tree. |
8 | */ |
9 | |
10 | //usage:#define swapon_trivial_usage |
11 | //usage: "[-a]" IF_FEATURE_SWAPON_PRI(" [-p PRI]") " [DEVICE]" |
12 | //usage:#define swapon_full_usage "\n\n" |
13 | //usage: "Start swapping on DEVICE\n" |
14 | //usage: "\n -a Start swapping on all swap devices" |
15 | //usage: IF_FEATURE_SWAPON_PRI( |
16 | //usage: "\n -p PRI Set swap device priority" |
17 | //usage: ) |
18 | //usage: |
19 | //usage:#define swapoff_trivial_usage |
20 | //usage: "[-a] [DEVICE]" |
21 | //usage:#define swapoff_full_usage "\n\n" |
22 | //usage: "Stop swapping on DEVICE\n" |
23 | //usage: "\n -a Stop swapping on all swap devices" |
24 | |
25 | #include "libbb.h" |
26 | #include <mntent.h> |
27 | #ifndef __BIONIC__ |
28 | # include <sys/swap.h> |
29 | #endif |
30 | |
31 | #if ENABLE_FEATURE_MOUNT_LABEL |
32 | # include "volume_id.h" |
33 | #else |
34 | # define resolve_mount_spec(fsname) ((void)0) |
35 | #endif |
36 | |
37 | #ifndef MNTTYPE_SWAP |
38 | # define MNTTYPE_SWAP "swap" |
39 | #endif |
40 | |
41 | #if ENABLE_FEATURE_SWAPON_PRI |
42 | struct globals { |
43 | int flags; |
44 | } FIX_ALIASING; |
45 | #define G (*(struct globals*)&bb_common_bufsiz1) |
46 | #define g_flags (G.flags) |
47 | #else |
48 | #define g_flags 0 |
49 | #endif |
50 | #define INIT_G() do { } while (0) |
51 | |
52 | static int swap_enable_disable(char *device) |
53 | { |
54 | int status; |
55 | struct stat st; |
56 | |
57 | resolve_mount_spec(&device); |
58 | xstat(device, &st); |
59 | |
60 | #if ENABLE_DESKTOP |
61 | /* test for holes */ |
62 | if (S_ISREG(st.st_mode)) |
63 | if (st.st_blocks * (off_t)512 < (uint64_t) st.st_size) |
64 | bb_error_msg("warning: swap file has holes"); |
65 | #endif |
66 | |
67 | if (applet_name[5] == 'n') |
68 | status = swapon(device, g_flags); |
69 | else |
70 | status = swapoff(device); |
71 | |
72 | if (status != 0) { |
73 | bb_simple_perror_msg(device); |
74 | return 1; |
75 | } |
76 | |
77 | return 0; |
78 | } |
79 | |
80 | static int do_em_all(void) |
81 | { |
82 | struct mntent *m; |
83 | FILE *f; |
84 | int err; |
85 | |
86 | f = setmntent("/etc/fstab", "r"); |
87 | if (f == NULL) |
88 | bb_perror_msg_and_die("/etc/fstab"); |
89 | |
90 | err = 0; |
91 | while ((m = getmntent(f)) != NULL) { |
92 | if (strcmp(m->mnt_type, MNTTYPE_SWAP) == 0) { |
93 | /* swapon -a should ignore entries with noauto, |
94 | * but swapoff -a should process them */ |
95 | if (applet_name[5] != 'n' |
96 | || hasmntopt(m, MNTOPT_NOAUTO) == NULL |
97 | ) { |
98 | #if ENABLE_FEATURE_SWAPON_PRI |
99 | const char *p; |
100 | g_flags = 0; /* each swap space might have different flags */ |
101 | p = hasmntopt(m, "pri"); |
102 | if (p) { |
103 | /* Max allowed 32767 (==SWAP_FLAG_PRIO_MASK) */ |
104 | unsigned int swap_prio = MIN(bb_strtou(p + 4 , NULL, 10), SWAP_FLAG_PRIO_MASK); |
105 | /* We want to allow "NNNN,foo", thus errno == EINVAL is allowed too */ |
106 | if (errno != ERANGE) { |
107 | g_flags = SWAP_FLAG_PREFER | |
108 | (swap_prio << SWAP_FLAG_PRIO_SHIFT); |
109 | } |
110 | } |
111 | #endif |
112 | err += swap_enable_disable(m->mnt_fsname); |
113 | } |
114 | } |
115 | } |
116 | |
117 | if (ENABLE_FEATURE_CLEAN_UP) |
118 | endmntent(f); |
119 | |
120 | return err; |
121 | } |
122 | |
123 | int swap_on_off_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
124 | int swap_on_off_main(int argc UNUSED_PARAM, char **argv) |
125 | { |
126 | int ret; |
127 | |
128 | INIT_G(); |
129 | |
130 | #if !ENABLE_FEATURE_SWAPON_PRI |
131 | ret = getopt32(argv, "a"); |
132 | #else |
133 | if (applet_name[5] == 'n') |
134 | opt_complementary = "p+"; |
135 | ret = getopt32(argv, (applet_name[5] == 'n') ? "ap:" : "a", &g_flags); |
136 | |
137 | if (ret & 2) { // -p |
138 | g_flags = SWAP_FLAG_PREFER | |
139 | ((g_flags & SWAP_FLAG_PRIO_MASK) << SWAP_FLAG_PRIO_SHIFT); |
140 | ret &= 1; |
141 | } |
142 | #endif |
143 | |
144 | if (ret /* & 1: not needed */) // -a |
145 | return do_em_all(); |
146 | |
147 | argv += optind; |
148 | if (!*argv) |
149 | bb_show_usage(); |
150 | |
151 | /* ret = 0; redundant */ |
152 | do { |
153 | ret += swap_enable_disable(*argv); |
154 | } while (*++argv); |
155 | |
156 | return ret; |
157 | } |
158 |