1/***************************************************************************
2 *
3 * hal-storage-zpool.c : ZFS pool methods
4 *
5 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
6 * Use is subject to license terms.
7 *
8 * Licensed under the Academic Free License version 2.1
9 *
10 **************************************************************************/
11
12#pragma ident	"%Z%%M%	%I%	%E% SMI"
13
14#ifdef HAVE_CONFIG_H
15#  include <config.h>
16#endif
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <glib.h>
22#include <glib/gstdio.h>
23#include <sys/types.h>
24#include <wait.h>
25#include <unistd.h>
26#include <bsm/adt.h>
27#include <bsm/adt_event.h>
28
29#include <libhal.h>
30#include <libhal-storage.h>
31#ifdef HAVE_POLKIT
32#include <libpolkit.h>
33#endif
34
35#include "hal-storage-shared.h"
36
37static void
38usage (void)
39{
40	fprintf (stderr, "This program should only be started by hald.\n");
41	exit (1);
42}
43
44
45void static
46unknown_zpool_error (const char *detail)
47{
48	fprintf (stderr, "org.freedesktop.Hal.Device.Volume.UnknownFailure\n");
49	fprintf (stderr, "%s\n", detail);
50	exit (1);
51}
52
53void
54audit_pool(const adt_export_data_t *imported_state, au_event_t event_id,
55    int result, const char *auth_used, const char *pool, const char *device)
56{
57	adt_session_data_t      *ah;
58	adt_event_data_t        *event;
59
60	if (adt_start_session(&ah, imported_state, 0) != 0) {
61        	printf ("adt_start_session failed %d\n", errno);
62        	return;
63	}
64	if ((event = adt_alloc_event(ah, event_id)) == NULL) {
65        	printf ("adt_alloc_event(ADT_attach)\n", errno);
66        	return;
67	}
68
69	switch (event_id) {
70	case ADT_pool_export:
71		event->adt_pool_export.auth_used = (char *)auth_used;
72		event->adt_pool_export.pool = (char *)pool;
73		event->adt_pool_export.device = (char *)device;
74		break;
75	case ADT_pool_import:
76		event->adt_pool_import.auth_used = (char *)auth_used;
77		event->adt_pool_import.pool = (char *)pool;
78		event->adt_pool_import.device = (char *)device;
79		break;
80	default:
81		goto out;
82	}
83
84	if (result == 0) {
85		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
86			printf ("adt_put_event(%d, success)\n", event_id);
87		}
88	} else {
89		if (adt_put_event(event, ADT_FAILURE, result) != 0) {
90			printf ("adt_put_event(%d, failure)\n", event_id);
91		}
92	}
93out:
94	adt_free_event(event);
95	(void) adt_end_session(ah);
96}
97
98
99void
100handle_zpool (LibHalContext *hal_ctx,
101#ifdef HAVE_POLKIT
102	      LibPolKitContext *pol_ctx,
103#endif
104	      char *subcmd, const char *pool, const char *device,
105	      const char *invoked_by_uid, const char *invoked_by_syscon_name,
106	      DBusConnection *system_bus)
107{
108	GError *err = NULL;
109	char *sout = NULL;
110	char *serr = NULL;
111	int exit_status = 0;
112	char *args[10];
113	int na;
114	adt_export_data_t *adt_data;
115	size_t adt_data_size;
116	au_event_t event_id;
117
118#ifdef DEBUG
119	printf ("subcmd                           = %s\n", subcmd);
120	printf ("pool                             = %s\n", pool);
121	printf ("device                           = %s\n", device);
122	printf ("invoked by uid                   = %s\n", invoked_by_uid);
123	printf ("invoked by system bus connection = %s\n", invoked_by_syscon_name);
124#endif
125
126	na = 0;
127	args[na++] = "/usr/sbin/zpool";
128	args[na++] = subcmd;
129	if ((strcmp (subcmd, "import") == 0) &&
130	    (strncmp (device, "/dev/lofi", 9) == 0)) {
131		args[na++] = "-d";
132		args[na++] = "/dev/lofi";
133	}
134	args[na++] = (char *) pool;
135	args[na++] = NULL;
136
137	/* invoke eject command */
138	if (!g_spawn_sync ("/",
139			   args,
140			   NULL,
141			   0,
142			   NULL,
143			   NULL,
144			   &sout,
145			   &serr,
146			   &exit_status,
147			   &err)) {
148		printf ("Cannot execute zpool %s\n", subcmd);
149		unknown_zpool_error ("Cannot spawn zpool");
150	}
151
152	if ((adt_data = get_audit_export_data (system_bus,
153	    invoked_by_syscon_name, &adt_data_size)) != NULL) {
154		event_id = (strcmp (subcmd, "import") == 0) ?
155		    ADT_pool_import : ADT_pool_export;
156		audit_pool (adt_data, event_id, WEXITSTATUS(exit_status),
157		    "solaris.device.mount.removable", pool, device);
158		free (adt_data);
159	}
160
161	if (exit_status != 0) {
162		printf ("zpool error %d, stdout='%s', stderr='%s'\n", exit_status, sout, serr);
163
164		unknown_zpool_error (serr);
165	}
166
167	g_free (sout);
168	g_free (serr);
169}
170
171
172int
173main (int argc, char *argv[])
174{
175	char *udi;
176	char *device;
177	const char *drive_udi;
178	LibHalDrive *drive;
179	LibHalVolume *volume;
180	DBusError error;
181	LibHalContext *hal_ctx = NULL;
182	DBusConnection *system_bus = NULL;
183#ifdef HAVE_POLKIT
184	LibPolKitContext *pol_ctx = NULL;
185#endif
186	char *invoked_by_uid;
187	char *invoked_by_syscon_name;
188
189	device = getenv ("HAL_PROP_BLOCK_DEVICE");
190	if (device == NULL)
191		usage ();
192
193	udi = getenv ("HAL_PROP_INFO_UDI");
194	if (udi == NULL)
195		usage ();
196
197	invoked_by_uid = getenv ("HAL_METHOD_INVOKED_BY_UID");
198
199	invoked_by_syscon_name = getenv ("HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME");
200
201	dbus_error_init (&error);
202	if ((hal_ctx = libhal_ctx_init_direct (&error)) == NULL) {
203		printf ("Cannot connect to hald\n");
204		LIBHAL_FREE_DBUS_ERROR (&error);
205		usage ();
206	}
207
208	dbus_error_init (&error);
209	system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
210	if (system_bus == NULL) {
211		printf ("Cannot connect to the system bus\n");
212		LIBHAL_FREE_DBUS_ERROR (&error);
213		usage ();
214	}
215#ifdef HAVE_POLKIT
216	pol_ctx = libpolkit_new_context (system_bus);
217	if (pol_ctx == NULL) {
218		printf ("Cannot get libpolkit context\n");
219		unknown_zpool_error ("Cannot get libpolkit context");
220	}
221#endif
222
223	/* should be a volume */
224	if ((volume = libhal_volume_from_udi (hal_ctx, udi)) == NULL) {
225		unknown_zpool_error ("Invalid volume");
226	}
227	if ((drive_udi = libhal_volume_get_storage_device_udi (volume)) == NULL ) {
228		unknown_zpool_error ("Cannot get drive udi");
229	}
230	if ((drive = libhal_drive_from_udi (hal_ctx, drive_udi)) == NULL) {
231		unknown_zpool_error ("Cannot get drive from udi");
232	}
233	if ((libhal_volume_get_fstype (volume) == NULL) ||
234	    (strcmp (libhal_volume_get_fstype (volume), "zfs") != 0)) {
235		unknown_zpool_error ("Not a zpool");
236	}
237	if ((libhal_volume_get_label (volume) == NULL) ||
238	    (strlen (libhal_volume_get_label (volume)) == 0)) {
239		unknown_zpool_error ("Invalid zpool name");
240	}
241
242        handle_zpool (hal_ctx,
243#ifdef HAVE_POLKIT
244		      pol_ctx,
245#endif
246                      ZPOOL_SUBCMD,
247                      libhal_volume_get_label (volume),
248		      device,
249                      invoked_by_uid,
250                      invoked_by_syscon_name,
251		      system_bus);
252
253	return 0;
254}
255
256