/* umount_davfs.c: unmount the davfs file system. Copyright (C) 2006, 2007, 2008, 2009 Werner Baumann This file is part of davfs2. davfs2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. davfs2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with davfs2; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #include #ifdef HAVE_LIBINTL_H #include #endif #ifdef HAVE_LOCALE_H #include #endif #include #ifdef HAVE_STDLIB_H #include #endif #include #ifdef HAVE_UNISTD_H #include #endif #include #include "defaults.h" #ifdef ENABLE_NLS #define _(String) gettext(String) #else #define _(String) String #define textdomain(Domainname) #define bindtextdomain(Domainname, Dirname) #endif /* This is lazy programming. All the dirty work is left to the real umount program, while we just sit and wait for mount.davfs to terminate. umount.davfs is a umount helper. It is usually called by umount and makes sure, that umount will not return until mount.davfs has synchronized all files. It first reads the pid-file and identifies the mount.davfs process. Then it calls mount again, with option -i (to not be called again), to do the real unmounting. In a loop it will watch the process list. When the mount.davfs process terminates, it will return. If it can't identify the mount.davfs process, it will call umount -i anyway, but warn the user. */ int main(int argc, char *argv[]) { setuid(getuid()); setgid(getgid()); setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); char *short_options = "Vhflnrv"; static const struct option options[] = { {"version", no_argument, NULL, 'V'}, {"help", no_argument, NULL, 'h'}, {0, 0, 0, 0} }; int o; o = getopt_long(argc, argv, short_options, options, NULL); while (o != -1) { switch (o) { case 'V': printf("%s <%s>\n\n", PACKAGE_STRING, DAV_HOME); printf(_("This is free software; see the source for copying " "conditions. There is NO\n" "warranty; not even for MERCHANTABILITY or FITNESS " "FOR A PARTICULAR PURPOSE.\n")); exit(EXIT_SUCCESS); case 'h': printf(_("Usage:\n" " u%s -V,--version : print version string\n" " u%s -h,--help : print this message\n\n"), PROGRAM_NAME, PROGRAM_NAME); printf(_("To umount a WebDAV-resource don't call u%s directly, " "but use\n" "`umount' instead.\n"), PROGRAM_NAME); printf(_(" umount : umount the WebDAV-resource as " "specified in\n" " /etc/fstab.\n")); exit(EXIT_SUCCESS); case 'f': case 'l': case 'n': case 'r': case 'v': case '?': break; default: error(EXIT_FAILURE, 0, _("unknown error parsing arguments")); } o = getopt_long(argc, argv, short_options, options, NULL); } if (optind > (argc - 1)) error(EXIT_FAILURE, 0, _("missing argument")); if (optind < (argc - 1)) error(EXIT_FAILURE, 0, _("too many arguments")); #ifdef HAVE_CANONICALIZE_FILE_NAME char *mpoint = canonicalize_file_name(argv[optind]); #else char* mpoint=(char*) malloc(1024); if(!mpoint) mpoint = argv[optind]; else realpath(argv[optind], mpoint); #endif if (!mpoint || *mpoint != '/') error(EXIT_FAILURE, 0, _("can't determine mount point")); char *m = mpoint; while (*m == '/') m++; char *mp = ne_strdup(m); m = strchr(mp, '/'); while (m) { *m = '-'; m = strchr(mp, '/'); } char *pidfile = ne_concat(DAV_SYS_RUN, "/", mp, ".pid", NULL); free(mp); char *umount_command = ne_concat("umount -i ", mpoint, NULL); char *pid = NULL; FILE *file = fopen(pidfile, "r"); if (!file || fscanf(file, "%a[0-9]", &pid) != 1 || !pid) { error(0, 0, _("\n" " can't read PID from file %s;\n" " trying to unmount anyway;\n" " please wait for %s to terminate"), pidfile, PROGRAM_NAME); return system(umount_command); } fclose(file); char *ps_command = ne_concat("ps -p ", pid, NULL); FILE *ps_in = popen(ps_command, "r"); if (!ps_in) { error(0, 0, _("\n" " can't read process list;\n" " trying to unmount anyway;\n" " please wait for %s to terminate"), PROGRAM_NAME); return system(umount_command); } int found = 0; size_t n = 0; char *ps_line = NULL; while (!found && getline(&ps_line, &n, ps_in) > 0) found = (strstr(ps_line, pid) && strstr(ps_line, PROGRAM_NAME)); pclose(ps_in); if (!found) { error(0, 0, _("\n" " can't find %s-process with pid %s;\n" " trying to unmount anyway.\n" " you propably have to remove %s manually"), PROGRAM_NAME, pid, pidfile); return system(umount_command); } if (system(umount_command) != 0) exit(EXIT_FAILURE); printf(_("%s: waiting while %s (pid %s) synchronizes the cache ."), argv[0], PROGRAM_NAME, pid); fflush(stdout); while (found) { sleep(3); printf("."); fflush(stdout); ps_in = popen(ps_command, "r"); if (!ps_in) { printf("\n"); error(EXIT_FAILURE, 0, _("an error occured while waiting; " "please wait for %s to terminate"), PROGRAM_NAME); } found = 0; while (!found && getline(&ps_line, &n, ps_in) > 0) found = (strstr(ps_line, pid) && strstr(ps_line, PROGRAM_NAME)); pclose(ps_in); } printf(" OK\n"); return 0; }