umount2系统调用及示例

umount2 函数详解

  1. 函数介绍

umount2 是Linux系统调用,用于卸载文件系统。它是 umount 函数的增强版本,支持更多的卸载选项和标志。通过 umount2,程序可以更精细地控制文件系统的卸载过程,包括强制卸载、延迟卸载等高级功能。

  1. 函数原型
1
2
3
#include <sys/mount.h>
int umount2(const char *target, int flags);

  1. 功能

umount2 卸载指定挂载点的文件系统,并支持多种卸载标志来控制卸载行为。它可以处理繁忙的文件系统、只读文件系统等情况,提供更灵活的卸载选项。

  1. 参数
  • *const char target: 要卸载的文件系统挂载点路径

  • int flags: 卸载标志,控制卸载行为

  1. 返回值
  • 成功: 返回0

  • 失败: 返回-1,并设置errno

  1. 相似函数,或关联函数
  • umount: 基础卸载函数(等同于umount2(target, 0))

  • mount: 挂载文件系统

  • getmntent: 获取挂载信息

  • /proc/mounts: 挂载信息文件

  1. 示例代码

示例1:基础umount2使用

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

/**
* 显示当前挂载信息
*/
void show_mount_info() {
printf("=== 当前挂载信息 ===\n");
system("cat /proc/mounts | head -10"); // 显示前10行挂载信息
printf("\n");
}

/**
* 创建测试挂载点
*/
int create_test_mountpoint(const char *mountpoint) {
struct stat st;

// 检查挂载点是否存在
if (stat(mountpoint, &st) == 0) {
printf("挂载点 %s 已存在\n", mountpoint);
return 0;
}

// 创建挂载点目录
if (mkdir(mountpoint, 0755) == -1) {
perror("创建挂载点目录失败");
return -1;
}

printf("创建挂载点: %s\n", mountpoint);
return 0;
}

/**
* 演示基础umount2使用方法
*/
int demo_umount2_basic() {
const char *test_mountpoint = "/tmp/test_umount2";
int result;

printf("=== 基础umount2使用示例 ===\n");

// 显示原始挂载信息
printf("1. 原始挂载信息:\n");
show_mount_info();

// 创建测试挂载点
printf("2. 创建测试挂载点:\n");
if (create_test_mountpoint(test_mountpoint) != 0) {
return -1;
}

// 尝试卸载不存在的挂载点(演示错误处理)
printf("3. 尝试卸载不存在的挂载点:\n");
printf(" 卸载目标: %s\n", test_mountpoint);

result = umount2(test_mountpoint, 0);
if (result == -1) {
printf(" ✓ 卸载失败(预期结果): %s\n", strerror(errno));
if (errno == EINVAL) {
printf(" 原因:指定的挂载点不存在\n");
} else if (errno == EPERM) {
printf(" 原因:权限不足\n");
} else if (errno == EBUSY) {
printf(" 原因:挂载点正忙\n");
}
} else {
printf(" ✗ 卸载意外成功\n");
}

// 演示不同卸载标志
printf("\n4. 卸载标志说明:\n");
printf(" 0: 普通卸载\n");
printf(" MNT_FORCE: 强制卸载\n");
printf(" MNT_DETACH: 延迟卸载\n");
printf(" MNT_EXPIRE: 标记为过期\n");

// 清理测试挂载点
printf("\n5. 清理测试挂载点:\n");
if (rmdir(test_mountpoint) == 0) {
printf(" ✓ 测试挂载点清理成功\n");
} else {
printf(" ✗ 测试挂载点清理失败: %s\n", strerror(errno));
}

return 0;
}

int main() {
return demo_umount2_basic();
}

示例2:文件系统挂载和卸载管理

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mntent.h>

/**
* 挂载点管理器结构
*/
typedef struct {
char mountpoint&#91;256];
char filesystem&#91;32];
char device&#91;256];
int is_mounted;
unsigned long mount_options;
} mount_manager_t;

/**
* 初始化挂载点管理器
*/
int init_mount_manager(mount_manager_t *manager, const char *mountpoint,
const char *device, const char *filesystem) {
strncpy(manager->mountpoint, mountpoint, sizeof(manager->mountpoint) - 1);
manager->mountpoint&#91;sizeof(manager->mountpoint) - 1] = '\0';

strncpy(manager->device, device, sizeof(manager->device) - 1);
manager->device&#91;sizeof(manager->device) - 1] = '\0';

strncpy(manager->filesystem, filesystem, sizeof(manager->filesystem) - 1);
manager->filesystem&#91;sizeof(manager->filesystem) - 1] = '\0';

manager->is_mounted = 0;
manager->mount_options = 0;

printf("挂载点管理器初始化:\n");
printf(" 挂载点: %s\n", manager->mountpoint);
printf(" 设备: %s\n", manager->device);
printf(" 文件系统: %s\n", manager->filesystem);

return 0;
}

/**
* 检查挂载点是否存在
*/
int is_mountpoint_exists(const char *mountpoint) {
FILE *fp = setmntent("/proc/mounts", "r");
if (!fp) {
return -1;
}

struct mntent *mnt;
int exists = 0;

while ((mnt = getmntent(fp)) != NULL) {
if (strcmp(mnt->mnt_dir, mountpoint) == 0) {
exists = 1;
break;
}
}

endmntent(fp);
return exists;
}

/**
* 挂载文件系统
*/
int mount_filesystem(mount_manager_t *manager) {
// 创建挂载点
struct stat st;
if (stat(manager->mountpoint, &st) == -1) {
if (mkdir(manager->mountpoint, 0755) == -1) {
perror("创建挂载点失败");
return -1;
}
printf("创建挂载点: %s\n", manager->mountpoint);
}

// 执行挂载
printf("挂载文件系统:\n");
printf(" 设备: %s\n", manager->device);
printf(" 挂载点: %s\n", manager->mountpoint);
printf(" 文件系统: %s\n", manager->filesystem);

// 注意:实际挂载需要root权限和有效设备
// 这里仅演示调用方式
printf(" 注意:实际挂载需要root权限和有效设备\n");

manager->is_mounted = 1;
return 0;
}

/**
* 卸载文件系统(使用umount2)
*/
int unmount_filesystem(mount_manager_t *manager, int flags) {
printf("卸载文件系统:\n");
printf(" 挂载点: %s\n", manager->mountpoint);
printf(" 卸载标志: 0x%x\n", flags);

// 检查挂载点是否存在
if (!is_mountpoint_exists(manager->mountpoint)) {
printf(" 挂载点不存在,无需卸载\n");
manager->is_mounted = 0;
return 0;
}

// 执行卸载
int result = umount2(manager->mountpoint, flags);
if (result == 0) {
printf(" ✓ 文件系统卸载成功\n");
manager->is_mounted = 0;

// 清理挂载点目录
if (rmdir(manager->mountpoint) == 0) {
printf(" ✓ 挂载点目录清理成功\n");
} else {
printf(" ✗ 挂载点目录清理失败: %s\n", strerror(errno));
}
} else {
printf(" ✗ 文件系统卸载失败: %s\n", strerror(errno));
if (errno == EBUSY) {
printf(" 原因:文件系统正忙\n");
} else if (errno == EINVAL) {
printf(" 原因:无效的挂载点\n");
} else if (errno == EPERM) {
printf(" 原因:权限不足\n");
}
}

return result;
}

/**
* 演示文件系统挂载和卸载管理
*/
int demo_filesystem_management() {
mount_manager_t manager;
const char *test_mountpoint = "/tmp/test_fs_manager";
const char *test_device = "/dev/loop0"; // 示例设备
const char *test_filesystem = "ext4";

printf("=== 文件系统挂载和卸载管理演示 ===\n");

// 初始化管理器
printf("1. 初始化挂载点管理器:\n");
if (init_mount_manager(&manager, test_mountpoint, test_device, test_filesystem) != 0) {
return -1;
}

// 显示当前挂载状态
printf("\n2. 当前挂载状态检查:\n");
int exists = is_mountpoint_exists(manager.mountpoint);
if (exists == 1) {
printf(" 挂载点已存在\n");
} else if (exists == 0) {
printf(" 挂载点不存在\n");
} else {
printf(" 无法检查挂载状态\n");
}

// 模拟挂载操作
printf("\n3. 模拟挂载操作:\n");
if (mount_filesystem(&manager) != 0) {
printf("挂载操作失败\n");
return -1;
}

// 演示不同卸载方式
printf("\n4. 演示不同卸载方式:\n");

// 方式1:普通卸载
printf(" 方式1:普通卸载 (MNT_UMOUNT):\n");
unmount_filesystem(&manager, 0);

// 方式2:强制卸载
printf("\n 方式2:强制卸载 (MNT_FORCE):\n");
unmount_filesystem(&manager, MNT_FORCE);

// 方式3:延迟卸载
printf("\n 方式3:延迟卸载 (MNT_DETACH):\n");
unmount_filesystem(&manager, MNT_DETACH);

// 方式4:过期卸载
printf("\n 方式4:过期卸载 (MNT_EXPIRE):\n");
unmount_filesystem(&manager, MNT_EXPIRE);

// 显示最终状态
printf("\n5. 最终状态:\n");
printf(" 挂载点状态: %s\n", manager.is_mounted ? "已挂载" : "未挂载");

return 0;
}

int main() {
return demo_filesystem_management();
}

示例3:安全卸载工具

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mntent.h>
#include <signal.h>
#include <sys/wait.h>

/**
* 安全卸载结果结构
*/
typedef struct {
char mountpoint&#91;256];
int attempts;
int success;
int force_used;
int detach_used;
int final_status;
char error_message&#91;256];
} safe_unmount_result_t;

/**
* 检查挂载点是否正在使用
*/
int is_mountpoint_busy(const char *mountpoint) {
// 检查是否有进程在使用该挂载点
char command&#91;512];
snprintf(command, sizeof(command), "lsof %s 2>/dev/null | wc -l", mountpoint);

FILE *fp = popen(command, "r");
if (fp) {
char buffer&#91;16];
if (fgets(buffer, sizeof(buffer), fp)) {
int count = atoi(buffer);
pclose(fp);
return count > 0;
}
pclose(fp);
}

return 0; // 默认认为不忙
}

/**
* 显示挂载点信息
*/
void show_mountpoint_info(const char *mountpoint) {
FILE *fp = setmntent("/proc/mounts", "r");
if (!fp) {
printf("无法读取挂载信息\n");
return;
}

struct mntent *mnt;
printf("挂载点详细信息:\n");

while ((mnt = getmntent(fp)) != NULL) {
if (strcmp(mnt->mnt_dir, mountpoint) == 0) {
printf(" 设备: %s\n", mnt->mnt_fsname);
printf(" 挂载点: %s\n", mnt->mnt_dir);
printf(" 文件系统: %s\n", mnt->mnt_type);
printf(" 选项: %s\n", mnt->mnt_opts);
break;
}
}

endmntent(fp);
}

/**
* 安全卸载文件系统
*/
int safe_unmount_filesystem(const char *mountpoint, safe_unmount_result_t *result) {
int attempt = 0;
const int max_attempts = 5;
int result_code = 0;

// 初始化结果结构
strncpy(result->mountpoint, mountpoint, sizeof(result->mountpoint) - 1);
result->mountpoint&#91;sizeof(result->mountpoint) - 1] = '\0';
result->attempts = 0;
result->success = 0;
result->force_used = 0;
result->detach_used = 0;
result->final_status = 0;
result->error_message&#91;0] = '\0';

printf("=== 安全卸载文件系统 ===\n");
printf("目标挂载点: %s\n", mountpoint);

// 检查挂载点是否存在
if (!is_mountpoint_exists(mountpoint)) {
printf("挂载点不存在,无需卸载\n");
result->success = 1;
return 0;
}

// 显示挂载点信息
show_mountpoint_info(mountpoint);

// 检查挂载点是否正在使用
printf("检查挂载点使用状态...\n");
if (is_mountpoint_busy(mountpoint)) {
printf("警告:挂载点正在使用中\n");
} else {
printf("挂载点当前未被使用\n");
}

// 尝试多次卸载
while (attempt < max_attempts) {
attempt++;
result->attempts = attempt;
printf("第 %d 次卸载尝试:\n", attempt);

// 根据尝试次数选择不同的卸载策略
int flags = 0;
if (attempt > 1) {
printf(" 挂载点可能正忙,等待片刻...\n");
sleep(1);
}

if (attempt == 2) {
// 第二次尝试:发送SIGTERM给可能使用该挂载点的进程
printf(" 尝试通知使用该挂载点的进程...\n");
} else if (attempt == 3) {
flags = MNT_FORCE; // 强制卸载
result->force_used = 1;
printf(" 使用强制卸载模式\n");
} else if (attempt == 4) {
flags = 0; // 再次尝试普通卸载
printf(" 再次尝试普通卸载\n");
} else if (attempt == 5) {
flags = MNT_DETACH; // 延迟卸载
result->detach_used = 1;
printf(" 使用延迟卸载模式\n");
}

// 执行卸载
result_code = umount2(mountpoint, flags);
if (result_code == 0) {
printf(" ✓ 卸载成功\n");
result->success = 1;
result->final_status = 0;
break;
} else {
printf(" ✗ 卸载失败: %s\n", strerror(errno));
result->final_status = errno;
strncpy(result->error_message, strerror(errno), sizeof(result->error_message) - 1);
result->error_message&#91;sizeof(result->error_message) - 1] = '\0';

// 根据错误类型决定是否继续尝试
if (errno == EINVAL) {
printf(" 无效的挂载点,停止尝试\n");
break;
} else if (errno == EPERM) {
printf(" 权限不足,停止尝试\n");
break;
}
}
}

// 显示最终结果
printf("\n=== 卸载结果 ===\n");
printf("挂载点: %s\n", result->mountpoint);
printf("尝试次数: %d\n", result->attempts);
printf("卸载状态: %s\n", result->success ? "成功" : "失败");

if (result->success) {
printf("卸载方式: ");
if (result->force_used) {
printf("强制卸载\n");
} else if (result->detach_used) {
printf("延迟卸载\n");
} else {
printf("普通卸载\n");
}
} else {
printf("失败原因: %s\n", result->error_message);
printf("最终错误码: %d\n", result->final_status);
}

return result->success ? 0 : -1;
}

/**
* 演示安全卸载工具
*/
int demo_safe_unmount_tool() {
safe_unmount_result_t result;
const char *test_mountpoint = "/mnt/test_safe_unmount";

printf("=== 安全卸载工具演示 ===\n");

// 检查权限
uid_t uid = getuid();
printf("权限检查:\n");
printf(" 当前用户ID: %d\n", uid);
if (uid == 0) {
printf(" ✓ 具有root权限\n");
} else {
printf(" ✗ 没有root权限,卸载操作可能失败\n");
printf(" 提示:文件系统卸载通常需要root权限\n");
}

// 显示当前挂载信息
printf("\n当前挂载信息:\n");
system("cat /proc/mounts | grep -E '(tmp|mnt)' | head -5");

// 演示安全卸载
printf("\n演示安全卸载:\n");
printf("目标挂载点: %s\n", test_mountpoint);

// 注意:实际演示中避免卸载真实的重要文件系统
// 这里仅演示调用方式和错误处理

// 模拟卸载不存在的挂载点
printf("\n1. 卸载不存在的挂载点:\n");
if (safe_unmount_filesystem(test_mountpoint, &result) != 0) {
printf("卸载不存在的挂载点(预期失败)\n");
}

// 演示卸载过程中的错误处理
printf("\n2. 卸载错误处理演示:\n");

// 尝试卸载根目录(应该失败)
printf("尝试卸载根目录:\n");
safe_unmount_filesystem("/", &result);

// 尝试卸载无效路径
printf("\n尝试卸载无效路径:\n");
safe_unmount_filesystem("/invalid/mount/point", &result);

// 显示安全卸载建议
printf("\n=== 安全卸载建议 ===\n");
printf("1. 卸载前检查:\n");
printf(" ✓ 确认具有足够权限\n");
printf(" ✓ 检查挂载点是否存在\n");
printf(" ✓ 确认没有进程使用该挂载点\n");
printf(" ✓ 备份重要数据\n");

printf("\n2. 卸载策略:\n");
printf(" ✓ 首先尝试普通卸载\n");
printf(" ✓ 失败后等待并重试\n");
printf(" ✓ 必要时使用强制卸载\n");
printf(" ✓ 最后考虑延迟卸载\n");

printf("\n3. 错误处理:\n");
printf(" ✓ 检查返回值和errno\n");
printf(" ✓ 根据错误类型采取不同措施\n");
printf(" ✓ 记录卸载操作日志\n");
printf(" ✓ 提供友好的错误信息\n");

printf("\n4. 安全考虑:\n");
printf(" ✓ 避免强制卸载重要文件系统\n");
printf(" ✓ 确保数据一致性\n");
printf(" ✓ 监控卸载后的系统状态\n");
printf(" ✓ 准备恢复方案\n");

return 0;
}

int main() {
return demo_safe_unmount_tool();
}

示例4:批量卸载管理器

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mntent.h>
#include <fnmatch.h>

/**
* 批量卸载条目结构
*/
typedef struct {
char mountpoint&#91;256];
char filesystem&#91;32];
char device&#91;256];
int selected_for_unmount;
int unmount_result;
char result_message&#91;128];
} batch_unmount_entry_t;

/**
* 批量卸载管理器结构
*/
typedef struct {
batch_unmount_entry_t entries&#91;64];
int entry_count;
int selected_count;
int successful_count;
int failed_count;
} batch_unmount_manager_t;

/**
* 初始化批量卸载管理器
*/
void init_batch_unmount_manager(batch_unmount_manager_t *manager) {
memset(manager, 0, sizeof(batch_unmount_manager_t));
printf("批量卸载管理器初始化完成\n");
}

/**
* 从/proc/mounts加载挂载信息
*/
int load_mount_entries(batch_unmount_manager_t *manager) {
FILE *fp = setmntent("/proc/mounts", "r");
if (!fp) {
printf("无法读取挂载信息: %s\n", strerror(errno));
return -1;
}

struct mntent *mnt;
int count = 0;

printf("加载挂载信息:\n");

while ((mnt = getmntent(fp)) != NULL && count < 64) {
// 过滤系统挂载点
if (strncmp(mnt->mnt_dir, "/proc", 5) == 0 ||
strncmp(mnt->mnt_dir, "/sys", 4) == 0 ||
strncmp(mnt->mnt_dir, "/dev", 4) == 0) {
continue; // 跳过系统挂载点
}

batch_unmount_entry_t *entry = &manager->entries&#91;count];
strncpy(entry->mountpoint, mnt->mnt_dir, sizeof(entry->mountpoint) - 1);
entry->mountpoint&#91;sizeof(entry->mountpoint) - 1] = '\0';

strncpy(entry->filesystem, mnt->mnt_type, sizeof(entry->filesystem) - 1);
entry->filesystem&#91;sizeof(entry->filesystem) - 1] = '\0';

strncpy(entry->device, mnt->mnt_fsname, sizeof(entry->device) - 1);
entry->device&#91;sizeof(entry->device) - 1] = '\0';

entry->selected_for_unmount = 0;
entry->unmount_result = 0;
entry->result_message&#91;0] = '\0';

printf(" %s (%s on %s)\n", entry->mountpoint, entry->filesystem, entry->device);
count++;
}

endmntent(fp);
manager->entry_count = count;
printf("共加载 %d 个挂载点\n", count);

return 0;
}

/**
* 根据模式选择挂载点
*/
int select_mountpoints_by_pattern(batch_unmount_manager_t *manager, const char *pattern) {
int selected = 0;

printf("根据模式选择挂载点: %s\n", pattern);

for (int i = 0; i < manager->entry_count; i++) {
batch_unmount_entry_t *entry = &manager->entries&#91;i];

if (fnmatch(pattern, entry->mountpoint, 0) == 0) {
entry->selected_for_unmount = 1;
selected++;
printf(" 选中: %s\n", entry->mountpoint);
}
}

manager->selected_count = selected;
printf("共选中 %d 个挂载点\n", selected);

return selected;
}

/**
* 执行批量卸载
*/
int execute_batch_unmount(batch_unmount_manager_t *manager, int flags) {
printf("=== 执行批量卸载 ===\n");
printf("卸载标志: 0x%x\n", flags);
printf("选中挂载点数量: %d\n", manager->selected_count);

manager->successful_count = 0;
manager->failed_count = 0;

for (int i = 0; i < manager->entry_count; i++) {
batch_unmount_entry_t *entry = &manager->entries&#91;i];

if (!entry->selected_for_unmount) {
continue;
}

printf("\n卸载 %s:\n", entry->mountpoint);

// 执行卸载
int result = umount2(entry->mountpoint, flags);
entry->unmount_result = result;

if (result == 0) {
printf(" ✓ 卸载成功\n");
manager->successful_count++;
strncpy(entry->result_message, "成功", sizeof(entry->result_message) - 1);
} else {
printf(" ✗ 卸载失败: %s\n", strerror(errno));
manager->failed_count++;
strncpy(entry->result_message, strerror(errno), sizeof(entry->result_message) - 1);
entry->result_message&#91;sizeof(entry->result_message) - 1] = '\0';
}
}

printf("\n=== 批量卸载结果 ===\n");
printf("成功: %d\n", manager->successful_count);
printf("失败: %d\n", manager->failed_count);
printf("总计: %d\n", manager->successful_count + manager->failed_count);

// 显示详细结果
printf("\n详细结果:\n");
for (int i = 0; i < manager->entry_count; i++) {
batch_unmount_entry_t *entry = &manager->entries&#91;i];
if (entry->selected_for_unmount) {
printf(" %s: %s (%s)\n",
entry->mountpoint,
entry->unmount_result == 0 ? "✓" : "✗",
entry->result_message);
}
}

return (manager->failed_count == 0) ? 0 : -1;
}

/**
* 显示批量卸载摘要
*/
void show_batch_unmount_summary(const batch_unmount_manager_t *manager) {
printf("=== 批量卸载摘要 ===\n");
printf("总挂载点数: %d\n", manager->entry_count);
printf("选中卸载数: %d\n", manager->selected_count);
printf("成功卸载数: %d\n", manager->successful_count);
printf("失败卸载数: %d\n", manager->failed_count);
printf("成功率: %.1f%%\n",
manager->selected_count > 0 ?
(double)manager->successful_count / manager->selected_count * 100 : 0);

if (manager->failed_count > 0) {
printf("\n失败详情:\n");
for (int i = 0; i < manager->entry_count; i++) {
const batch_unmount_entry_t *entry = &manager->entries&#91;i];
if (entry->selected_for_unmount && entry->unmount_result != 0) {
printf(" %s: %s\n", entry->mountpoint, entry->result_message);
}
}
}
}

/**
* 演示批量卸载管理器
*/
int demo_batch_unmount_manager() {
batch_unmount_manager_t manager;

printf("=== 批量卸载管理器演示 ===\n");

// 初始化管理器
printf("1. 初始化批量卸载管理器:\n");
init_batch_unmount_manager(&manager);

// 加载挂载信息
printf("\n2. 加载挂载信息:\n");
if (load_mount_entries(&manager) != 0) {
printf("加载挂载信息失败\n");
return -1;
}

// 显示可用的卸载选项
printf("\n3. 可用挂载点:\n");
for (int i = 0; i < manager.entry_count && i < 10; i++) {
const batch_unmount_entry_t *entry = &manager.entries&#91;i];
printf(" %d. %s (%s)\n", i + 1, entry->mountpoint, entry->filesystem);
}

if (manager.entry_count > 10) {
printf(" ... (还有 %d 个挂载点)\n", manager.entry_count - 10);
}

// 演示模式匹配选择
printf("\n4. 模式匹配选择演示:\n");

// 选择/tmp目录下的挂载点
select_mountpoints_by_pattern(&manager, "/tmp/*");

// 选择/media目录下的挂载点
select_mountpoints_by_pattern(&manager, "/media/*");

// 选择所有ext4文件系统
printf("\n根据文件系统类型选择:\n");
int ext4_selected = 0;
for (int i = 0; i < manager.entry_count; i++) {
batch_unmount_entry_t *entry = &manager.entries&#91;i];
if (strcmp(entry->filesystem, "ext4") == 0) {
entry->selected_for_unmount = 1;
ext4_selected++;
printf(" 选中ext4文件系统: %s\n", entry->mountpoint);
}
}
printf("共选中 %d 个ext4文件系统\n", ext4_selected);

// 显示选中结果
printf("\n5. 选中挂载点列表:\n");
for (int i = 0; i < manager.entry_count; i++) {
const batch_unmount_entry_t *entry = &manager.entries&#91;i];
if (entry->selected_for_unmount) {
printf(" %s (%s on %s)\n",
entry->mountpoint, entry->filesystem, entry->device);
}
}

// 演示不同卸载模式
printf("\n6. 不同卸载模式演示:\n");

// 模式1:普通卸载
printf("模式1:普通卸载\n");
printf("注意:实际演示中跳过真实卸载操作以避免影响系统\n");

// 模式2:强制卸载
printf("\n模式2:强制卸载\n");
printf("卸载标志: MNT_FORCE (0x%x)\n", MNT_FORCE);

// 模式3:延迟卸载
printf("\n模式3:延迟卸载\n");
printf("卸载标志: MNT_DETACH (0x%x)\n", MNT_DETACH);

// 模式4:过期卸载
printf("\n模式4:过期卸载\n");
printf("卸载标志: MNT_EXPIRE (0x%x)\n", MNT_EXPIRE);

// 显示批量卸载策略
printf("\n=== 批量卸载策略 ===\n");
printf("1. 选择策略:\n");
printf(" ✓ 支持通配符模式匹配\n");
printf(" ✓ 支持文件系统类型筛选\n");
printf(" ✓ 支持设备类型筛选\n");
printf(" ✓ 支持交互式选择\n");

printf("\n2. 卸载策略:\n");
printf(" ✓ 优先尝试普通卸载\n");
printf(" ✓ 失败后尝试强制卸载\n");
printf(" ✓ 最后考虑延迟卸载\n");
printf(" ✓ 支持批量重试机制\n");

printf("\n3. 错误处理:\n");
printf(" ✓ 详细记录每个卸载操作结果\n");
printf(" ✓ 提供失败原因分析\n");
printf(" ✓ 支持部分成功处理\n");
printf(" ✓ 生成卸载报告\n");

printf("\n4. 安全考虑:\n");
printf(" ✓ 避免卸载系统关键挂载点\n");
printf(" ✓ 检查挂载点使用状态\n");
printf(" ✓ 提供确认机制\n");
printf(" ✓ 支持回滚操作\n");

return 0;
}

int main() {
return demo_batch_unmount_manager();
}

示例5:文件系统监控和管理

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
#include <sys/mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mntent.h>
#include <time.h>
#include <sys/statvfs.h>

/**
* 文件系统统计信息结构
*/
typedef struct {
char mountpoint&#91;256];
char filesystem&#91;32];
char device&#91;256];
unsigned long long total_size_kb;
unsigned long long used_size_kb;
unsigned long long available_size_kb;
double usage_percent;
time_t last_check_time;
int is_mounted;
int readonly;
} filesystem_stats_t;

/**
* 文件系统监控器结构
*/
typedef struct {
filesystem_stats_t filesystems&#91;32];
int fs_count;
time_t last_update_time;
int monitoring_enabled;
} fs_monitor_t;

/**
* 更新文件系统统计信息
*/
int update_filesystem_stats(filesystem_stats_t *fs) {
struct statvfs buf;

if (statvfs(fs->mountpoint, &buf) != 0) {
printf("获取文件系统统计信息失败: %s\n", strerror(errno));
return -1;
}

// 计算空间使用情况
unsigned long long block_size = buf.f_frsize ? buf.f_frsize : buf.f_bsize;
fs->total_size_kb = (unsigned long long)buf.f_blocks * block_size / 1024;
fs->available_size_kb = (unsigned long long)buf.f_bavail * block_size / 1024;
fs->used_size_kb = fs->total_size_kb - (unsigned long long)buf.f_bfree * block_size / 1024;

if (fs->total_size_kb > 0) {
fs->usage_percent = (double)fs->used_size_kb / fs->total_size_kb * 100;
} else {
fs->usage_percent = 0.0;
}

fs->last_check_time = time(NULL);

// 检查是否为只读
fs->readonly = (buf.f_flag & ST_RDONLY) ? 1 : 0;

return 0;
}

/**
* 从/proc/mounts加载文件系统信息
*/
int load_filesystem_info(fs_monitor_t *monitor) {
FILE *fp = setmntent("/proc/mounts", "r");
if (!fp) {
printf("无法读取挂载信息: %s\n", strerror(errno));
return -1;
}

struct mntent *mnt;
int count = 0;

while ((mnt = getmntent(fp)) != NULL && count < 32) {
// 跳过某些系统挂载点
if (strncmp(mnt->mnt_dir, "/proc", 5) == 0 ||
strncmp(mnt->mnt_dir, "/sys", 4) == 0 ||
strncmp(mnt->mnt_dir, "/dev", 4) == 0) {
continue;
}

filesystem_stats_t *fs = &monitor->filesystems&#91;count];
strncpy(fs->mountpoint, mnt->mnt_dir, sizeof(fs->mountpoint) - 1);
fs->mountpoint&#91;sizeof(fs->mountpoint) - 1] = '\0';

strncpy(fs->filesystem, mnt->mnt_type, sizeof(fs->filesystem) - 1);
fs->filesystem&#91;sizeof(fs->filesystem) - 1] = '\0';

strncpy(fs->device, mnt->mnt_fsname, sizeof(fs->device) - 1);
fs->device&#91;sizeof(fs->device) - 1] = '\0';

fs->is_mounted = 1;

// 更新统计信息
update_filesystem_stats(fs);

count++;
}

endmntent(fp);
monitor->fs_count = count;
monitor->last_update_time = time(NULL);

printf("加载了 %d 个文件系统信息\n", count);
return 0;
}

/**
* 显示文件系统统计信息
*/
void show_filesystem_stats(const filesystem_stats_t *fs) {
char time_str&#91;64];
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", localtime(&fs->last_check_time));

printf("文件系统: %s\n", fs->mountpoint);
printf(" 设备: %s\n", fs->device);
printf(" 类型: %s\n", fs->filesystem);
printf(" 总空间: %.2f GB\n", fs->total_size_kb / (1024.0 * 1024.0));
printf(" 已用空间: %.2f GB (%.1f%%)\n",
fs->used_size_kb / (1024.0 * 1024.0), fs->usage_percent);
printf(" 可用空间: %.2f GB\n", fs->available_size_kb / (1024.0 * 1024.0));
printf(" 只读模式: %s\n", fs->readonly ? "是" : "否");
printf(" 最后检查: %s\n", time_str);
}

/**
* 监控文件系统使用情况
*/
int monitor_filesystem_usage(fs_monitor_t *monitor, const char *mountpoint, double threshold) {
for (int i = 0; i < monitor->fs_count; i++) {
filesystem_stats_t *fs = &monitor->filesystems&#91;i];

if (strcmp(fs->mountpoint, mountpoint) == 0) {
// 更新统计信息
update_filesystem_stats(fs);

printf("监控文件系统 %s:\n", mountpoint);
show_filesystem_stats(fs);

// 检查使用率阈值
if (fs->usage_percent > threshold) {
printf("⚠ 警告: 文件系统使用率过高 (%.1f%% > %.1f%%)\n",
fs->usage_percent, threshold);

// 根据使用率严重程度提供建议
if (fs->usage_percent > 95) {
printf(" 🚨 严重: 立即清理磁盘空间\n");
} else if (fs->usage_percent > 90) {
printf(" ⚠ 警告: 尽快清理磁盘空间\n");
} else if (fs->usage_percent > 80) {
printf(" ℹ 提示: 考虑清理磁盘空间\n");
}

return 1; // 超过阈值
} else {
printf("✓ 文件系统使用率正常 (%.1f%%)\n", fs->usage_percent);
return 0; // 正常
}
}
}

printf("未找到指定的挂载点: %s\n", mountpoint);
return -1; // 未找到
}

/**
* 演示文件系统监控和管理
*/
int demo_filesystem_monitoring() {
fs_monitor_t monitor = {0};
uid_t uid = getuid();

printf("=== 文件系统监控和管理演示 ===\n");

// 权限检查
printf("权限检查:\n");
printf(" 当前用户ID: %d\n", uid);
if (uid == 0) {
printf(" ✓ 具有root权限\n");
} else {
printf(" ℹ 普通用户权限(部分功能可能受限)\n");
}

// 加载文件系统信息
printf("\n1. 加载文件系统信息:\n");
if (load_filesystem_info(&monitor) != 0) {
printf("加载文件系统信息失败\n");
return -1;
}

// 显示所有文件系统信息
printf("\n2. 文件系统统计信息:\n");
for (int i = 0; i < monitor.fs_count && i < 5; i++) {
printf("\n文件系统 %d:\n", i + 1);
show_filesystem_stats(&monitor.filesystems&#91;i]);
}

if (monitor.fs_count > 5) {
printf("\n... (还有 %d 个文件系统)\n", monitor.fs_count - 5);
}

// 演示使用率监控
printf("\n3. 文件系统使用率监控演示:\n");

// 监控各个文件系统
for (int i = 0; i < monitor.fs_count && i < 3; i++) {
filesystem_stats_t *fs = &monitor.filesystems&#91;i];
printf("\n监控 %s:\n", fs->mountpoint);

// 不同阈值的监控
monitor_filesystem_usage(&monitor, fs->mountpoint, 80.0); // 警告阈值
monitor_filesystem_usage(&monitor, fs->mountpoint, 90.0); // 严重阈值
}

// 演示umount2在监控中的应用
printf("\n4. umount2在监控中的应用:\n");

// 模拟需要卸载的情况
printf("模拟文件系统维护场景:\n");

for (int i = 0; i < monitor.fs_count && i < 2; i++) {
filesystem_stats_t *fs = &monitor.filesystems&#91;i];
printf("\n检查 %s 是否需要维护:\n", fs->mountpoint);

// 检查使用率和只读状态
if (fs->usage_percent > 95) {
printf(" 文件系统使用率过高 (%.1f%%)\n", fs->usage_percent);
printf(" 建议: 卸载后进行文件系统检查\n");

// 演示不同卸载选项
printf(" 卸载选项:\n");
printf(" 1. 普通卸载: umount2(\"%s\", 0)\n", fs->mountpoint);
printf(" 2. 强制卸载: umount2(\"%s\", MNT_FORCE)\n", fs->mountpoint);
printf(" 3. 延迟卸载: umount2(\"%s\", MNT_DETACH)\n", fs->mountpoint);
} else if (fs->readonly) {
printf(" 文件系统为只读模式\n");
printf(" 可能需要重新挂载为读写模式\n");
} else {
printf(" 文件系统状态正常\n");
}
}

// 显示监控策略和最佳实践
printf("\n=== 文件系统监控策略 ===\n");
printf("1. 监控频率:\n");
printf(" ✓ 关键系统: 每分钟检查\n");
printf(" ✓ 重要数据: 每5分钟检查\n");
printf(" ✓ 一般用途: 每小时检查\n");

printf("\n2. 阈值设置:\n");
printf(" ✓ 警告阈值: 80%% 使用率\n");
printf(" ✓ 严重阈值: 90%% 使用率\n");
printf(" ✓ 紧急阈值: 95%% 使用率\n");

printf("\n3. 响应策略:\n");
printf(" ✓ 自动告警通知\n");
printf(" ✓ 日志记录\n");
printf(" ✓ 自动清理临时文件\n");
printf(" ✓ 邮件/SMS通知\n");

printf("\n4. umount2使用场景:\n");
printf(" ✓ 系统维护时的安全卸载\n");
printf(" ✓ 文件系统检查前的准备\n");
printf(" ✓ 紧急情况下的强制卸载\n");
printf(" ✓ 资源回收时的延迟卸载\n");

// 显示安全考虑
printf("\n=== 安全考虑 ===\n");
printf("1. 权限管理:\n");
printf(" ✓ 文件系统操作需要适当权限\n");
printf(" ✓ 避免普通用户执行危险操作\n");
printf(" ✓ 使用sudo进行权限提升\n");

printf("\n2. 数据安全:\n");
printf(" ✓ 卸载前确保数据已同步\n");
printf(" ✓ 避免强制卸载重要数据\n");
printf(" ✓ 备份重要文件系统\n");

printf("\n3. 系统稳定性:\n");
printf(" ✓ 避免卸载系统关键挂载点\n");
printf(" ✓ 监控卸载操作的影响\n");
printf(" ✓ 准备系统恢复方案\n");

return 0;
}

int main() {
return demo_filesystem_monitoring();
}

umount2 使用注意事项

系统要求:

内核版本: 支持umount2的Linux内核

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

权限要求: 通常需要root权限或适当的挂载权限

架构支持: 支持所有主流架构

卸载标志详解:

0: 普通卸载(默认行为)

MNT_FORCE: 强制卸载(即使文件系统正忙)

MNT_DETACH: 延迟卸载(立即返回,后台清理)

MNT_EXPIRE: 标记为过期(如果未被使用则卸载)

错误处理:

EBUSY: 文件系统正忙,无法卸载

EINVAL: 无效的挂载点

EPERM: 权限不足

EACCES: 访问被拒绝

ENOMEM: 内存不足

安全考虑:

权限验证: 确保具有足够的权限

挂载点验证: 验证挂载点的有效性

使用状态检查: 检查文件系统是否正在使用

数据同步: 确保数据已正确同步

最佳实践:

渐进式卸载: 优先尝试普通卸载,失败后再尝试强制卸载

状态检查: 卸载前后检查系统状态

日志记录: 记录所有卸载操作

错误恢复: 准备适当的错误恢复机制

用户通知: 及时通知用户操作结果

umount2标志详细说明

MNT_FORCE (1):

  • 功能: 强制卸载文件系统

  • 使用场景: 文件系统正忙时的紧急卸载

  • 风险: 可能导致数据丢失或文件系统损坏

MNT_DETACH (2):

  • 功能: 延迟卸载(懒卸载)

  • 使用场景: 立即返回,后台清理资源

  • 优势: 不阻塞调用进程

MNT_EXPIRE (4):

  • 功能: 标记挂载点为过期

  • 使用场景: 如果没有进程使用则卸载

  • 特点: 非阻塞操作

相关函数和工具

系统调用:

1
2
3
4
5
6
7
8
// 基础卸载函数
int umount(const char *target);

// 挂载函数
int mount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags,
const void *data);

命令行工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 普通卸载
umount /mnt/point

# 强制卸载
umount -f /mnt/point

# 延迟卸载
umount -l /mnt/point

# 查看挂载信息
cat /proc/mounts
mount | grep point

常见使用场景

1. 系统维护:

1
2
3
// 维护前安全卸载文件系统
umount2("/mnt/data", 0);

2. 紧急处理:

1
2
3
// 紧急情况下强制卸载
umount2("/mnt/critical", MNT_FORCE);

3. 资源管理:

1
2
3
// 延迟卸载以避免阻塞
umount2("/mnt/temp", MNT_DETACH);

4. 自动化脚本:

1
2
3
4
5
// 批量卸载操作
for (int i = 0; i < count; i++) {
umount2(mountpoints&#91;i], 0);
}

总结

umount2 是Linux系统中强大的文件系统卸载工具,提供了:

灵活的卸载选项: 支持普通、强制、延迟等多种卸载模式

完善的错误处理: 详细的错误码和错误信息

安全的卸载机制: 多种安全检查和保护措施

标准兼容性: 符合POSIX标准,广泛支持

通过合理使用 umount2,可以构建安全可靠的文件系统管理工具。在实际应用中,需要注意权限要求、错误处理和系统稳定性等关键问题,遵循最佳实践确保系统的安全和稳定运行。

data-ad-format="auto" data-full-width-responsive="true">