1 /***************************************************************************
2 * CVSID: $Id: hal-storage-mount.c,v 1.7 2006/06/21 00:44:03 david Exp $
3 *
4 * hal-storage-mount.c : Mount wrapper
5 *
6 * Copyright (C) 2006 David Zeuthen, <david@fubar.dk>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 **************************************************************************/
23
24
25 #ifdef HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <glib.h>
33 #include <glib/gstdio.h>
34 #ifdef __FreeBSD__
35 #include <fstab.h>
36 #include <sys/param.h>
37 #include <sys/ucred.h>
38 #include <sys/mount.h>
39 #include <limits.h>
40 #include <pwd.h>
41 #elif sun
42 #include <fcntl.h>
43 #include <sys/mnttab.h>
44 #include <sys/vfstab.h>
45 #include <sys/stat.h>
46 #include <sys/wait.h>
47 #include <bsm/adt.h>
48 #include <bsm/adt_event.h>
49 #else
50 #include <mntent.h>
51 #endif
52 #include <sys/types.h>
53 #include <unistd.h>
54 #include <sys/file.h>
55 #include <errno.h>
56 #include <syslog.h>
57
58 #include "hal-storage-shared.h"
59
60 #ifdef __FreeBSD__
61 struct mtab_handle
62 {
63 struct statfs *mounts;
64 int n_mounts;
65 int iter;
66 };
67 #endif
68
69
70 gboolean
mtab_open(gpointer * handle)71 mtab_open (gpointer *handle)
72 {
73 #ifdef __FreeBSD__
74 struct mtab_handle *mtab;
75
76 mtab = g_new0 (struct mtab_handle, 1);
77 mtab->n_mounts = getmntinfo (&mtab->mounts, MNT_NOWAIT);
78 if (mtab->n_mounts == 0) {
79 g_free (mtab);
80 return FALSE;
81 }
82
83 *handle = mtab;
84 return TRUE;
85 #elif sun
86 *handle = fopen (MNTTAB, "r");
87 return *handle != NULL;
88 #else
89 *handle = fopen ("/proc/mounts", "r");
90 return *handle != NULL;
91 #endif
92 }
93
94 char *
mtab_next(gpointer handle,char ** mount_point)95 mtab_next (gpointer handle, char **mount_point)
96 {
97 #ifdef __FreeBSD__
98 struct mtab_handle *mtab = handle;
99
100 if (mtab->iter < mtab->n_mounts)
101 return mtab->mounts[mtab->iter++].f_mntfromname;
102 else
103 return NULL;
104 #error TODO: set *mount_point to g_strdup()-ed value if mount_point!=NULL
105 #elif sun
106 static struct mnttab mnt;
107
108 if (getmntent (handle, &mnt) == 0) {
109 if (mount_point != NULL) {
110 *mount_point = g_strdup (mnt.mnt_mountp);
111 }
112 return mnt.mnt_special;
113 } else {
114 return NULL;
115 }
116 #else
117 struct mntent *mnt;
118
119 mnt = getmntent (handle);
120
121 if (mnt != NULL) {
122 if (mount_point != NULL) {
123 *mount_point = g_strdup (mnt->mnt_dir);
124 }
125 return mnt->mnt_fsname;
126 } else {
127 return NULL;
128 }
129 #endif
130 }
131
132 void
mtab_close(gpointer handle)133 mtab_close (gpointer handle)
134 {
135 #ifdef __FreeBSD__
136 g_free (handle);
137 #else
138 fclose (handle);
139 #endif
140 }
141
142
143
144 gboolean
fstab_open(gpointer * handle)145 fstab_open (gpointer *handle)
146 {
147 #ifdef __FreeBSD__
148 return setfsent () == 1;
149 #elif sun
150 *handle = fopen (VFSTAB, "r");
151 return *handle != NULL;
152 #else
153 *handle = fopen ("/etc/fstab", "r");
154 return *handle != NULL;
155 #endif
156 }
157
158 char *
fstab_next(gpointer handle,char ** mount_point)159 fstab_next (gpointer handle, char **mount_point)
160 {
161 #ifdef __FreeBSD__
162 struct fstab *fstab;
163
164 fstab = getfsent ();
165
166 /* TODO: fill out mount_point */
167 if (mount_point != NULL && fstab != NULL) {
168 *mount_point = fstab->fs_file;
169 }
170
171 return fstab ? fstab->fs_spec : NULL;
172 #elif sun
173 static struct vfstab v;
174
175 return getvfsent (handle, &v) == 0 ? v.vfs_special : NULL;
176 #else
177 struct mntent *mnt;
178
179 mnt = getmntent (handle);
180
181 if (mount_point != NULL && mnt != NULL) {
182 *mount_point = mnt->mnt_dir;
183 }
184
185 return mnt ? mnt->mnt_fsname : NULL;
186 #endif
187 }
188
189 void
fstab_close(gpointer handle)190 fstab_close (gpointer handle)
191 {
192 #ifdef __FreeBSD__
193 endfsent ();
194 #else
195 fclose (handle);
196 #endif
197 }
198
199 #ifdef __FreeBSD__
200 #define UMOUNT "/sbin/umount"
201 #elif sun
202 #define UMOUNT "/sbin/umount"
203 #else
204 #define UMOUNT "/bin/umount"
205 #endif
206
207 void
unknown_error(const char * detail)208 unknown_error (const char *detail)
209 {
210 fprintf (stderr, "org.freedesktop.Hal.Device.Volume.UnknownFailure\n");
211 fprintf (stderr, "%s\n", detail);
212 exit (1);
213 }
214
215
216 static void
device_busy(const char * detail)217 device_busy (const char *detail)
218 {
219 fprintf (stderr, "org.freedesktop.Hal.Device.Volume.Busy\n");
220 fprintf (stderr, "%s\n", detail);
221 exit (1);
222 }
223
224
225 static void
not_mounted(const char * detail)226 not_mounted (const char *detail)
227 {
228 fprintf (stderr, "org.freedesktop.Hal.Device.Volume.NotMounted\n");
229 fprintf (stderr, "%s\n", detail);
230 exit (1);
231 }
232
233
234 static void
not_mounted_by_hal(const char * detail)235 not_mounted_by_hal (const char *detail)
236 {
237 fprintf (stderr, "org.freedesktop.Hal.Device.Volume.NotMountedByHal\n");
238 fprintf (stderr, "%s\n", detail);
239 exit (1);
240 }
241
242 static void
permission_denied_privilege(const char * privilege,const char * uid)243 permission_denied_privilege (const char *privilege, const char *uid)
244 {
245 fprintf (stderr, "org.freedesktop.Hal.Device.PermissionDeniedByPolicy\n");
246 fprintf (stderr, "%s refused uid %s\n", privilege, uid);
247 exit (1);
248 }
249
250 static void
permission_denied_volume_ignore(const char * device)251 permission_denied_volume_ignore (const char *device)
252 {
253 fprintf (stderr, "org.freedesktop.Hal.Device.Volume.PermissionDenied\n");
254 fprintf (stderr, "Device has %s volume.ignore set to TRUE. Refusing to mount.\n", device);
255 exit (1);
256 }
257
258 void
handle_unmount(LibHalContext * hal_ctx,LibPolKitContext * pol_ctx,const char * udi,LibHalVolume * volume,LibHalDrive * drive,const char * device,const char * invoked_by_uid,const char * invoked_by_syscon_name,gboolean option_lazy,gboolean option_force,DBusConnection * system_bus)259 handle_unmount (LibHalContext *hal_ctx,
260 #ifdef HAVE_POLKIT
261 LibPolKitContext *pol_ctx,
262 #endif
263 const char *udi,
264 LibHalVolume *volume, LibHalDrive *drive, const char *device,
265 const char *invoked_by_uid, const char *invoked_by_syscon_name,
266 gboolean option_lazy, gboolean option_force,
267 DBusConnection *system_bus)
268 {
269 int i, j;
270 DBusError error;
271 GError *err = NULL;
272 char *sout = NULL;
273 char *serr = NULL;
274 int exit_status;
275 char *args[10];
276 int na;
277 FILE *hal_mtab_orig;
278 int hal_mtab_orig_len;
279 int num_read;
280 char *hal_mtab_buf;
281 char **lines;
282 char *mount_point_to_unmount;
283 gboolean mounted_by_other_uid;
284 FILE *hal_mtab_new;
285 #ifdef sun
286 adt_export_data_t *adt_data;
287 size_t adt_data_size;
288 #endif
289
290 #ifdef DEBUG
291 printf ("device = %s\n", device);
292 printf ("invoked by uid = %s\n", invoked_by_uid);
293 printf ("invoked by system bus connection = %s\n", invoked_by_syscon_name);
294 #endif
295
296 if (volume != NULL) {
297 dbus_error_init (&error);
298 if (libhal_device_get_property_bool (hal_ctx, udi, "volume.ignore", &error) ||
299 dbus_error_is_set (&error)) {
300 if (dbus_error_is_set (&error)) {
301 LIBHAL_FREE_DBUS_ERROR (&error);
302 }
303 /*
304 * When device allocation is enabled (bsmconv or TX), we
305 * set volume.ignore on all volumes, but still want
306 * Mount() to succeed when called from the euid=0
307 * device allocation program.
308 */
309 if (atol (invoked_by_uid) != 0) {
310 permission_denied_volume_ignore (device);
311 }
312 }
313
314 if (!libhal_volume_is_mounted (volume)) {
315 not_mounted ("According to HAL, the volume is not mounted");
316 }
317 }
318
319
320 /* check hal's mtab file to verify the device to unmount is actually mounted by hal */
321 hal_mtab_orig = fopen ("/media/.hal-mtab", "r");
322 if (hal_mtab_orig == NULL) {
323 unknown_error ("Cannot open /media/.hal-mtab");
324 }
325 if (fseek (hal_mtab_orig, 0L, SEEK_END) != 0) {
326 unknown_error ("Cannot seek to end of /media/.hal-mtab");
327 }
328 hal_mtab_orig_len = ftell (hal_mtab_orig);
329 if (hal_mtab_orig_len < 0) {
330 unknown_error ("Cannot determine size of /media/.hal-mtab");
331 }
332 rewind (hal_mtab_orig);
333 hal_mtab_buf = g_new0 (char, hal_mtab_orig_len + 1);
334 num_read = fread (hal_mtab_buf, 1, hal_mtab_orig_len, hal_mtab_orig);
335 if (num_read != hal_mtab_orig_len) {
336 unknown_error ("Cannot read from /media/.hal-mtab");
337 }
338 fclose (hal_mtab_orig);
339
340 #ifdef DEBUG
341 printf ("hal_mtab = '%s'\n", hal_mtab_buf);
342 #endif
343
344 lines = g_strsplit (hal_mtab_buf, "\n", 0);
345 g_free (hal_mtab_buf);
346
347 mount_point_to_unmount = NULL;
348 mounted_by_other_uid = TRUE;
349
350 /* find the entry we're going to unmount */
351 for (i = 0; lines[i] != NULL; i++) {
352 char **line_elements;
353 char *special, *dosp;
354 struct stat st;
355
356 #ifdef DEBUG
357 printf (" line = '%s'\n", lines[i]);
358 #endif
359
360 if ((lines[i])[0] == '#')
361 continue;
362
363 line_elements = g_strsplit (lines[i], "\t", 6);
364 if (g_strv_length (line_elements) == 6) {
365
366 #ifdef DEBUG
367 printf (" devfile = '%s'\n", line_elements[0]);
368 printf (" uid = '%s'\n", line_elements[1]);
369 printf (" session id = '%s'\n", line_elements[2]);
370 printf (" fs = '%s'\n", line_elements[3]);
371 printf (" options = '%s'\n", line_elements[4]);
372 printf (" mount_point = '%s'\n", line_elements[5]);
373 #endif
374
375 if (strcmp (line_elements[0], device) == 0) {
376 char *line_to_free;
377
378 if (strcmp (line_elements[1], invoked_by_uid) == 0) {
379 mounted_by_other_uid = FALSE;
380 }
381 #ifdef sun
382 if (stat("/dev/vt/console_user", &st) == 0 &&
383 st.st_uid == atoi (invoked_by_uid)) {
384 /*
385 * Owner is allowed to take over. Before we have real
386 * ownership in HAL, assume it's the console owner.
387 */
388 mounted_by_other_uid = FALSE;
389 }
390 #endif /* sun */
391 mount_point_to_unmount = g_strdup (line_elements[5]);
392
393 line_to_free = lines[i];
394
395 for (j = i; lines[j] != NULL; j++) {
396 lines[j] = lines[j+1];
397 }
398 lines[j] = NULL;
399
400 g_free (line_to_free);
401
402 g_strfreev (line_elements);
403 goto line_found;
404
405 }
406
407 }
408
409 g_strfreev (line_elements);
410 }
411 line_found:
412
413 if (mount_point_to_unmount == NULL) {
414 not_mounted_by_hal ("Device to unmount is not in /media/.hal-mtab so it is not mounted by HAL");
415 }
416
417 /* bail out, unless if we got the "hal-storage-can-unmount-volumes-mounted-by-others" privilege only
418 * if mounted_by_other_uid==TRUE
419 *
420 * We allow uid 0 to actually ensure that Unmount(options=["lazy"], "/dev/blah") works from addon-storage.
421 */
422 if ((strcmp (invoked_by_uid, "0") != 0) && mounted_by_other_uid) {
423 /* TODO: actually check for privilege "hal-storage-can-unmount-volumes-mounted-by-others" */
424 permission_denied_privilege ("hal-storage-can-unmount-volumes-mounted-by-others", invoked_by_uid);
425 }
426
427 /* create new .hal-mtab~ file without the entry we're going to unmount */
428 hal_mtab_new = fopen ("/media/.hal-mtab~", "w");
429 if (hal_mtab_new == NULL) {
430 unknown_error ("Cannot create /media/.hal-mtab~");
431 }
432 for (i = 0; lines[i] != NULL; i++) {
433 if (i > 0) {
434 char anewl[2] = "\n\0";
435 if (fwrite (anewl, 1, 1, hal_mtab_new) != 1) {
436 unknown_error ("Cannot write to /media/.hal-mtab~");
437 }
438 }
439
440 if (fwrite (lines[i], 1, strlen (lines[i]), hal_mtab_new) != strlen (lines[i])) {
441 unknown_error ("Cannot write to /media/.hal-mtab~");
442 }
443
444 }
445 fclose (hal_mtab_new);
446
447 g_strfreev (lines);
448
449 /* construct arguments to /bin/umount */
450 na = 0;
451 args[na++] = UMOUNT;
452 if (option_lazy)
453 args[na++] = "-l";
454 if (option_force)
455 args[na++] = "-f";
456 args[na++] = (char *) device;
457 args[na++] = NULL;
458
459 #ifdef DEBUG
460 printf ("will umount %s (mounted at '%s'), mounted_by_other_uid=%d\n",
461 device, mount_point_to_unmount, mounted_by_other_uid);
462 #endif
463
464 /* invoke /bin/umount */
465 if (!g_spawn_sync ("/",
466 args,
467 NULL,
468 0,
469 NULL,
470 NULL,
471 &sout,
472 &serr,
473 &exit_status,
474 &err)) {
475 printf ("Cannot execute %s\n", UMOUNT);
476 unlink ("/media/.hal-mtab~");
477 unknown_error ("Cannot spawn " UMOUNT);
478 }
479
480 /* check if unmount was succesful */
481 if (exit_status != 0) {
482 printf ("%s error %d, stdout='%s', stderr='%s'\n", UMOUNT, exit_status, sout, serr);
483
484 if (strstr (serr, "device is busy") != NULL) {
485 unlink ("/media/.hal-mtab~");
486 device_busy (serr);
487 } else {
488 unlink ("/media/.hal-mtab~");
489 unknown_error (serr);
490 }
491 }
492
493 #ifdef sun
494 if ((adt_data = get_audit_export_data (system_bus,
495 invoked_by_syscon_name, &adt_data_size)) != NULL) {
496 audit_volume (adt_data, ADT_detach, WEXITSTATUS(exit_status),
497 "solaris.device.mount.removable",
498 mount_point_to_unmount, device, NULL);
499 free (adt_data);
500 }
501 #endif
502
503 /* unmount was succesful, remove directory we created in Mount() */
504 #ifdef sun
505 if (strncmp (mount_point_to_unmount, "/media/", 7) == 0)
506 #endif
507 if (g_rmdir (mount_point_to_unmount) != 0) {
508 unlink ("/media/.hal-mtab~");
509 unknown_error ("Cannot remove directory");
510 }
511
512 /* set new .hal-mtab file */
513 if (rename ("/media/.hal-mtab~", "/media/.hal-mtab") != 0) {
514 unlink ("/media/.hal-mtab~");
515 unknown_error ("Cannot rename /media/.hal-mtab~ to /media/.hal-mtab");
516 }
517
518 #ifdef DEBUG
519 printf ("done unmounting\n");
520 #endif
521 openlog ("hald", 0, LOG_DAEMON);
522 syslog (LOG_INFO, "unmounted %s from '%s' on behalf of uid %s", device, mount_point_to_unmount, invoked_by_uid);
523 closelog ();
524
525 g_free (sout);
526 g_free (serr);
527 g_free (mount_point_to_unmount);
528 }
529
530 #define EJECT "/usr/bin/eject"
531
532 void
handle_eject(LibHalContext * hal_ctx,LibPolKitContext * pol_ctx,const char * udi,LibHalDrive * drive,const char * device,const char * invoked_by_uid,const char * invoked_by_syscon_name,gboolean closetray,DBusConnection * system_bus)533 handle_eject (LibHalContext *hal_ctx,
534 #ifdef HAVE_POLKIT
535 LibPolKitContext *pol_ctx,
536 #endif
537 const char *udi,
538 LibHalDrive *drive, const char *device,
539 const char *invoked_by_uid, const char *invoked_by_syscon_name,
540 gboolean closetray, DBusConnection *system_bus)
541 {
542 GError *err = NULL;
543 char *sout = NULL;
544 char *serr = NULL;
545 int exit_status;
546 char *args[10];
547 int na;
548 #ifdef sun
549 adt_export_data_t *adt_data;
550 size_t adt_data_size;
551 #endif
552 /* TODO: should we require privileges here? */
553
554 #ifdef DEBUG
555 printf ("device = %s\n", device);
556 printf ("invoked by uid = %s\n", invoked_by_uid);
557 printf ("invoked by system bus connection = %s\n", invoked_by_syscon_name);
558 #endif
559
560 /* construct arguments to EJECT (e.g. /usr/bin/eject) */
561 na = 0;
562 args[na++] = EJECT;
563 if (closetray) {
564 args[na++] = "-t";
565 }
566 args[na++] = (char *) device;
567 args[na++] = NULL;
568
569 #ifdef sun
570 putenv("EJECT_DIRECT=1");
571 #endif
572
573 #ifdef DEBUG
574 printf ("will eject %s\n", device);
575 #endif
576
577 /* invoke eject command */
578 if (!g_spawn_sync ("/",
579 args,
580 NULL,
581 0,
582 NULL,
583 NULL,
584 &sout,
585 &serr,
586 &exit_status,
587 &err)) {
588 printf ("Cannot execute %s\n", EJECT);
589 unknown_error ("Cannot spawn " EJECT);
590 }
591
592 #ifdef sun
593 /*
594 * Solaris eject returns 4 for manually ejectable media like floppy.
595 * Consider it success.
596 */
597 if (WEXITSTATUS(exit_status) == 4) {
598 exit_status = 0;
599 }
600
601 if ((adt_data = get_audit_export_data (system_bus,
602 invoked_by_syscon_name, &adt_data_size)) != NULL) {
603 audit_volume (adt_data, ADT_remove, WEXITSTATUS(exit_status),
604 "solaris.device.mount.removable", NULL, device, NULL);
605 free (adt_data);
606 }
607 #endif /* sun */
608
609 /* check if eject was succesful */
610 if (exit_status != 0) {
611 printf ("%s error %d, stdout='%s', stderr='%s'\n", EJECT, exit_status, sout, serr);
612
613 unknown_error (serr);
614 }
615
616 /* eject was succesful... */
617
618 #ifdef DEBUG
619 printf ("done ejecting\n");
620 #endif
621
622 g_free (sout);
623 g_free (serr);
624 }
625
626
627 static int lock_mtab_fd = -1;
628
629 gboolean
lock_hal_mtab(void)630 lock_hal_mtab (void)
631 {
632 if (lock_mtab_fd >= 0)
633 return TRUE;
634
635 printf ("%d: XYA attempting to get lock on /media/.hal-mtab-lock\n", getpid ());
636
637 lock_mtab_fd = open ("/media/.hal-mtab-lock", O_CREAT | O_RDWR);
638
639 if (lock_mtab_fd < 0)
640 return FALSE;
641
642 tryagain:
643 #if sun
644 if (lockf (lock_mtab_fd, F_LOCK, 0) != 0) {
645 #else
646 if (flock (lock_mtab_fd, LOCK_EX) != 0) {
647 #endif
648 if (errno == EINTR)
649 goto tryagain;
650 return FALSE;
651 }
652
653 printf ("%d: XYA got lock on /media/.hal-mtab-lock\n", getpid ());
654
655
656 return TRUE;
657 }
658
659 void
660 unlock_hal_mtab (void)
661 {
662 #if sun
663 lockf (lock_mtab_fd, F_ULOCK, 0);
664 #else
665 flock (lock_mtab_fd, LOCK_UN);
666 #endif
667 close (lock_mtab_fd);
668 lock_mtab_fd = -1;
669 printf ("%d: XYA released lock on /media/.hal-mtab-lock\n", getpid ());
670 }
671
672 #if sun
673
674 /* map PolicyKit privilege to RBAC authorization */
675 char *
676 auth_from_privilege(const char *privilege)
677 {
678 char *authname;
679 int i;
680
681 if (strcmp (privilege, "hal-storage-removable-mount") == 0) {
682 authname = g_strdup ("solaris.device.mount.removable");
683 } else if (strcmp (privilege, "hal-storage-removable-mount-all-options") == 0) {
684 authname = g_strdup ("solaris.device.mount.alloptions.removable");
685 } else if (strcmp (privilege, "hal-storage-fixed-mount") == 0) {
686 authname = g_strdup ("solaris.device.mount.fixed");
687 } else if (strcmp (privilege, "hal-storage-fixed-mount-all-options") == 0) {
688 authname = g_strdup ("solaris.device.mount.alloptions.fixed");
689 } else {
690 /* replace '-' with '.' */
691 authname = g_strdup (privilege);
692 for (i = 0; i < strlen (authname); i++) {
693 if (authname[i] == '-') {
694 authname[i] = '.';
695 }
696 }
697 }
698 return (authname);
699 }
700
701 void
702 audit_volume(const adt_export_data_t *imported_state, au_event_t event_id,
703 int result, const char *auth_used, const char *mount_point,
704 const char *device, const char *options)
705 {
706 adt_session_data_t *ah;
707 adt_event_data_t *event;
708
709 if (adt_start_session(&ah, imported_state, 0) != 0) {
710 printf ("adt_start_session failed %d\n", errno);
711 return;
712 }
713 if ((event = adt_alloc_event(ah, event_id)) == NULL) {
714 printf ("adt_alloc_event(ADT_attach)\n", errno);
715 return;
716 }
717
718 switch (event_id) {
719 case ADT_attach:
720 event->adt_attach.auth_used = (char *)auth_used;
721 event->adt_attach.mount_point = (char *)mount_point;
722 event->adt_attach.device = (char *)device;
723 event->adt_attach.options = (char *)options;
724 break;
725 case ADT_detach:
726 event->adt_detach.auth_used = (char *)auth_used;
727 event->adt_detach.mount_point = (char *)mount_point;
728 event->adt_detach.device = (char *)device;
729 event->adt_detach.options = (char *)options;
730 break;
731 case ADT_remove:
732 event->adt_remove.auth_used = (char *)auth_used;
733 event->adt_remove.mount_point = (char *)mount_point;
734 event->adt_remove.device = (char *)device;
735 break;
736 default:
737 goto out;
738 }
739
740 if (result == 0) {
741 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
742 printf ("adt_put_event(%d, success)\n", event_id);
743 }
744 } else {
745 if (adt_put_event(event, ADT_FAILURE, result) != 0) {
746 printf ("adt_put_event(%d, failure)\n", event_id);
747 }
748 }
749 out:
750 adt_free_event(event);
751 (void) adt_end_session(ah);
752 }
753
754 #endif /* sun */
755