/***************************************************************************
* CVSID: $Id$
*
* hal-storage-mount.c : Mount wrapper
*
* Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
**************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#ifdef __FreeBSD__
#include <fstab.h>
#include <limits.h>
#include <pwd.h>
#else
#include <mntent.h>
#endif
#include <unistd.h>
#include <errno.h>
#include <syslog.h>
#include <libhal.h>
#include <libhal-storage.h>
#ifdef HAVE_POLKIT
#include <libpolkit.h>
#endif
#include "hal-storage-shared.h"
#ifdef __FreeBSD__
#else
#endif
static void
usage (void)
{
exit (1);
}
static void
{
exit (1);
}
static void
{
exit (1);
}
static void
{
exit (1);
}
static void
{
exit (1);
}
static void
{
exit (1);
}
static void
{
exit (1);
}
static void
{
exit (1);
}
static void
{
exit (1);
}
#ifdef HAVE_POLKIT
static void
{
exit (1);
}
#endif
/* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
static void
{
gchar *p, *q;
p = filename;
q = filename;
while (*p)
{
if (*p == G_DIR_SEPARATOR)
{
if (!last_was_slash)
*q++ = G_DIR_SEPARATOR;
}
else
{
if (last_was_slash && *p == '.')
{
if (*(p + 1) == G_DIR_SEPARATOR ||
*(p + 1) == '\0')
{
if (*(p + 1) == '\0')
break;
p += 1;
}
else if (*(p + 1) == '.' &&
(*(p + 2) == G_DIR_SEPARATOR ||
*(p + 2) == '\0'))
{
if (q > filename + 1)
{
q--;
while (q > filename + 1 &&
*(q - 1) != G_DIR_SEPARATOR)
q--;
}
if (*(p + 2) == '\0')
break;
p += 2;
}
else
{
*q++ = *p;
}
}
else
{
*q++ = *p;
}
}
p++;
}
q--;
*q = '\0';
}
static char *
{
char *dir;
char *link;
char *f;
char *f1;
while (g_file_test (f, G_FILE_TEST_IS_SYMLINK)) {
g_free (f);
f = NULL;
goto out;
}
dir = g_path_get_dirname (f);
g_free (f);
f = f1;
}
out:
if (f != NULL)
return f;
}
static LibHalVolume *
{
int i;
char **hal_udis;
int num_hal_udis;
dbus_error_init (&error);
goto out;
}
for (i = 0; i < num_hal_udis; i++) {
char *udi;
break;
}
}
out:
return result;
}
static void
bailout_if_in_fstab (LibHalContext *hal_ctx, const char *device, const char *label, const char *uuid)
{
char *entry;
char *_mount_point;
if (! fstab_open (&handle)) {
unknown_error ("Cannot open /etc/fstab");
}
char *resolved;
#ifdef DEBUG
#endif
/* (heck, we also do the stuff below in gnome-mount) */
/* OK, so what's if someone attaches an external disk with the label '/' and
*
* LABEL=/ / ext3 defaults 1 1
*
* case; suppose that you take the disk from your Fedora server and attaches it
* to your laptop. Bingo, you now have two disks with the label '/'. One must
* seriously wonder if using things like LABEL=/ for / is a good idea; just
* what happens if you boot in this configuration? (answer: the initrd gets
* it wrong most of the time.. sigh)
*
* if it is, then check if it's the same device_file as the given one...
*/
/* see if a volume is mounted at this mount point */
if (_mount_point != NULL) {
if (mounted_vol != NULL) {
const char *mounted_vol_device_file;
/* no need to resolve symlinks, hal uses the canonical device file */
if (mounted_vol_device_file != NULL &&
#ifdef DEBUG
printf ("Wanting to mount %s that has label %s, but /etc/fstab says LABEL=%s is to be mounted at mount point '%s'. However %s (that also has label %s), is already mounted at said mount point. So, skipping said /etc/fstab entry.\n",
#endif
}
}
}
if (!skip_fstab_entry) {
}
}
}
} else {
#ifdef DEBUG
#endif
}
}
}
}
static gboolean
{
char *entry;
printf ("cannot open mount list\n");
unknown_error ("Cannot open /etc/mtab or equivalent");
}
char *resolved;
#ifdef DEBUG
#endif
}
}
mtab_close (handle);
return ret;
}
/* maps volume_id fs types to the appropriate -t mount option */
static const char *
{
#ifdef __FreeBSD__
return "cd9660";
return "ext2fs";
return "msdosfs";
return "hsfs";
return "pcfs";
#endif
return fstype;
}
static void
#ifdef HAVE_POLKIT
#endif
const char *udi,
const char *invoked_by_uid, const char *invoked_by_syscon_name,
{
int i, j;
char **allowed_options;
char **given_options;
char *mount_dir;
int exit_status;
int na;
char *privilege;
#ifdef HAVE_POLKIT
#endif
const char *end;
#ifdef __FreeBSD__
#endif
const char *label;
const char *uuid;
const char *model;
const char *drive_type;
#ifdef sun
#endif
#ifdef DEBUG
#endif
dbus_error_init (&error);
dbus_error_is_set (&error)) {
if (dbus_error_is_set (&error)) {
}
/*
* When device allocation is enabled (bsmconv or TX), we
* set volume.ignore on all volumes, but still want
* Mount() to succeed when called from the euid=0
* device allocation program.
*/
if (atol (invoked_by_uid) != 0) {
}
}
} else {
}
/* TODO: sanity check that what hal exports is correct (cf. Martin Pitt's email) */
/* read from stdin */
/* validate that input from stdin is UTF-8 */
unknown_error ("Error validating mount_point as UTF-8");
unknown_error ("Error validating mount_fstype as UTF-8");
unknown_error ("Error validating mount_options as UTF-8");
#ifdef sun
if (calling_uid != 0) {
#endif
for (i = 0; mount_point[i] != '\0'; i++) {
if (mount_point[i] == '\n' ||
mount_point[i] == G_DIR_SEPARATOR) {
unknown_error ("mount_point cannot contain the following characters: newline, G_DIR_SEPARATOR (usually /)");
}
}
#ifdef sun
}
#endif
#ifdef DEBUG
#endif
/* delete any trailing whitespace options from splitting the string */
if (strlen (given_options[i]) > 0)
break;
given_options[i] = NULL;
}
#ifdef sun
/* for read-only media append 'ro' option if not already */
"storage.removable.solaris.read_only", NULL);
if (append_ro) {
for (i = 0; i < (int) g_strv_length (given_options); i++) {
}
}
}
#endif /* sun */
/* is option 'remount' included? */
is_remount = FALSE;
for (i = 0; i < (int) g_strv_length (given_options); i++) {
is_remount = TRUE;
}
}
if (is_remount) {
if (!libhal_volume_is_mounted (volume)) {
}
} else {
}
}
unknown_error ("Cannot get mount_dir for remount even though volume is mounted!");
}
} else {
if (libhal_volume_is_mounted (volume)) {
}
} else {
}
}
}
if (!is_remount) {
/* figure out mount point if no mount point is given... */
if (strlen (mount_point) == 0) {
char *p;
const char *label;
else
/* best - use label */
} else {
/* fallback - use "disk" */
}
/* sanitize computed mount point name, e.g. replace invalid chars with '-' */
p = mount_point;
while (TRUE) {
if (p == NULL)
break;
*p = '-';
};
} else {
}
/* check mount point name - only forbid separators */
#ifdef sun
if (calling_uid != 0) {
#endif
}
#ifdef sun
}
#endif
/* check if mount point is available - append number to mount point */
i = 0;
while (TRUE) {
#ifdef sun
if (is_abs_path)
else
#endif
if (i == 0)
else
#ifdef DEBUG
#endif
/* XXX should test for being a mount point */
break;
}
if (explicit_mount_point_given) {
}
i++;
}
}
dbus_error_init (&error);
allowed_options = libhal_device_get_property_strlist (hal_ctx, udi, "volume.mount.valid_options", &error);
if (dbus_error_is_set (&error)) {
unknown_error ("Cannot get volume.mount.valid_options");
dbus_error_free (&error);
}
#ifdef DEBUG
for (i = 0; given_options[i] != NULL; i++)
for (i = 0; allowed_options[i] != NULL; i++)
#endif
/* check mount options */
for (i = 0; given_options[i] != NULL; i++) {
for (j = 0; allowed_options[j] != NULL; j++) {
goto option_ok;
}
/* option matched allowed ending in '=', e.g.
* given == "umask=foobar" and allowed == "umask="
*/
char *endp;
/* check for uid=, it requires special handling */
if (*endp != '\0') {
unknown_error ("option uid is malformed");
}
#ifdef DEBUG
#endif
goto option_ok;
} else {
goto option_ok;
}
}
}
/* apparently option was not ok */
;
}
/* Check privilege */
pol_is_fixed = TRUE;
/* don't consider uid= on non-pollable drives for the purpose of policy
* (since these drives normally use vfat)
*/
/* don't consider uid= on vfat, iso9660, udf change-uid for the purpose of policy
*/
}
}
if (pol_is_fixed) {
if (pol_change_uid) {
privilege = "hal-storage-fixed-mount-all-options";
} else {
privilege = "hal-storage-fixed-mount";
}
} else {
if (pol_change_uid) {
privilege = "hal-storage-removable-mount-all-options";
} else {
privilege = "hal-storage-removable-mount";
}
}
#ifdef DEBUG
#endif
#ifdef HAVE_POLKIT
udi,
NULL) != LIBPOLKIT_RESULT_OK) {
printf ("cannot lookup privilege\n");
unknown_error ("Cannot lookup privilege from PolicyKit");
}
if (!allowed_by_privilege) {
printf ("caller don't possess privilege\n");
}
#endif
#ifdef DEBUG
printf ("passed privilege\n");
#endif
if (!is_remount) {
/* create directory */
#ifdef sun
#else
#endif
unknown_error ("Cannot create mount directory");
}
#ifdef __FreeBSD__
} else {
calling_gid = 0;
}
unknown_error ();
}
#endif
}
/* construct arguments to mount */
na = 0;
if (strlen (mount_fstype) > 0) {
/* non-pollable drive; force auto */
mount_do_fstype = "auto";
} else if (libhal_volume_get_fstype (volume) != NULL && strlen (libhal_volume_get_fstype (volume)) > 0) {
}
for (i = 0; given_options[i] != NULL; i++) {
}
#ifdef sun
if (append_ro) {
}
#endif
/* TODO FIXME XXX HACK: OK, so we should rewrite the options in /media/.hal-mtab ..
* but it doesn't really matter much at this point */
if (!is_remount) {
char *mount_dir_escaped;
int hal_mtab_orig_len;
int num_read;
char *hal_mtab_buf;
char *hal_mtab_buf_old;
/* Maintain a list in /media/.hal-mtab with entries of the following format
*
* <device_file>\t<uid>\t<session-id>\t<fstype>\t<options_sep_by_comma>\t<mount point>\n
*
* where session-id currently is unused and thus set to 0.
*
* Example:
*
*/
if (hal_mtab_orig == NULL) {
unknown_error ("Cannot open /media/.hal-mtab");
}
unknown_error ("Cannot seek to end of /media/.hal-mtab");
}
if (hal_mtab_orig_len < 0) {
unknown_error ("Cannot determine size of /media/.hal-mtab");
}
if (num_read != hal_mtab_orig_len) {
unknown_error ("Cannot read from /media/.hal-mtab");
}
} else {
}
#ifdef DEBUG
#endif
unknown_error ("Cannot create /media/.hal-mtab~");
}
if (hal_mtab_buf_old == NULL) {
unknown_error ("Out of memory appending to /media/.hal-mtab~");
}
unknown_error ("Cannot write to /media/.hal-mtab~");
}
#ifdef DEBUG
#endif
} /* !is_remount */
/* now try to mount */
if (!g_spawn_sync ("/",
args,
NULL,
0,
NULL,
NULL,
&sout,
&serr,
&err)) {
unlink ("/media/.hal-mtab~");
}
if (exit_status != 0) {
if (!is_remount) {
unlink ("/media/.hal-mtab~");
}
} else {
int n;
for (n = 0; serr[n] != '\0'; n++) {
if (serr[n] == '\n') {
serr[n] = ' ';
}
}
}
}
if (!is_remount) {
unlink ("/media/.hal-mtab~");
#ifdef DEBUG
#endif
unknown_error ("Cannot rename /media/.hal-mtab~ to /media/.hal-mtab");
}
#ifdef DEBUG
#endif
}
if (is_remount) {
} else {
}
closelog ();
#ifdef sun
}
#endif
}
int
{
char *udi;
char *device;
#ifdef HAVE_POLKIT
#endif
char *invoked_by_uid;
char *invoked_by_syscon_name;
if (!lock_hal_mtab ()) {
unknown_error ("Cannot obtain lock on /media/.hal-mtab");
}
usage ();
usage ();
dbus_error_init (&error);
printf ("Cannot connect to hald\n");
usage ();
}
dbus_error_init (&error);
if (system_bus == NULL) {
printf ("Cannot connect to the system bus\n");
usage ();
}
#ifdef HAVE_POLKIT
printf ("Cannot get libpolkit context\n");
unknown_error ("Cannot get libpolkit context");
}
#endif
usage ();
} else {
#ifdef HAVE_POLKIT
#endif
}
} else {
const char *drive_udi;
unknown_error ("Cannot get drive_udi from volume");
unknown_error ("Cannot get drive from hal");
#ifdef HAVE_POLKIT
#endif
}
unlock_hal_mtab ();
return 0;
}