13ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
23ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen
33781343738de4abddf56982325a77bd70a98cd26Alexander Larsson/* GIO - GLib Input, Output and Streaming Library
43781343738de4abddf56982325a77bd70a98cd26Alexander Larsson *
53781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Copyright (C) 2006-2007 Red Hat, Inc.
63781343738de4abddf56982325a77bd70a98cd26Alexander Larsson *
73781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * This library is free software; you can redistribute it and/or
83781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * modify it under the terms of the GNU Lesser General Public
93781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * License as published by the Free Software Foundation; either
103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * version 2 of the License, or (at your option) any later version.
113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson *
123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * This library is distributed in the hope that it will be useful,
133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * but WITHOUT ANY WARRANTY; without even the implied warranty of
143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Lesser General Public License for more details.
163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson *
173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * You should have received a copy of the GNU Lesser General
183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Public License along with this library; if not, write to the
193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Boston, MA 02111-1307, USA.
213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson *
223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Author: Alexander Larsson <alexl@redhat.com>
233ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen *         David Zeuthen <davidz@redhat.com>
243781343738de4abddf56982325a77bd70a98cd26Alexander Larsson */
253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
26761424465aaad736916b029383483b6ac419d831Johan Dahlin#include "config.h"
273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <string.h>
293781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <glib.h>
313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include "gunixvolumemonitor.h"
323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include "gunixmounts.h"
333ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen#include "gunixmount.h"
343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include "gunixvolume.h"
353d93bf6968884d75dd2706ef85e2014305eb92f2Cody Russell#include "gmount.h"
363ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen#include "gmountprivate.h"
373d93bf6968884d75dd2706ef85e2014305eb92f2Cody Russell#include "giomodule.h"
383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include "glibintl.h"
393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
407f3280230bc9448a5750fc17a6eabef691ba25f4Alexander Larsson#include "gioalias.h"
417f3280230bc9448a5750fc17a6eabef691ba25f4Alexander Larsson
423781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstruct _GUnixVolumeMonitor {
433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GNativeVolumeMonitor parent;
443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GUnixMountMonitor *mount_monitor;
463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GList *last_mountpoints;
483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GList *last_mounts;
493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GList *volumes;
513ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  GList *mounts;
523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson};
533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
543ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenstatic void mountpoints_changed      (GUnixMountMonitor  *mount_monitor,
553ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen                                      gpointer            user_data);
563ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenstatic void mounts_changed           (GUnixMountMonitor  *mount_monitor,
573ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen                                      gpointer            user_data);
583ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenstatic void update_volumes           (GUnixVolumeMonitor *monitor);
593ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenstatic void update_mounts            (GUnixVolumeMonitor *monitor);
603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
61d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson#define g_unix_volume_monitor_get_type _g_unix_volume_monitor_get_type
62bff9ecedbbea1a794827f569638365db40c442e6Alexander LarssonG_DEFINE_TYPE_WITH_CODE (GUnixVolumeMonitor, g_unix_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR,
63bff9ecedbbea1a794827f569638365db40c442e6Alexander Larsson                         g_io_extension_point_implement (G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME,
64bff9ecedbbea1a794827f569638365db40c442e6Alexander Larsson							 g_define_type_id,
65bff9ecedbbea1a794827f569638365db40c442e6Alexander Larsson							 "unix",
66bff9ecedbbea1a794827f569638365db40c442e6Alexander Larsson							 0));
673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
683781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic void
693781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_unix_volume_monitor_finalize (GObject *object)
703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GUnixVolumeMonitor *monitor;
723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  monitor = G_UNIX_VOLUME_MONITOR (object);
743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mountpoints_changed, monitor);
763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_signal_handlers_disconnect_by_func (monitor->mount_monitor, mounts_changed, monitor);
773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_object_unref (monitor->mount_monitor);
793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
803ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  g_list_foreach (monitor->last_mountpoints, (GFunc)g_unix_mount_point_free, NULL);
813ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  g_list_free (monitor->last_mountpoints);
823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_foreach (monitor->last_mounts, (GFunc)g_unix_mount_free, NULL);
833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_free (monitor->last_mounts);
843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_foreach (monitor->volumes, (GFunc)g_object_unref, NULL);
863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_free (monitor->volumes);
873ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  g_list_foreach (monitor->mounts, (GFunc)g_object_unref, NULL);
883ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  g_list_free (monitor->mounts);
89a4427bfff5d31499dc0b46fa3f734bc92f7d0dd5Michael Natterer
90a4427bfff5d31499dc0b46fa3f734bc92f7d0dd5Michael Natterer  G_OBJECT_CLASS (g_unix_volume_monitor_parent_class)->finalize (object);
913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
9373477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larssonstatic void
9473477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larssong_unix_volume_monitor_dispose (GObject *object)
9573477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson{
9673477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson  GUnixVolumeMonitor *monitor;
9773477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson
9873477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson  monitor = G_UNIX_VOLUME_MONITOR (object);
9973477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson  g_list_foreach (monitor->volumes, (GFunc)g_object_unref, NULL);
10073477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson  g_list_free (monitor->volumes);
10173477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson  monitor->volumes = NULL;
10273477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson
10373477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson  g_list_foreach (monitor->mounts, (GFunc)g_object_unref, NULL);
10473477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson  g_list_free (monitor->mounts);
10573477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson  monitor->mounts = NULL;
10673477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson
10773477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson  G_OBJECT_CLASS (g_unix_volume_monitor_parent_class)->dispose (object);
10873477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson}
10973477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson
1103781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GList *
1113ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenget_mounts (GVolumeMonitor *volume_monitor)
1123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
1133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GUnixVolumeMonitor *monitor;
1143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GList *l;
1153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  monitor = G_UNIX_VOLUME_MONITOR (volume_monitor);
1173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1183ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  l = g_list_copy (monitor->mounts);
1193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_foreach (l, (GFunc)g_object_ref, NULL);
1203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return l;
1223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
1233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1243781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GList *
1253ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenget_volumes (GVolumeMonitor *volume_monitor)
1263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
1273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GUnixVolumeMonitor *monitor;
1283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GList *l;
1293781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  monitor = G_UNIX_VOLUME_MONITOR (volume_monitor);
1313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1323ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  l = g_list_copy (monitor->volumes);
1333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_foreach (l, (GFunc)g_object_ref, NULL);
1343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1353781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return l;
1363781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
1373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1383ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenstatic GList *
1393ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenget_connected_drives (GVolumeMonitor *volume_monitor)
1403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
1413ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  return NULL;
1423ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen}
1433ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen
144f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthenstatic GVolume *
145f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthenget_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
146f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthen{
147f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthen  return NULL;
148f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthen}
149f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthen
150f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthenstatic GMount *
151f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthenget_mount_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
152f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthen{
153f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthen  return NULL;
154f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthen}
155f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthen
156c4e3cfbf4070d9bf255d08e23591e8a8dc476d72Alexander Larssonstatic gboolean
157c4e3cfbf4070d9bf255d08e23591e8a8dc476d72Alexander Larssonis_supported (void)
158c4e3cfbf4070d9bf255d08e23591e8a8dc476d72Alexander Larsson{
159c4e3cfbf4070d9bf255d08e23591e8a8dc476d72Alexander Larsson  return TRUE;
160c4e3cfbf4070d9bf255d08e23591e8a8dc476d72Alexander Larsson}
161c4e3cfbf4070d9bf255d08e23591e8a8dc476d72Alexander Larsson
1623ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenstatic GMount *
163c4e3cfbf4070d9bf255d08e23591e8a8dc476d72Alexander Larssonget_mount_for_mount_path (const char *mount_path,
164c4e3cfbf4070d9bf255d08e23591e8a8dc476d72Alexander Larsson                          GCancellable *cancellable)
1653ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen{
1663ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  GUnixMountEntry *mount_entry;
1673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GUnixMount *mount;
1683781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
169feb5258cf9ca9c3b3d9a58a98b1c6c75c822855aMatthias Clasen  mount_entry = g_unix_mount_at (mount_path, NULL);
1704d23d2647a324c33de1e8bfbbf1d5720ec8bb728Matthias Clasen
1714d23d2647a324c33de1e8bfbbf1d5720ec8bb728Matthias Clasen  if (!mount_entry)
1724d23d2647a324c33de1e8bfbbf1d5720ec8bb728Matthias Clasen    return NULL;
1734d23d2647a324c33de1e8bfbbf1d5720ec8bb728Matthias Clasen
1743ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  /* TODO: Set mountable volume? */
1753ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  mount = _g_unix_mount_new (NULL, mount_entry, NULL);
1763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1776dba7df4b12852623a9b893301b22af028184793Matthias Clasen  g_unix_mount_free (mount_entry);
1786dba7df4b12852623a9b893301b22af028184793Matthias Clasen
1793ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  return G_MOUNT (mount);
1803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
1813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1823781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic void
1833781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_unix_volume_monitor_class_init (GUnixVolumeMonitorClass *klass)
1843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
1853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass);
1873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GNativeVolumeMonitorClass *native_class = G_NATIVE_VOLUME_MONITOR_CLASS (klass);
1883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  gobject_class->finalize = g_unix_volume_monitor_finalize;
19073477419e89e73c4af49c3f2d88493af4f57ce90Alexander Larsson  gobject_class->dispose = g_unix_volume_monitor_dispose;
1913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1923ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  monitor_class->get_mounts = get_mounts;
1933ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  monitor_class->get_volumes = get_volumes;
1943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  monitor_class->get_connected_drives = get_connected_drives;
195f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthen  monitor_class->get_volume_for_uuid = get_volume_for_uuid;
196f4add8f0faf4a8c2ca1cdb4f99f5f3d0d66aaff8David Zeuthen  monitor_class->get_mount_for_uuid = get_mount_for_uuid;
19728d1c8e0ad86253c84de1ee948a338eec98ae701Alexander Larsson  monitor_class->is_supported = is_supported;
1983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1993ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  native_class->get_mount_for_mount_path = get_mount_for_mount_path;
2003781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
2013781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2023781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic void
2033781343738de4abddf56982325a77bd70a98cd26Alexander Larssonmountpoints_changed (GUnixMountMonitor *mount_monitor,
204a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		     gpointer           user_data)
2053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
2063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GUnixVolumeMonitor *unix_monitor = user_data;
2073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2083ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  /* Update both to make sure volumes are created before mounts */
2093781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  update_volumes (unix_monitor);
2103ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  update_mounts (unix_monitor);
2113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
2123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2133781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic void
2143781343738de4abddf56982325a77bd70a98cd26Alexander Larssonmounts_changed (GUnixMountMonitor *mount_monitor,
215a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		gpointer           user_data)
2163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
2173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GUnixVolumeMonitor *unix_monitor = user_data;
2183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2193ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  /* Update both to make sure volumes are created before mounts */
2203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  update_volumes (unix_monitor);
2213ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  update_mounts (unix_monitor);
2223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
2233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2243781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic void
2253781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_unix_volume_monitor_init (GUnixVolumeMonitor *unix_monitor)
2263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
2273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  unix_monitor->mount_monitor = g_unix_mount_monitor_new ();
2293781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_signal_connect (unix_monitor->mount_monitor,
2318d37a7964d3b41de330aa581b61eda374b093e71Sven Neumann		    "mounts-changed", G_CALLBACK (mounts_changed),
2323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		    unix_monitor);
2333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_signal_connect (unix_monitor->mount_monitor,
2358d37a7964d3b41de330aa581b61eda374b093e71Sven Neumann		    "mountpoints-changed", G_CALLBACK (mountpoints_changed),
2363781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		    unix_monitor);
2373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  update_volumes (unix_monitor);
2393ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  update_mounts (unix_monitor);
2403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
2413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson/**
2433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * g_unix_volume_monitor_new:
2443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson *
2453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Returns:  a new #GVolumeMonitor.
2463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson **/
2473781343738de4abddf56982325a77bd70a98cd26Alexander LarssonGVolumeMonitor *
248d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson_g_unix_volume_monitor_new (void)
2493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
2503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GUnixVolumeMonitor *monitor;
2513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  monitor = g_object_new (G_TYPE_UNIX_VOLUME_MONITOR, NULL);
2533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2543781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return G_VOLUME_MONITOR (monitor);
2553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
2563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2573781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic void
258a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasendiff_sorted_lists (GList         *list1,
259a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen                   GList         *list2,
260a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen                   GCompareFunc   compare,
261a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   GList        **added,
262a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen                   GList        **removed)
2633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
2643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  int order;
2653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  *added = *removed = NULL;
2673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2683781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  while (list1 != NULL &&
2693781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	 list2 != NULL)
2703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
2713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      order = (*compare) (list1->data, list2->data);
2723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (order < 0)
2733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
2743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  *removed = g_list_prepend (*removed, list1->data);
2753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  list1 = list1->next;
2763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
2773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      else if (order > 0)
2783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
2793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  *added = g_list_prepend (*added, list2->data);
2803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  list2 = list2->next;
2813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
2823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      else
2833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{ /* same item */
2843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  list1 = list1->next;
2853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  list2 = list2->next;
2863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
2873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
2883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  while (list1 != NULL)
2903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
2913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      *removed = g_list_prepend (*removed, list1->data);
2923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      list1 = list1->next;
2933781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
2943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  while (list2 != NULL)
2953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
2963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      *added = g_list_prepend (*added, list2->data);
2973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      list2 = list2->next;
2983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
2993781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
3003781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3013781343738de4abddf56982325a77bd70a98cd26Alexander Larsson/**
3023ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen * _g_unix_volume_monitor_lookup_volume_for_mount_path:
3033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * @monitor:
3043ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen * @mount_path:
3053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson *
3063ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen * Returns:  #GUnixVolume for the given @mount_path.
3073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson **/
3083ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid ZeuthenGUnixVolume *
3093ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen_g_unix_volume_monitor_lookup_volume_for_mount_path (GUnixVolumeMonitor *monitor,
3103ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen                                                     const char         *mount_path)
3113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
3123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GList *l;
3133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3143ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  for (l = monitor->volumes; l != NULL; l = l->next)
3153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
3163ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      GUnixVolume *volume = l->data;
3173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3183ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      if (_g_unix_volume_has_mount_path (volume, mount_path))
3193ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen	return volume;
3203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
3213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return NULL;
3233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
3243781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3253ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenstatic GUnixMount *
3263ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenfind_mount_by_mountpath (GUnixVolumeMonitor *monitor,
3273ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen                         const char *mount_path)
3283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
3293781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GList *l;
3303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3313ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  for (l = monitor->mounts; l != NULL; l = l->next)
3323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
3333ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      GUnixMount *mount = l->data;
3343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3353ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      if (_g_unix_mount_has_mount_path (mount, mount_path))
3363ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen	return mount;
3373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
3383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return NULL;
3403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
3413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3423781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic void
3433ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenupdate_volumes (GUnixVolumeMonitor *monitor)
3443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
3453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GList *new_mountpoints;
3463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GList *removed, *added;
3473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GList *l;
3483ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  GUnixVolume *volume;
3493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
350feb5258cf9ca9c3b3d9a58a98b1c6c75c822855aMatthias Clasen  new_mountpoints = g_unix_mount_points_get (NULL);
3513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  new_mountpoints = g_list_sort (new_mountpoints, (GCompareFunc) g_unix_mount_point_compare);
3533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3543781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  diff_sorted_lists (monitor->last_mountpoints,
3553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     new_mountpoints, (GCompareFunc) g_unix_mount_point_compare,
3563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     &added, &removed);
3573781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3583781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  for (l = removed; l != NULL; l = l->next)
3593781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
3603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      GUnixMountPoint *mountpoint = l->data;
3613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3623ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      volume = _g_unix_volume_monitor_lookup_volume_for_mount_path (monitor,
3633ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen                                                                    g_unix_mount_point_get_mount_path (mountpoint));
3643ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      if (volume)
3653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
3663ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen	  _g_unix_volume_disconnected (volume);
3673ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen	  monitor->volumes = g_list_remove (monitor->volumes, volume);
3688d37a7964d3b41de330aa581b61eda374b093e71Sven Neumann	  g_signal_emit_by_name (monitor, "volume-removed", volume);
36988679aba98d30ba069edfffb46257ef77451d641David Zeuthen	  g_signal_emit_by_name (volume, "removed");
3703ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen	  g_object_unref (volume);
3713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
3723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
3733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  for (l = added; l != NULL; l = l->next)
3753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
3763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      GUnixMountPoint *mountpoint = l->data;
3773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3783ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      volume = _g_unix_volume_new (G_VOLUME_MONITOR (monitor), mountpoint);
3793ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      if (volume)
3803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
3813ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen	  monitor->volumes = g_list_prepend (monitor->volumes, volume);
3828d37a7964d3b41de330aa581b61eda374b093e71Sven Neumann	  g_signal_emit_by_name (monitor, "volume-added", volume);
3833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
3843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
3853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_free (added);
3873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_free (removed);
3883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_foreach (monitor->last_mountpoints,
3893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		  (GFunc)g_unix_mount_point_free, NULL);
3903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_free (monitor->last_mountpoints);
3913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  monitor->last_mountpoints = new_mountpoints;
3923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
3933781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3943781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic void
3953ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenupdate_mounts (GUnixVolumeMonitor *monitor)
3963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
3973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GList *new_mounts;
3983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GList *removed, *added;
3993781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GList *l;
4003ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  GUnixMount *mount;
4013781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GUnixVolume *volume;
4023781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  const char *mount_path;
4033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
404feb5258cf9ca9c3b3d9a58a98b1c6c75c822855aMatthias Clasen  new_mounts = g_unix_mounts_get (NULL);
4053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  new_mounts = g_list_sort (new_mounts, (GCompareFunc) g_unix_mount_compare);
4073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4083781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  diff_sorted_lists (monitor->last_mounts,
4093781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     new_mounts, (GCompareFunc) g_unix_mount_compare,
4103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     &added, &removed);
4113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  for (l = removed; l != NULL; l = l->next)
4133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
4143ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      GUnixMountEntry *mount_entry = l->data;
4153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4163ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      mount = find_mount_by_mountpath (monitor, g_unix_mount_get_mount_path (mount_entry));
4173ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      if (mount)
4183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
4193ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen	  _g_unix_mount_unmounted (mount);
4203ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen	  monitor->mounts = g_list_remove (monitor->mounts, mount);
4218d37a7964d3b41de330aa581b61eda374b093e71Sven Neumann	  g_signal_emit_by_name (monitor, "mount-removed", mount);
42288679aba98d30ba069edfffb46257ef77451d641David Zeuthen	  g_signal_emit_by_name (mount, "unmounted");
4233ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen	  g_object_unref (mount);
4243781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
4253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
4263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  for (l = added; l != NULL; l = l->next)
4283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
4293ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      GUnixMountEntry *mount_entry = l->data;
4303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4313ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      mount_path = g_unix_mount_get_mount_path (mount_entry);
4323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4333ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      volume = _g_unix_volume_monitor_lookup_volume_for_mount_path (monitor, mount_path);
4343ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      mount = _g_unix_mount_new (G_VOLUME_MONITOR (monitor), mount_entry, volume);
4353ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen      if (mount)
4363781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
4373ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen	  monitor->mounts = g_list_prepend (monitor->mounts, mount);
4388d37a7964d3b41de330aa581b61eda374b093e71Sven Neumann	  g_signal_emit_by_name (monitor, "mount-added", mount);
4393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
4403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
4413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_free (added);
4433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_free (removed);
4443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_foreach (monitor->last_mounts,
4453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		  (GFunc)g_unix_mount_free, NULL);
4463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_list_free (monitor->last_mounts);
4473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  monitor->last_mounts = new_mounts;
4483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
449