midlevel.c (bc9767f9) midlevel.c (dfac3eb2)
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE

--- 10 unchanged lines hidden (view full) ---

19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE

--- 10 unchanged lines hidden (view full) ---

19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident "%Z%%M% %I% %E% SMI"
28
29#include "libscf_impl.h"
30
31#include <libuutil.h>
32#include <stdio.h>
33#include <strings.h>
34#include <string.h>
35#include <stdlib.h>
36#include <sys/param.h>
37#include <errno.h>
38#include <libgen.h>
27#include "libscf_impl.h"
28
29#include <libuutil.h>
30#include <stdio.h>
31#include <strings.h>
32#include <string.h>
33#include <stdlib.h>
34#include <sys/param.h>
35#include <errno.h>
36#include <libgen.h>
37#include <assert.h>
39#include "midlevel_impl.h"
40#include "lowlevel_impl.h"
41
42#ifndef NDEBUG
43#define bad_error(func, err) { \
44 uu_warn("%s:%d: %s failed with unexpected error %d. Aborting.\n", \
45 __FILE__, __LINE__, func, err); \
46 abort(); \

--- 2433 unchanged lines hidden (view full) ---

2480
2481 if (temp_filename) {
2482 (void) strcpy(temp_filename, filename);
2483 (void) strcat(temp_filename, "XXXXXX");
2484 }
2485
2486 return (0);
2487}
38#include "midlevel_impl.h"
39#include "lowlevel_impl.h"
40
41#ifndef NDEBUG
42#define bad_error(func, err) { \
43 uu_warn("%s:%d: %s failed with unexpected error %d. Aborting.\n", \
44 __FILE__, __LINE__, func, err); \
45 abort(); \

--- 2433 unchanged lines hidden (view full) ---

2479
2480 if (temp_filename) {
2481 (void) strcpy(temp_filename, filename);
2482 (void) strcat(temp_filename, "XXXXXX");
2483 }
2484
2485 return (0);
2486}
2487
2488static scf_type_t
2489scf_true_base_type(scf_type_t type)
2490{
2491 scf_type_t base = type;
2492
2493 do {
2494 type = base;
2495 (void) scf_type_base_type(type, &base);
2496 } while (base != type);
2497
2498 return (base);
2499}
2500
2501/*
2502 * Convenience routine which frees all strings and opaque data
2503 * allocated by scf_read_propvec.
2504 *
2505 * Like free(3C), this function preserves the value of errno.
2506 */
2507void
2508scf_clean_propvec(scf_propvec_t *propvec)
2509{
2510 int saved_errno = errno;
2511 scf_propvec_t *prop;
2512
2513 for (prop = propvec; prop->pv_prop != NULL; prop++) {
2514 assert(prop->pv_type != SCF_TYPE_INVALID);
2515 if (prop->pv_type == SCF_TYPE_OPAQUE) {
2516 scf_opaque_t *o = prop->pv_ptr;
2517
2518 if (o->so_addr != NULL)
2519 free(o->so_addr);
2520 } else if (scf_true_base_type(prop->pv_type) ==
2521 SCF_TYPE_ASTRING) {
2522 if (*(char **)prop->pv_ptr != NULL)
2523 free(*(char **)prop->pv_ptr);
2524 }
2525 }
2526
2527 errno = saved_errno;
2528}
2529
2530static int
2531count_props(scf_propvec_t *props)
2532{
2533 int count = 0;
2534
2535 for (; props->pv_prop != NULL; props++)
2536 count++;
2537 return (count);
2538}
2539
2540/*
2541 * Reads a vector of properties from the specified fmri/property group.
2542 * If 'running' is true, reads from the running snapshot instead of the
2543 * editing snapshot.
2544 *
2545 * For string types, a buffer is allocated using malloc(3C) to hold the
2546 * zero-terminated string, a pointer to which is stored in the
2547 * caller-provided char **. It is the caller's responsbility to free
2548 * this string. To simplify error handling, unread strings are
2549 * initialized to NULL.
2550 *
2551 * For opaque types, a buffer is allocated using malloc(3C) to hold the
2552 * opaque data. A pointer to this buffer and its size are stored in
2553 * the caller-provided scf_opaque_t. It is the caller's responsibility
2554 * to free this buffer. To simplify error handling, the address fields
2555 * for unread opaque data are initialized to NULL.
2556 *
2557 * All other data is stored directly in caller-provided variables or
2558 * structures.
2559 *
2560 * If this function fails to read a specific property, *badprop is set
2561 * to point at that property's entry in the properties array.
2562 *
2563 * On all failures, all memory allocated by this function is freed.
2564 */
2565int
2566scf_read_propvec(const char *fmri, const char *pgname, boolean_t running,
2567 scf_propvec_t *properties, scf_propvec_t **badprop)
2568{
2569 scf_handle_t *h = handle_create();
2570 scf_service_t *s = scf_service_create(h);
2571 scf_instance_t *i = scf_instance_create(h);
2572 scf_snapshot_t *snap = running ? scf_snapshot_create(h) : NULL;
2573 scf_propertygroup_t *pg = scf_pg_create(h);
2574 scf_property_t *p = scf_property_create(h);
2575 scf_value_t *v = scf_value_create(h);
2576 boolean_t instance = B_TRUE;
2577 scf_propvec_t *prop;
2578 int error = 0;
2579
2580 if (h == NULL || s == NULL || i == NULL || (running && snap == NULL) ||
2581 pg == NULL || p == NULL || v == NULL)
2582 goto scferror;
2583
2584 if (scf_handle_decode_fmri(h, fmri, NULL, s, i, NULL, NULL, 0) == -1)
2585 goto scferror;
2586
2587 if (scf_instance_to_fmri(i, NULL, 0) == -1) {
2588 if (scf_error() != SCF_ERROR_NOT_SET)
2589 goto scferror;
2590 instance = B_FALSE;
2591 }
2592
2593 if (running) {
2594 if (!instance) {
2595 error = SCF_ERROR_TYPE_MISMATCH;
2596 goto out;
2597 }
2598
2599 if (scf_instance_get_snapshot(i, "running", snap) !=
2600 SCF_SUCCESS)
2601 goto scferror;
2602 }
2603
2604 if ((instance ? scf_instance_get_pg_composed(i, snap, pgname, pg) :
2605 scf_service_get_pg(s, pgname, pg)) == -1)
2606 goto scferror;
2607
2608 for (prop = properties; prop->pv_prop != NULL; prop++) {
2609 if (prop->pv_type == SCF_TYPE_OPAQUE)
2610 ((scf_opaque_t *)prop->pv_ptr)->so_addr = NULL;
2611 else if (scf_true_base_type(prop->pv_type) == SCF_TYPE_ASTRING)
2612 *((char **)prop->pv_ptr) = NULL;
2613 }
2614
2615 for (prop = properties; prop->pv_prop != NULL; prop++) {
2616 int ret = 0;
2617
2618 if (scf_pg_get_property(pg, prop->pv_prop, p) == -1 ||
2619 scf_property_get_value(p, v) == -1) {
2620 *badprop = prop;
2621 goto scferror;
2622 }
2623 switch (prop->pv_type) {
2624 case SCF_TYPE_BOOLEAN: {
2625 uint8_t b;
2626
2627 ret = scf_value_get_boolean(v, &b);
2628 if (ret == -1)
2629 break;
2630 if (prop->pv_aux != 0) {
2631 uint64_t *bits = prop->pv_ptr;
2632 *bits = b ? (*bits | prop->pv_aux) :
2633 (*bits & ~prop->pv_aux);
2634 } else {
2635 boolean_t *bool = prop->pv_ptr;
2636 *bool = b ? B_TRUE : B_FALSE;
2637 }
2638 break;
2639 }
2640 case SCF_TYPE_COUNT:
2641 ret = scf_value_get_count(v, prop->pv_ptr);
2642 break;
2643 case SCF_TYPE_INTEGER:
2644 ret = scf_value_get_integer(v, prop->pv_ptr);
2645 break;
2646 case SCF_TYPE_TIME: {
2647 scf_time_t *time = prop->pv_ptr;
2648
2649 ret = scf_value_get_time(v, &time->st_sec,
2650 &time->st_nanosec);
2651 break;
2652 }
2653 case SCF_TYPE_OPAQUE: {
2654 scf_opaque_t *opaque = prop->pv_ptr;
2655 ssize_t size = scf_value_get_opaque(v, NULL, 0);
2656
2657 if (size == -1) {
2658 *badprop = prop;
2659 goto scferror;
2660 }
2661 if ((opaque->so_addr = malloc(size)) == NULL) {
2662 error = SCF_ERROR_NO_MEMORY;
2663 goto out;
2664 }
2665 opaque->so_size = size;
2666 ret = scf_value_get_opaque(v, opaque->so_addr, size);
2667 break;
2668 }
2669 default: {
2670 char *s;
2671 ssize_t size;
2672
2673 assert(scf_true_base_type(prop->pv_type) ==
2674 SCF_TYPE_ASTRING);
2675
2676 size = scf_value_get_astring(v, NULL, 0);
2677 if (size == -1) {
2678 *badprop = prop;
2679 goto scferror;
2680 }
2681 if ((s = malloc(++size)) == NULL) {
2682 error = SCF_ERROR_NO_MEMORY;
2683 goto out;
2684 }
2685 ret = scf_value_get_astring(v, s, size);
2686 *(char **)prop->pv_ptr = s;
2687 }
2688
2689 if (ret == -1) {
2690 *badprop = prop;
2691 goto scferror;
2692 }
2693
2694 }
2695 }
2696
2697 goto out;
2698
2699scferror:
2700 error = scf_error();
2701 scf_clean_propvec(properties);
2702
2703out:
2704 scf_pg_destroy(pg);
2705 scf_snapshot_destroy(snap);
2706 scf_instance_destroy(i);
2707 scf_service_destroy(s);
2708 scf_handle_destroy(h);
2709
2710 if (error != 0) {
2711 (void) scf_set_error(error);
2712 return (SCF_FAILED);
2713 }
2714
2715 return (SCF_SUCCESS);
2716}
2717
2718/*
2719 * Writes a vector of properties to the specified fmri/property group.
2720 *
2721 * If this function fails to write a specific property, *badprop is set
2722 * to point at that property's entry in the properties array.
2723 *
2724 * One significant difference between this function and the
2725 * scf_read_propvec function is that for string types, pv_ptr is a
2726 * char *, not a char **. This means that you can't write a propvec
2727 * you just read, but makes other uses (hopefully the majority) simpler.
2728 */
2729int
2730scf_write_propvec(const char *fmri, const char *pgname,
2731 scf_propvec_t *properties, scf_propvec_t **badprop)
2732{
2733 scf_handle_t *h = handle_create();
2734 scf_service_t *s = scf_service_create(h);
2735 scf_instance_t *inst = scf_instance_create(h);
2736 scf_snapshot_t *snap = scf_snapshot_create(h);
2737 scf_propertygroup_t *pg = scf_pg_create(h);
2738 scf_property_t *p = scf_property_create(h);
2739 scf_transaction_t *tx = scf_transaction_create(h);
2740 scf_value_t **v = NULL;
2741 scf_transaction_entry_t **e = NULL;
2742 boolean_t instance = B_TRUE;
2743 int i, n;
2744 scf_propvec_t *prop;
2745 int error = 0, ret;
2746
2747 n = count_props(properties);
2748 v = calloc(n, sizeof (scf_value_t *));
2749 e = calloc(n, sizeof (scf_transaction_entry_t *));
2750
2751 if (v == NULL || e == NULL) {
2752 error = SCF_ERROR_NO_MEMORY;
2753 goto out;
2754 }
2755
2756 if (h == NULL || s == NULL || inst == NULL || pg == NULL || p == NULL ||
2757 tx == NULL)
2758 goto scferror;
2759
2760 for (i = 0; i < n; i++) {
2761 v[i] = scf_value_create(h);
2762 e[i] = scf_entry_create(h);
2763 if (v[i] == NULL || e[i] == NULL)
2764 goto scferror;
2765 }
2766
2767 if (scf_handle_decode_fmri(h, fmri, NULL, s, inst, NULL, NULL, 0)
2768 != SCF_SUCCESS)
2769 goto scferror;
2770
2771 if (scf_instance_to_fmri(inst, NULL, 0) == -1) {
2772 if (scf_error() != SCF_ERROR_NOT_SET)
2773 goto scferror;
2774 instance = B_FALSE;
2775 }
2776
2777 if ((instance ? scf_instance_get_pg(inst, pgname, pg) :
2778 scf_service_get_pg(s, pgname, pg)) == -1)
2779 goto scferror;
2780
2781top:
2782 if (scf_transaction_start(tx, pg) == -1)
2783 goto scferror;
2784
2785 for (prop = properties, i = 0; prop->pv_prop != NULL; prop++, i++) {
2786 ret = scf_transaction_property_change(tx, e[i], prop->pv_prop,
2787 prop->pv_type);
2788 if (ret == -1 && scf_error() == SCF_ERROR_NOT_FOUND)
2789 ret = scf_transaction_property_new(tx, e[i],
2790 prop->pv_prop, prop->pv_type);
2791
2792 if (ret == -1) {
2793 *badprop = prop;
2794 goto scferror;
2795 }
2796
2797 switch (prop->pv_type) {
2798 case SCF_TYPE_BOOLEAN: {
2799 boolean_t b = (prop->pv_aux != 0) ?
2800 (*(uint64_t *)prop->pv_ptr & prop->pv_aux) != 0 :
2801 *(boolean_t *)prop->pv_ptr;
2802
2803 scf_value_set_boolean(v[i], b ? 1 : 0);
2804 break;
2805 }
2806 case SCF_TYPE_COUNT:
2807 scf_value_set_count(v[i], *(uint64_t *)prop->pv_ptr);
2808 break;
2809 case SCF_TYPE_INTEGER:
2810 scf_value_set_integer(v[i], *(int64_t *)prop->pv_ptr);
2811 break;
2812 case SCF_TYPE_TIME: {
2813 scf_time_t *time = prop->pv_ptr;
2814
2815 ret = scf_value_set_time(v[i], time->st_sec,
2816 time->st_nanosec);
2817 break;
2818 }
2819 case SCF_TYPE_OPAQUE: {
2820 scf_opaque_t *opaque = prop->pv_ptr;
2821
2822 ret = scf_value_set_opaque(v[i], opaque->so_addr,
2823 opaque->so_size);
2824 break;
2825 }
2826 case SCF_TYPE_ASTRING:
2827 ret = scf_value_set_astring(v[i],
2828 (const char *)prop->pv_ptr);
2829 break;
2830 default:
2831 ret = scf_value_set_from_string(v[i], prop->pv_type,
2832 (const char *)prop->pv_ptr);
2833 }
2834
2835 if (ret == -1 || scf_entry_add_value(e[i], v[i]) == -1) {
2836 *badprop = prop;
2837 goto scferror;
2838 }
2839 }
2840
2841 ret = scf_transaction_commit(tx);
2842 if (ret == 1)
2843 goto out;
2844
2845 if (ret == 0 && scf_pg_update(pg) != -1) {
2846 scf_transaction_reset(tx);
2847 goto top;
2848 }
2849
2850scferror:
2851 error = scf_error();
2852
2853out:
2854 if (v != NULL) {
2855 for (i = 0; i < n; i++)
2856 scf_value_destroy(v[i]);
2857 free(v);
2858 }
2859
2860 if (e != NULL) {
2861 for (i = 0; i < n; i++)
2862 scf_entry_destroy(e[i]);
2863 free(e);
2864 }
2865
2866 scf_transaction_destroy(tx);
2867 scf_property_destroy(p);
2868 scf_pg_destroy(pg);
2869 scf_snapshot_destroy(snap);
2870 scf_instance_destroy(inst);
2871 scf_service_destroy(s);
2872 scf_handle_destroy(h);
2873
2874 if (error != 0) {
2875 (void) scf_set_error(error);
2876 return (SCF_FAILED);
2877 }
2878
2879 return (SCF_SUCCESS);
2880}