Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

mntd_volume.c

00001 /***************************************************************************
00002  * CVSID: $Id: mntd_volume.c,v 1.34 2004/05/26 19:12:40 stefanb Exp $
00003  *
00004  * mntd_volume.c : Volume handler for MNT daemon
00005  *
00006  * Copyright (C) 2004 Stefan Bambach, <stefan@bambach.biz>
00007  *
00008  * Licensed under the GNU General Public License 2.0
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  **************************************************************************/
00025  
00026 #ifdef HAVE_CONFIG_H
00027 #  include <config.h>
00028 #endif
00029 
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <glib.h>
00034 #include <dbus/dbus.h>
00035 #include <dbus/dbus-glib.h>
00036 
00037 #include <libmnt/libmnt.h>   /* for common defines etc. */
00038 #include "mntd_dir.h"
00039 #include "mntd_mount.h"
00040 #include "mntd_volume.h"
00041 #include "mntd_dbus_manager.h"
00042 #include "errmanager.h"
00043 
00044 
00045 /* Private Methods */
00046 int mntd_volume_init(PVOLUME pv);
00047 void mntd_volume_destroy(PVOLUME pv);
00048 int mntd_volume_set_device(PVOLUME pv, const char *device);
00049 char *mntd_volume_get_device(PVOLUME pv);
00050 void mntd_volume_to_string(PVOLUME pv);
00051 int mntd_volume_set_mntpnt(PVOLUME pv, const char *mntpnt);
00052 char *mntd_volume_get_mntpnt(PVOLUME pv);
00053 int mntd_volume_set_fstype(PVOLUME pv, const char *fstype);
00054 char *mntd_volume_get_fstype(PVOLUME pv);
00055 int mntd_volume_mount(PVOLUME pv);
00056 int mntd_volume_umount(PVOLUME pv);
00057 char *mntd_volume_g_build_mntpnt(PVOLUME pv, const char *base);
00058 int mntd_volume_helper_base_is_in_mntpath(const char *base, const char *mntpnt);
00059 int mntd_volume_is_in_mntpath(PVOLUME pv);
00060 int mntd_volume_send_signal(PVOLUME pv, int what);
00061 int mntd_volume_send_mounted(PVOLUME pv);
00062 int mntd_volume_send_unmounted(PVOLUME pv);
00063 
00064 
00080 PVOLUME new_Volume(const char *udi, const char *base)
00081 {
00082     PVOLUME pv = NULL;
00083     char *s_udi = NULL;
00084     char *s_base = NULL;
00085     
00086     //MSG_DEBUG("new_Volume(%s) called", udi);
00087     
00088     g_assert(udi!=NULL);
00089     g_assert(base!=NULL);
00090     
00091     // get mem for volume object
00092     pv = (PVOLUME) malloc(sizeof(VOLUME));
00093     if (pv==NULL) {
00094         return NULL;
00095     }
00096     
00097     // clear structure memory
00098     memset(pv, 0, sizeof(VOLUME));
00099     
00100     // setting udi for this volume
00101     s_udi = strdup(udi);
00102     if (s_udi == NULL) {
00103         goto error;
00104     }
00105     pv->udi = s_udi;
00106     
00107     // setting base mount directory
00108     s_base = strdup(base);
00109     if (s_base == NULL) {
00110         goto error;
00111     }
00112     pv->base = s_base;
00113     
00114     // setting methods
00115     pv->init = mntd_volume_init;
00116     pv->_send_signal = mntd_volume_send_signal;
00117     pv->_send_mounted = mntd_volume_send_mounted;
00118     pv->_send_unmounted = mntd_volume_send_unmounted;
00119     pv->destroy = mntd_volume_destroy;
00120     pv->set_device = mntd_volume_set_device;
00121     pv->get_device = mntd_volume_get_device;
00122     pv->to_string = mntd_volume_to_string;
00123     pv->set_mntpnt = mntd_volume_set_mntpnt;
00124     pv->get_mntpnt = mntd_volume_get_mntpnt;
00125     pv->set_fstype = mntd_volume_set_fstype;
00126     pv->get_fstype = mntd_volume_get_fstype;
00127     pv->mount = mntd_volume_mount;
00128     pv->umount = mntd_volume_umount;
00129     pv->is_in_mntpath = mntd_volume_is_in_mntpath;
00130     
00131     // call constructor
00132     if(pv->init(pv) == -1) {
00133         goto error;
00134     }
00135     
00136     // alright, return volume object
00137     goto exit;
00138     
00139 error:
00140     pv->destroy(pv);
00141     pv = NULL;
00142     
00143 exit:
00144     return pv;
00145 }
00146 
00147 
00154 int mntd_volume_init(PVOLUME pv)
00155 {
00156     g_assert(pv!=NULL);
00157     
00158     //MSG_DEBUG("init(%s) called", pv->udi);
00159 
00160     pv->device = NULL;
00161     pv->mntpnt = NULL;
00162     pv->fstype = NULL;
00163     pv->last_signal = SIGNAL_UNKNOWN;
00164     
00165     return 0;
00166 }
00167 
00168 
00173 void mntd_volume_destroy(PVOLUME pv)
00174 {
00175     g_assert(pv!=NULL);
00176     
00177     //MSG_DEBUG("mntd_volume_destroy(%p) called (key='%s')", pv, pv->udi);
00178     
00179     // umount it now
00180     pv->umount(pv);
00181     
00182     // free udi memory
00183     if (pv->udi != NULL) {
00184         free(pv->udi);
00185         pv->udi = NULL;
00186     }
00187     
00188     // free base memory
00189     if (pv->base != NULL) {
00190         free(pv->base);
00191         pv->base = NULL;
00192     }
00193     
00194     // free device memory
00195     if (pv->device != NULL) {
00196         free(pv->device);
00197         pv->device = NULL;
00198     }
00199     
00200     // free mntpnt memory
00201     if (pv->mntpnt != NULL) {
00202         free(pv->mntpnt);
00203         pv->mntpnt = NULL;
00204     }
00205     
00206     // free fstype memory
00207     if (pv->fstype != NULL) {
00208         free(pv->fstype);
00209         pv->fstype = NULL;
00210     }
00211     
00212     // free volume manager structure
00213     memset(pv, 0, sizeof(VOLUME));
00214     free(pv);
00215     
00216     return;
00217 }
00218 
00219 
00225 void
00226 mntd_volume_to_string(PVOLUME pv)
00227 {
00228     //MSG_DEBUG("mntd_volume_to_string(%p) called", pv);
00229 
00230     MSG_DEBUG("------------------------------------------------------");
00231     MSG_DEBUG("udi:        %s", pv->udi);
00232     MSG_DEBUG("base:       %s", pv->base);
00233     MSG_DEBUG("device:     %s", pv->device);
00234     MSG_DEBUG("mntpnt:     %s", pv->mntpnt);
00235     MSG_DEBUG("fstype:     %s", pv->fstype);
00236     
00237     return;
00238 }
00239 
00240 
00248 int
00249 mntd_volume_set_device(PVOLUME pv, const char *device)
00250 {
00251     char *s_device = NULL;
00252     
00253     //MSG_DEBUG("set_device(%s) called", device);
00254 
00255     g_assert(pv!=NULL);
00256 
00257     if (device == NULL) {
00258         if (pv->device != NULL) {
00259             free(pv->device);
00260             pv->device = NULL;
00261         }
00262         return 0;
00263     }
00264     
00265     // return OK, if nothing to change
00266     if (pv->device != NULL) {
00267         if (strcmp(device, pv->device)==0) {
00268             return 0;
00269         }
00270     }
00271     
00272     s_device = strdup(device);
00273     if (s_device == NULL) {
00274         return -1;
00275     }
00276     
00277     if (pv->device != NULL) {
00278         free(pv->device);
00279         pv->device = NULL;
00280     }
00281     
00282     pv->device = s_device;
00283     
00284     MSG_DEBUG("Set device to '%s' for '%s'", s_device, pv->udi);
00285     
00286     // device found, so mount it now
00287     pv->mount(pv);
00288     
00289     return 0;
00290 }
00291 
00292 
00302 char *
00303 mntd_volume_get_device(PVOLUME pv)
00304 {
00305     g_assert(pv!=NULL);
00306     
00307     if (pv->device != NULL) {
00308         return strdup(pv->device);
00309     }
00310     
00311     return NULL;
00312 }
00313 
00314 
00322 int
00323 mntd_volume_set_mntpnt(PVOLUME pv, const char *mntpnt)
00324 {
00325     char *s_mntpnt = NULL;
00326     
00327     //MSG_DEBUG("set_mntpnt(%s) called", mntpnt);
00328 
00329     g_assert(pv!=NULL);
00330 
00331     if (mntpnt == NULL) {
00332         if (pv->mntpnt != NULL) {
00333             
00334             MSG_DEBUG("Remove mount point '%s' ('%s')", pv->mntpnt, pv->udi);
00335             
00336             // sending signal
00337             pv->_send_signal(pv, SIGNAL_UNMOUNTED);
00338 
00339             free(pv->mntpnt);
00340             pv->mntpnt = NULL;
00341         }
00342         return 0;
00343     }
00344     
00345     // return OK, if nothing to change
00346     if (pv->mntpnt != NULL) {
00347         if (strcmp(mntpnt, pv->mntpnt)==0) {
00348             return 0;
00349         }
00350     }
00351     
00352     s_mntpnt = strdup(mntpnt);
00353     if (s_mntpnt == NULL) {
00354         return -1;
00355     }
00356     
00357     if (pv->mntpnt != NULL) {
00358         
00359         MSG_DEBUG("Change mount point '%s' ('%s')", pv->mntpnt, pv->udi);
00360         
00361         free(pv->mntpnt);
00362         pv->mntpnt = NULL;
00363     }
00364     
00365     pv->mntpnt = s_mntpnt;
00366     
00367     MSG_DEBUG("Set mount point to '%s' ('%s')", s_mntpnt, pv->udi);
00368     
00369     // sending signal
00370     pv->_send_signal(pv, SIGNAL_UNKNOWN);
00371     
00372     return 0;
00373 }
00374 
00375 
00385 char *
00386 mntd_volume_get_mntpnt(PVOLUME pv)
00387 {
00388     g_assert(pv!=NULL);
00389     
00390     if (pv->mntpnt != NULL) {
00391         return strdup(pv->mntpnt);
00392     }
00393     
00394     return NULL;
00395 }
00396 
00397 
00405 int
00406 mntd_volume_set_fstype(PVOLUME pv, const char *fstype)
00407 {
00408     char *s_fstype = NULL;
00409     
00410     //MSG_DEBUG("set_fstype(%s) called", fstype);
00411 
00412     g_assert(pv!=NULL);
00413 
00414     if (fstype == NULL) {
00415         if (pv->fstype != NULL) {
00416             free(pv->fstype);
00417             pv->fstype = NULL;
00418         }
00419         return 0;
00420     }
00421     
00422     // return OK, if nothing to change
00423     if (pv->fstype != NULL) {
00424         if (strcmp(fstype, pv->fstype)==0) {
00425             return 0;
00426         }
00427     }
00428     
00429     s_fstype = strdup(fstype);
00430     if (s_fstype == NULL) {
00431         return -1;
00432     }
00433     
00434     if (pv->fstype != NULL) {
00435         free(pv->fstype);
00436         pv->fstype = NULL;
00437     }
00438     
00439     pv->fstype = s_fstype;
00440 
00441     //MSG_DEBUG("Set filesystem type to '%s' for '%s'", s_fstype, pv->udi);
00442     
00443     return 0;
00444 }
00445 
00446 
00456 char *
00457 mntd_volume_get_fstype(PVOLUME pv)
00458 {
00459     g_assert(pv!=NULL);
00460     
00461     if (pv->fstype != NULL) {
00462         return strdup(pv->fstype);
00463     }
00464     
00465     return NULL;
00466 }
00467 
00468 
00475 int
00476 mntd_volume_mount(PVOLUME pv)
00477 {
00478     char *path = NULL;
00479     int error=0;
00480     int res = 0;
00481     
00482     //MSG_DEBUG("mntd_volume_mount(%p) called", pv);
00483 
00484     g_assert(pv!=NULL);
00485     g_assert(pv->device!=NULL);
00486     
00487     // check for error
00488     if (pv->base == NULL) {
00489         MSG_ERR("base mountpoint path is not configured");
00490         goto error;
00491     }
00492     
00493     // check for already mounted volume
00494     if (pv->mntpnt != NULL) {
00495         MSG_INF("'%s' already mounted on '%s'.", pv->device, pv->mntpnt);
00496         goto error;
00497     }
00498     
00499     // build mount point path
00500     path = mntd_volume_g_build_mntpnt(pv, pv->base);
00501     if (path == NULL) {
00502         MSG_ERR("Out of memory");
00503         goto error;
00504     }
00505     
00506     // create mount point
00507     mntd_dir_rmdirs(path);
00508     mntd_dir_mkdirs(path, 0664, &error);
00509     if (!mntd_dir_is_dir(path)) {
00510         MSG_ERR("Couldn't create '%s' (%d)", path, error);
00511         goto error;
00512     }
00513 
00514     // mounting device
00515     res = mntd_mount_mount("-o ro", pv->device, path);
00516     if (res != 0) {
00517         MSG_INF("Couldn't mount '%s' on '%s'. Perhaps wrong filesystem, or no filesystem on it (e.g. extended partition, ...).", pv->device, path);
00518         // error
00519         goto error;
00520     }
00521     
00522     // set mntpnt, so nested calls to GetMntPnt() will work
00523     pv->set_mntpnt(pv, path);
00524     
00525     // TODO: Test for readable / writeable
00526     ;
00527     
00528     MSG_INF("Mounted '%s' on '%s'.", pv->device, path);
00529     
00530     // send signal to processes listing to dbus
00531     pv->_send_signal(pv, SIGNAL_MOUNTED);
00532     
00533     goto cleanup;
00534     
00535 error:
00536     // try to remove mount point
00537     mntd_dir_remove(path);
00538     // error
00539     res = -1;
00540     
00541 cleanup:
00542     if (path != NULL) {
00543         free(path);
00544         path = NULL;
00545     }
00546     
00547     return res;
00548 }
00549 
00550 
00562 int
00563 mntd_volume_umount(PVOLUME pv)
00564 {
00565     int res = 0;
00566     char *mntpnt = NULL;
00567     int status = 0;
00568     
00569     //MSG_DEBUG("mntd_volume_umount(%p) called", pv);
00570 
00571     g_assert(pv!=NULL);
00572     
00573     // is mounted by mntd or in configured mount path ?
00574     if (pv->is_in_mntpath(pv)) {
00575         // mount point configured ?
00576         if (pv->mntpnt != NULL) {
00577             mntpnt = pv->get_mntpnt(pv);
00578             if (mntpnt != NULL) {
00579                 // unmount it
00580                 status = mntd_mount_umount("", mntpnt);
00581                 if (status != 0) {
00582                     MSG_ERR("Couldn't unmount '%s' on '%s'.", pv->device, mntpnt);
00583                     goto error;
00584                 } else {
00585                     MSG_INF("Unmounted '%s' on '%s'.", pv->device, mntpnt);
00586                     
00587                     // send signal to processes listing to dbus
00588                     pv->_send_signal(pv, SIGNAL_UNMOUNTED);
00589                 }
00590                 
00591                 // try to remove mount point
00592                 mntd_dir_remove(mntpnt);
00593 
00594                 // set mntpnt, so nested calls to GetMntPnt() will work
00595                 pv->set_mntpnt(pv, NULL);
00596                 pv->set_fstype(pv, NULL);
00597                 
00598             } else {
00599                 MSG_ERR("mntpnt==NULL for '%s' on '%s'", pv->device, pv->udi);
00600                 goto error;
00601             }
00602         } else {
00603             MSG_ERR("Volume (udi='%s') on device '%s' mounted by mntd has mntpnt==NULL !", pv->udi, pv->device);
00604             goto error;
00605         }
00606     } else {
00607         MSG_INF("Device '%s' at '%s' is not mounted by mntd -> do not unmount it.", pv->device, pv->mntpnt);
00608         goto error;
00609     }
00610     
00611     goto cleanup;
00612     
00613 error:
00614     res = -1;
00615 
00616 cleanup:
00617     if (mntpnt != NULL) {
00618         free(mntpnt);
00619         mntpnt = NULL;
00620     }
00621     
00622     return res;
00623 }
00624 
00625 
00633 char *
00634 mntd_volume_g_build_mntpnt(PVOLUME pv, const char *base)
00635 {
00636     gchar *res = NULL;
00637     gchar *name = NULL;
00638     
00639     g_assert(pv!=NULL);
00640     g_assert(base!=NULL);
00641     
00642     if (pv->device == NULL) {
00643         goto error;
00644     }
00645     
00646     name = g_path_get_basename(pv->device);
00647     if(name==NULL) {
00648         goto error;
00649     }
00650     
00651     if (g_path_is_absolute((gchar *)base)) {
00652         res = g_build_path(G_DIR_SEPARATOR_S, (gchar *)base, name, NULL);
00653     } else {
00654         MSG_WARNING("basepath for mount point have to be absolute (adding DIRSEP) -> check your config");
00655         res = g_build_path(G_DIR_SEPARATOR_S, G_DIR_SEPARATOR_S, (gchar *)base, name, NULL);
00656     }
00657     if (res==NULL) {
00658         goto error;
00659     }
00660     
00661     goto cleanup;
00662     
00663 error:
00664     res = NULL;
00665     
00666 cleanup:
00667     if (name!=NULL) {
00668         g_free(name);
00669         name = NULL;
00670     }
00671     
00672     return (char *)res;
00673 }
00674 
00675 
00683 int
00684 mntd_volume_helper_base_is_in_mntpath(const char *base, const char *mntpnt)
00685 {
00686     int res = TRUE;
00687     int abs_base = 0;
00688     int abs_mntpnt = 0;
00689     gchar *path_base = NULL;
00690     gchar *path_mntpnt = NULL;
00691     
00692     g_assert(base!=NULL);
00693     g_assert(mntpnt!=NULL);
00694 
00695     // check for absolute pathes
00696     abs_base = g_path_is_absolute((gchar *)base);
00697     abs_mntpnt = g_path_is_absolute((gchar *)mntpnt);
00698     if (abs_base != abs_mntpnt) {
00699         goto no;
00700     }
00701     
00702     // check for substring
00703     path_base = g_build_path(G_DIR_SEPARATOR_S, (gchar *)base, NULL);
00704     if (path_base == NULL) {
00705         goto no;
00706     }
00707     path_mntpnt = g_build_path(G_DIR_SEPARATOR_S, (gchar *)mntpnt, NULL);
00708     if (path_mntpnt == NULL) {
00709         goto no;
00710     }
00711     if (!g_str_has_prefix(path_mntpnt, path_base)) {
00712         goto no;
00713     }
00714     
00715     goto cleanup;
00716     
00717 no:
00718     res = FALSE;
00719     
00720 cleanup:
00721     if (path_base != NULL) {
00722         g_free(path_base);
00723         path_base = NULL;
00724     }
00725     if (path_mntpnt != NULL) {
00726         g_free(path_mntpnt);
00727         path_mntpnt = NULL;
00728     }
00729     //MSG_DEBUG("mntd_volume_helper_base_is_in_mntpath('%s', '%s') returned %s", base, mntpnt, (res==TRUE) ? "true" : "false");
00730 
00731     return res;
00732 }
00733 
00734 
00741 int
00742 mntd_volume_is_in_mntpath(PVOLUME pv)
00743 {
00744     g_assert(pv!=NULL);
00745     
00746     if ((pv->mntpnt==NULL) || (pv->base==NULL)) {
00747         return FALSE;
00748     }
00749     
00750     return mntd_volume_helper_base_is_in_mntpath(pv->base, pv->mntpnt);
00751 }
00752 
00753 
00760 int
00761 mntd_volume_send_mounted(PVOLUME pv)
00762 {
00763     g_assert(pv!=NULL);
00764     g_assert(pv->udi!=NULL);
00765     g_assert(pv->mntpnt!=NULL);
00766 
00767     if (pv->last_signal!=SIGNAL_MOUNTED) {
00768         pv->last_signal = SIGNAL_MOUNTED;
00769         MSG_DEBUG("sending 'mounted' signal for '%s' ('%s') ...", pv->mntpnt, pv->udi);
00770         mntd_dbus_manager_send_signal_volume_mounted(pv);
00771     }
00772 
00773     return TRUE;
00774 }
00775 
00776 
00783 int
00784 mntd_volume_send_unmounted(PVOLUME pv)
00785 {
00786     g_assert(pv!=NULL);
00787     g_assert(pv->udi!=NULL);
00788     g_assert(pv->mntpnt!=NULL);
00789 
00790     if (pv->last_signal!=SIGNAL_UNMOUNTED) {
00791         pv->last_signal = SIGNAL_UNMOUNTED;
00792         MSG_DEBUG("sending 'unmounted' signal for '%s' ('%s') ...", pv->mntpnt, pv->udi);
00793         mntd_dbus_manager_send_signal_volume_unmounted(pv);
00794     }
00795 
00796     return TRUE;
00797 }
00798 
00799 
00809 int
00810 mntd_volume_send_signal(PVOLUME pv, int what)
00811 {
00812     g_assert(pv!=NULL);
00813     g_assert(pv->udi!=NULL);
00814     
00815     // called from mount()
00816     if (what==SIGNAL_MOUNTED) {
00817         pv->_send_mounted(pv);
00818     
00819     // called from unmount()
00820     } else if (what==SIGNAL_UNMOUNTED) {
00821         pv->_send_unmounted(pv);
00822     
00823     // called from somewhere else
00824     } else {
00825         if (pv->is_in_mntpath(pv)) {
00826             if (pv->mntpnt!=NULL) {
00827                 pv->_send_mounted(pv);
00828             } else {
00829                 pv->_send_unmounted(pv);
00830             }
00831         }
00832     }
00833     
00834     return TRUE;
00835 }
00836 
00837 

Generated on Thu May 27 23:27:28 2004 for Mntd by doxygen 1.3.5