multipath-tools: Introducing multipath C API
[multipath-tools/.git] / libdmmp / libdmmp_pg.c
1 /*
2  * Copyright (C) 2015 - 2016 Red Hat, Inc.
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Author: Gris Ge <fge@redhat.com>
18  *         Todd Gill <tgill@redhat.com>
19  */
20
21 #include <stdlib.h>
22 #include <stdint.h>
23 #include <inttypes.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <json.h>
27
28 #include "libdmmp/libdmmp.h"
29 #include "libdmmp_private.h"
30
31 #define _DMMP_SHOW_PGS_CMD "show groups raw format %w|%g|%p|%t|%s"
32 #define _DMMP_SHOW_PG_INDEX_WWID        0
33 #define _DMMP_SHOW_PG_INDEX_PG_ID       1
34 #define _DMMP_SHOW_PG_INDEX_PRI         2
35 #define _DMMP_SHOW_PG_INDEX_STATUS      3
36 #define _DMMP_SHOW_PG_INDEX_SELECTOR    4
37
38 struct dmmp_path_group {
39         uint32_t id;
40         /* ^ pgindex of struct path, will be used for path group switch */
41         uint32_t status;
42         uint32_t priority;
43         char *selector;
44         uint32_t dmmp_p_count;
45         struct dmmp_path **dmmp_ps;
46 };
47
48 static const struct _num_str_conv _DMMP_PATH_GROUP_STATUS_CONV[] = {
49         {DMMP_PATH_GROUP_STATUS_UNKNOWN, "undef"},
50         {DMMP_PATH_GROUP_STATUS_ACTIVE, "active"},
51         {DMMP_PATH_GROUP_STATUS_DISABLED, "disabled"},
52         {DMMP_PATH_GROUP_STATUS_ENABLED, "enabled"},
53 };
54
55 _dmmp_str_func_gen(dmmp_path_group_status_str, uint32_t, pg_status,
56                    _DMMP_PATH_GROUP_STATUS_CONV);
57 _dmmp_str_conv_func_gen(_dmmp_path_group_status_str_conv, ctx, pg_status_str,
58                         uint32_t, DMMP_PATH_GROUP_STATUS_UNKNOWN,
59                         _DMMP_PATH_GROUP_STATUS_CONV);
60
61 _dmmp_getter_func_gen(dmmp_path_group_id_get, struct dmmp_path_group, dmmp_pg,
62                       id, uint32_t);
63 _dmmp_getter_func_gen(dmmp_path_group_status_get, struct dmmp_path_group,
64                       dmmp_pg, status, uint32_t);
65 _dmmp_getter_func_gen(dmmp_path_group_priority_get, struct dmmp_path_group,
66                       dmmp_pg, priority, uint32_t);
67 _dmmp_getter_func_gen(dmmp_path_group_selector_get, struct dmmp_path_group,
68                       dmmp_pg, selector, const char *);
69 _dmmp_array_free_func_gen(_dmmp_path_group_array_free, struct dmmp_path_group,
70                           _dmmp_path_group_free);
71
72
73 struct dmmp_path_group *_dmmp_path_group_new(void)
74 {
75         struct dmmp_path_group *dmmp_pg = NULL;
76
77         dmmp_pg = (struct dmmp_path_group *)
78                 malloc(sizeof(struct dmmp_path_group));
79
80         if (dmmp_pg != NULL) {
81                 dmmp_pg->id = _DMMP_PATH_GROUP_ID_UNKNOWN;
82                 dmmp_pg->status = DMMP_PATH_GROUP_STATUS_UNKNOWN;
83                 dmmp_pg->priority = 0;
84                 dmmp_pg->selector = NULL;
85                 dmmp_pg->dmmp_p_count = 0;
86                 dmmp_pg->dmmp_ps = NULL;
87         }
88         return dmmp_pg;
89 }
90 int _dmmp_path_group_update(struct dmmp_context *ctx,
91                             struct dmmp_path_group *dmmp_pg,
92                             json_object *j_obj_pg)
93 {
94         int rc = DMMP_OK;
95         uint32_t id = 0;
96         int priority_int = -1 ;
97         const char *status_str = NULL;
98         const char *selector = NULL;
99         struct array_list *ar_ps = NULL;
100         int ar_ps_len = -1;
101         uint32_t i = 0;
102         struct dmmp_path *dmmp_p = NULL;
103
104         assert(ctx != NULL);
105         assert(dmmp_pg != NULL);
106         assert(j_obj_pg != NULL);
107
108         _json_obj_get_value(ctx, j_obj_pg, status_str, "dm_st",
109                             json_type_string, json_object_get_string, rc, out);
110
111         _json_obj_get_value(ctx, j_obj_pg, selector, "selector",
112                             json_type_string, json_object_get_string, rc, out);
113
114         _json_obj_get_value(ctx, j_obj_pg, priority_int, "pri",
115                             json_type_int, json_object_get_int, rc, out);
116
117         _json_obj_get_value(ctx, j_obj_pg, id, "group",
118                             json_type_int, json_object_get_int, rc, out);
119
120         dmmp_pg->priority = (priority_int <= 0) ? 0 : priority_int & UINT32_MAX;
121
122         _dmmp_null_or_empty_str_check(ctx, status_str, rc, out);
123         _dmmp_null_or_empty_str_check(ctx, selector, rc, out);
124
125         dmmp_pg->selector = strdup(selector);
126         _dmmp_alloc_null_check(ctx, dmmp_pg->selector, rc, out);
127
128         dmmp_pg->id = id;
129
130         if (dmmp_pg->id == _DMMP_PATH_GROUP_ID_UNKNOWN) {
131                 rc = DMMP_ERR_BUG;
132                 _error(ctx, "BUG: Got unknown(%d) path group ID",
133                        _DMMP_PATH_GROUP_ID_UNKNOWN);
134                 goto out;
135         }
136
137         dmmp_pg->status = _dmmp_path_group_status_str_conv(ctx, status_str);
138
139         _json_obj_get_value(ctx, j_obj_pg, ar_ps, "paths",
140                             json_type_array, json_object_get_array, rc, out);
141
142         ar_ps_len = array_list_length(ar_ps);
143         if (ar_ps_len < 0) {
144                 rc = DMMP_ERR_BUG;
145                 _error(ctx, "BUG: Got negative length for ar_ps");
146                 goto out;
147         }
148         else if (ar_ps_len == 0)
149                 goto out;
150         else
151                 dmmp_pg->dmmp_p_count = ar_ps_len & UINT32_MAX;
152
153         dmmp_pg->dmmp_ps = (struct dmmp_path **)
154                 malloc(sizeof(struct dmmp_path *) * dmmp_pg->dmmp_p_count);
155         _dmmp_alloc_null_check(ctx, dmmp_pg->dmmp_ps, rc, out);
156         for (; i < dmmp_pg->dmmp_p_count; ++i)
157                 dmmp_pg->dmmp_ps[i] = NULL;
158
159         for (i = 0; i < dmmp_pg->dmmp_p_count; ++i) {
160                 dmmp_p = _dmmp_path_new();
161                 _dmmp_alloc_null_check(ctx, dmmp_p, rc, out);
162                 dmmp_pg->dmmp_ps[i] = dmmp_p;
163                 _good(_dmmp_path_update(ctx, dmmp_p,
164                                         array_list_get_idx(ar_ps, i)),
165                       rc, out);
166         }
167
168         _debug(ctx, "Got path group id: %" PRIu32 "", dmmp_pg->id);
169         _debug(ctx, "Got path group priority: %" PRIu32 "", dmmp_pg->priority);
170         _debug(ctx, "Got path group status: %s(%" PRIu32 ")",
171                dmmp_path_group_status_str(dmmp_pg->status), dmmp_pg->status);
172         _debug(ctx, "Got path group selector: '%s'", dmmp_pg->selector);
173
174 out:
175         if (rc != DMMP_OK)
176                 _dmmp_path_group_free(dmmp_pg);
177         return rc;
178 }
179
180 void _dmmp_path_group_free(struct dmmp_path_group *dmmp_pg)
181 {
182         uint32_t i = 0;
183
184         if (dmmp_pg == NULL)
185                 return;
186
187         free((char *) dmmp_pg->selector);
188
189         if (dmmp_pg->dmmp_ps != NULL) {
190                 for (i = 0; i < dmmp_pg->dmmp_p_count; ++i) {
191                         _dmmp_path_free(dmmp_pg->dmmp_ps[i]);
192                 }
193                 free(dmmp_pg->dmmp_ps);
194         }
195         free(dmmp_pg);
196 }
197
198 void dmmp_path_array_get(struct dmmp_path_group *mp_pg,
199                          struct dmmp_path ***mp_paths,
200                          uint32_t *dmmp_p_count)
201 {
202         assert(mp_pg != NULL);
203         assert(mp_paths != NULL);
204         assert(dmmp_p_count != NULL);
205
206         *mp_paths = mp_pg->dmmp_ps;
207         *dmmp_p_count = mp_pg->dmmp_p_count;
208 }