umount2 函数详解 Link to heading
1. 函数介绍 Link to heading
umount2
是Linux系统调用,用于卸载文件系统。它是 umount
函数的增强版本,支持更多的卸载选项和标志。通过 umount2
,程序可以更精细地控制文件系统的卸载过程,包括强制卸载、延迟卸载等高级功能。
2. 函数原型 Link to heading
#include <sys/mount.h>
int umount2(const char *target, int flags);
3. 功能 Link to heading
umount2
卸载指定挂载点的文件系统,并支持多种卸载标志来控制卸载行为。它可以处理繁忙的文件系统、只读文件系统等情况,提供更灵活的卸载选项。
4. 参数 Link to heading
- *const char target: 要卸载的文件系统挂载点路径
- int flags: 卸载标志,控制卸载行为
5. 返回值 Link to heading
- 成功: 返回0
- 失败: 返回-1,并设置errno
6. 相似函数,或关联函数 Link to heading
- umount: 基础卸载函数(等同于umount2(target, 0))
- mount: 挂载文件系统
- getmntent: 获取挂载信息
- /proc/mounts: 挂载信息文件
7. 示例代码 Link to heading
示例1:基础umount2使用 Link to heading
#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:文件系统挂载和卸载管理 Link to heading
#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[256];
char filesystem[32];
char device[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[sizeof(manager->mountpoint) - 1] = '\0';
strncpy(manager->device, device, sizeof(manager->device) - 1);
manager->device[sizeof(manager->device) - 1] = '\0';
strncpy(manager->filesystem, filesystem, sizeof(manager->filesystem) - 1);
manager->filesystem[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:安全卸载工具 Link to heading
#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[256];
int attempts;
int success;
int force_used;
int detach_used;
int final_status;
char error_message[256];
} safe_unmount_result_t;
/**
* 检查挂载点是否正在使用
*/
int is_mountpoint_busy(const char *mountpoint) {
// 检查是否有进程在使用该挂载点
char command[512];
snprintf(command, sizeof(command), "lsof %s 2>/dev/null | wc -l", mountpoint);
FILE *fp = popen(command, "r");
if (fp) {
char buffer[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[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[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[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:批量卸载管理器 Link to heading
#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[256];
char filesystem[32];
char device[256];
int selected_for_unmount;
int unmount_result;
char result_message[128];
} batch_unmount_entry_t;
/**
* 批量卸载管理器结构
*/
typedef struct {
batch_unmount_entry_t entries[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[count];
strncpy(entry->mountpoint, mnt->mnt_dir, sizeof(entry->mountpoint) - 1);
entry->mountpoint[sizeof(entry->mountpoint) - 1] = '\0';
strncpy(entry->filesystem, mnt->mnt_type, sizeof(entry->filesystem) - 1);
entry->filesystem[sizeof(entry->filesystem) - 1] = '\0';
strncpy(entry->device, mnt->mnt_fsname, sizeof(entry->device) - 1);
entry->device[sizeof(entry->device) - 1] = '\0';
entry->selected_for_unmount = 0;
entry->unmount_result = 0;
entry->result_message[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[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[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[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[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[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[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[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[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:文件系统监控和管理 Link to heading
#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[256];
char filesystem[32];
char device[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[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[count];
strncpy(fs->mountpoint, mnt->mnt_dir, sizeof(fs->mountpoint) - 1);
fs->mountpoint[sizeof(fs->mountpoint) - 1] = '\0';
strncpy(fs->filesystem, mnt->mnt_type, sizeof(fs->filesystem) - 1);
fs->filesystem[sizeof(fs->filesystem) - 1] = '\0';
strncpy(fs->device, mnt->mnt_fsname, sizeof(fs->device) - 1);
fs->device[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[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[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[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[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[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 使用注意事项 Link to heading
系统要求: Link to heading
- 内核版本: 支持umount2的Linux内核
- 权限要求: 通常需要root权限或适当的挂载权限
- 架构支持: 支持所有主流架构
卸载标志详解: Link to heading
- 0: 普通卸载(默认行为)
- MNT_FORCE: 强制卸载(即使文件系统正忙)
- MNT_DETACH: 延迟卸载(立即返回,后台清理)
- MNT_EXPIRE: 标记为过期(如果未被使用则卸载)
错误处理: Link to heading
- EBUSY: 文件系统正忙,无法卸载
- EINVAL: 无效的挂载点
- EPERM: 权限不足
- EACCES: 访问被拒绝
- ENOMEM: 内存不足
安全考虑: Link to heading
- 权限验证: 确保具有足够的权限
- 挂载点验证: 验证挂载点的有效性
- 使用状态检查: 检查文件系统是否正在使用
- 数据同步: 确保数据已正确同步
最佳实践: Link to heading
- 渐进式卸载: 优先尝试普通卸载,失败后再尝试强制卸载
- 状态检查: 卸载前后检查系统状态
- 日志记录: 记录所有卸载操作
- 错误恢复: 准备适当的错误恢复机制
- 用户通知: 及时通知用户操作结果
umount2标志详细说明 Link to heading
MNT_FORCE (1): Link to heading
- 功能: 强制卸载文件系统
- 使用场景: 文件系统正忙时的紧急卸载
- 风险: 可能导致数据丢失或文件系统损坏
MNT_DETACH (2): Link to heading
- 功能: 延迟卸载(懒卸载)
- 使用场景: 立即返回,后台清理资源
- 优势: 不阻塞调用进程
MNT_EXPIRE (4): Link to heading
- 功能: 标记挂载点为过期
- 使用场景: 如果没有进程使用则卸载
- 特点: 非阻塞操作
相关函数和工具 Link to heading
系统调用: Link to heading
// 基础卸载函数
int umount(const char *target);
// 挂载函数
int mount(const char *source, const char *target,
const char *filesystemtype, unsigned long mountflags,
const void *data);
命令行工具: Link to heading
# 普通卸载
umount /mnt/point
# 强制卸载
umount -f /mnt/point
# 延迟卸载
umount -l /mnt/point
# 查看挂载信息
cat /proc/mounts
mount | grep point
常见使用场景 Link to heading
1. 系统维护: Link to heading
// 维护前安全卸载文件系统
umount2("/mnt/data", 0);
2. 紧急处理: Link to heading
// 紧急情况下强制卸载
umount2("/mnt/critical", MNT_FORCE);
3. 资源管理: Link to heading
// 延迟卸载以避免阻塞
umount2("/mnt/temp", MNT_DETACH);
4. 自动化脚本: Link to heading
// 批量卸载操作
for (int i = 0; i < count; i++) {
umount2(mountpoints[i], 0);
}
总结 Link to heading
umount2
是Linux系统中强大的文件系统卸载工具,提供了:
- 灵活的卸载选项: 支持普通、强制、延迟等多种卸载模式
- 完善的错误处理: 详细的错误码和错误信息
- 安全的卸载机制: 多种安全检查和保护措施
- 标准兼容性: 符合POSIX标准,广泛支持
通过合理使用 umount2
,可以构建安全可靠的文件系统管理工具。在实际应用中,需要注意权限要求、错误处理和系统稳定性等关键问题,遵循最佳实践确保系统的安全和稳定运行。