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