glusterfs
1/*
2Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
3This file is part of GlusterFS.
4
5This file is licensed to you under your choice of the GNU Lesser
6General Public License, version 3 or any later version (LGPLv3 or
7later), or the GNU General Public License, version 2 (GPLv2), in all
8cases as published by the Free Software Foundation.
9*/
10
11#ifndef _CONFIG_H12#define _CONFIG_H13#include "config.h"14#endif15
16#include <stdlib.h>17#include <stdio.h>18#include <unistd.h>19#include <errno.h>20#include <dirent.h>21#include <limits.h>22#include <sys/types.h>23#include <sys/stat.h>24#include <sys/mount.h>25
26#include "glusterfs/globals.h"27#include "glusterfs/glusterfs.h"28#include "glusterfs/logging.h"29#include "glusterfs/syscall.h"30#include "glusterfs/mem-types.h"31
32static void33usage(void)34{
35fprintf(stderr, "Usage: umountd [-d dev] [-t timeout] [-r] path\n");36exit(EXIT_FAILURE);37}
38
39static int40sanity_check(char *path, dev_t *devp)41{
42struct stat st;43struct stat parent_st;44int ret;45char pathtmp[PATH_MAX];46char *parent;47
48if (path == NULL)49usage();50
51if ((ret = stat(path, &st)) != 0) {52switch (errno) {53case ENOTCONN:54/* volume is stopped */55break;56default:57gf_log("umountd", GF_LOG_ERROR, "Cannot access %s: %s\n", path,58strerror(errno));59goto out;60}61}62
63/* If dev was not specified, get it from path */64if (*devp == -1 && ret == 0)65*devp = st.st_dev;66
67snprintf(pathtmp, PATH_MAX, "%s", path);68parent = dirname(pathtmp);69
70if (stat(parent, &parent_st) != 0) {71gf_log("umountd", GF_LOG_ERROR, "Cannot access %s: %s\n", parent,72strerror(errno));73goto out;74}75
76if (st.st_dev == parent_st.st_dev) {77gf_log("umountd", GF_LOG_ERROR, "No filesystem mounted on %s\n", path);78goto out;79}80
81ret = 0;82
83out:84return ret;85}
86
87static void88log_rotate(int signum)89{
90gf_log_logrotate(1);91
92if (signal(SIGHUP, *log_rotate) == SIG_ERR) {93gf_log("umountd", GF_LOG_ERROR, "signal () failed");94exit(EXIT_FAILURE);95}96
97return;98}
99
100static int101logging_init(void)102{
103glusterfs_ctx_t *ctx;104char log_file[PATH_MAX];105int ret = -1;106
107ctx = glusterfs_ctx_new();108if (!ctx) {109fprintf(stderr, "glusterfs_ctx_new failed\n");110goto out;111}112
113ret = glusterfs_globals_init(ctx);114if (ret) {115fprintf(stderr, "glusterfs_globals_init failed\n");116goto out;117}118
119THIS->ctx = ctx;120xlator_mem_acct_init(THIS, gf_common_mt_end);121
122snprintf(log_file, PATH_MAX, "%s/umountd.log", DEFAULT_LOG_FILE_DIRECTORY);123
124ret = gf_log_init(ctx, log_file, "umountd");125if (ret) {126fprintf(stderr, "gf_log_init failed\n");127goto out;128}129
130if (signal(SIGHUP, *log_rotate) == SIG_ERR) {131gf_log("umountd", GF_LOG_ERROR, "signal () failed");132goto out;133}134
135ret = 0;136out:137return ret;138}
139
140static int141umountd_async(char *path, dev_t dev, int frmdir, int timeout)142{
143int ret = -1;144struct stat stbuf = {1450,146};147int unmount_ret = 0;148
149do {150unmount_ret = unmount(path, 0);151if (unmount_ret == 0)152gf_log("umountd", GF_LOG_INFO, "Unmounted %s", path);153
154if (unmount_ret != 0 && errno != EBUSY) {155gf_log("umountd", GF_LOG_WARNING, "umount %s failed: %s", path,156strerror(errno));157}158
159ret = sys_lstat(path, &stbuf);160if (ret != 0) {161gf_log("umountd", GF_LOG_WARNING, "Cannot stat device from %s",162path, strerror(errno));163break;164}165
166if (stbuf.st_dev != dev) {167if (unmount_ret != 0)168gf_log("umountd", GF_LOG_INFO,169"device mismatch "170"(expect %lld, found %lld), "171"someone else unmounted %s",172dev, stbuf.st_dev, path);173ret = 0;174break;175}176
177sleep(timeout);178} while (1 /*CONSTCOND*/);179
180if (ret) {181gf_log("umountd", GF_LOG_ERROR, "Asynchronous unmount of %s failed: %s",182path, strerror(errno));183} else {184if (frmdir) {185ret = rmdir(path);186if (ret)187gf_log("umountd", GF_LOG_WARNING, "rmdir %s failed: %s", path,188strerror(errno));189else190gf_log("umountd", GF_LOG_INFO, "Removed %s", path);191}192}193
194return ret;195}
196
197int
198main(int argc, char **argv)199{
200char *path = NULL;201dev_t dev = -1;202int frmdir = 0;203int timeout = 30;204int f;205
206while ((f = getopt(argc, argv, "d:rt:")) != -1) {207switch (f) {208case 'p':209path = optarg;210break;211case 'd':212dev = strtoll(optarg, NULL, 10);213break;214case 't':215timeout = atoi(optarg);216break;217case 'r':218frmdir = 1;219break;220default:221usage();222break;223}224}225
226argc -= optind;227argv += optind;228
229if (argc != 1)230usage();231
232path = argv[0];233
234if (logging_init() != 0)235exit(EXIT_FAILURE);236
237if (sanity_check(path, &dev) != 0)238exit(EXIT_FAILURE);239
240if (daemon(0, 0) != 0)241exit(EXIT_FAILURE);242
243if (umountd_async(path, dev, frmdir, timeout) != 0)244exit(EXIT_FAILURE);245
246return EXIT_SUCCESS;247}
248