25eb8651467f2949212bc1040a5f225dc6ebfdd0
[profile/ivi/murphy.git] / src / resource / resource.c
1 /*
2  * Copyright (c) 2012, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *  * Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *  * Neither the name of Intel Corporation nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <stdio.h>
31 #include <ctype.h>
32 #include <string.h>
33 #include <errno.h>
34
35 #include <murphy/common/mm.h>
36 #include <murphy/common/log.h>
37
38 #include <murphy-db/mqi.h>
39
40 #include <murphy/resource/client-api.h>
41 #include <murphy/resource/manager-api.h>
42
43 #include "resource.h"
44 #include "resource-owner.h"
45 #include "resource-set.h"
46 #include "application-class.h"
47 #include "zone.h"
48
49
50 #define RESOURCE_MAX        (sizeof(mrp_resource_mask_t) * 8)
51 #define ATTRIBUTE_MAX       (sizeof(mrp_attribute_mask_t) * 8)
52 #define NAME_LENGTH          24
53
54 #define RSETID_IDX           0
55 #define AUTOREL_IDX          1
56 #define STATE_IDX            2
57 #define GRANT_IDX            3
58 #define FIRST_ATTRIBUTE_IDX  4
59
60
61 #define VALID_TYPE(t) ((t) == mqi_string  || \
62                        (t) == mqi_integer || \
63                        (t) == mqi_unsignd || \
64                        (t) == mqi_floating  )
65
66 typedef struct {
67     uint32_t          rsetid;
68     int32_t           autorel;
69     int32_t           state;
70     int32_t           grant;
71     mrp_attr_value_t  attrs[MQI_COLUMN_MAX];
72 } user_row_t;
73
74
75 static uint32_t            resource_def_count;
76 static mrp_resource_def_t *resource_def_table[RESOURCE_MAX];
77 static MRP_LIST_HOOK(manager_list);
78 static mqi_handle_t        resource_user_table[RESOURCE_MAX];
79
80 static uint32_t add_resource_definition(const char *, bool, uint32_t,
81                                         mrp_resource_mgr_ftbl_t *, void *);
82
83 #if 0
84 static uint32_t find_resource_attribute_id(mrp_resource_t *, const char *);
85
86 static mqi_data_type_t   get_resource_attribute_value_type(mrp_resource_t *,
87                                                            uint32_t);
88
89 static mrp_attr_value_t *get_resource_attribute_default_value(mrp_resource_t*,
90                                                               uint32_t);
91 #endif
92
93 static int  resource_user_create_table(mrp_resource_def_t *);
94 static void resource_user_insert(mrp_resource_t *, bool);
95 static void resource_user_delete(mrp_resource_t *);
96
97 static void set_attr_descriptors(mqi_column_desc_t *, mrp_resource_t *);
98
99
100
101 uint32_t mrp_resource_definition_create(const char *name, bool shareable,
102                                         mrp_attr_def_t *attrdefs,
103                                         mrp_resource_mgr_ftbl_t *manager,
104                                         void *mgrdata)
105 {
106     uint32_t nattr;
107     uint32_t id;
108     mrp_resource_def_t *def;
109
110     MRP_ASSERT(name, "invalid argument");
111
112     if (mrp_resource_definition_find_by_name(name)) {
113         mrp_log_error("attmpt to redefine resource '%s'", name);
114         return MRP_RESOURCE_ID_INVALID;
115     }
116
117     for (nattr = 0;  attrdefs && attrdefs[nattr].name;  nattr++)
118         ;
119
120     id = add_resource_definition(name, shareable, nattr, manager, mgrdata);
121
122     if (id != MRP_RESOURCE_ID_INVALID) {
123         def = mrp_resource_definition_find_by_id(id);
124
125         MRP_ASSERT(def, "got confused with data structures");
126
127         if (mrp_attribute_copy_definitions(attrdefs, def->attrdefs) < 0)
128             return MRP_RESOURCE_ID_INVALID;
129
130         resource_user_create_table(def);
131         mrp_resource_owner_create_database_table(def);
132     }
133
134     return id;
135 }
136
137 uint32_t mrp_resource_definition_count(void)
138 {
139     return resource_def_count;
140 }
141
142 mrp_resource_def_t *mrp_resource_definition_find_by_name(const char *name)
143 {
144     mrp_resource_def_t *def;
145     uint32_t            i;
146
147     for (i = 0;  i < resource_def_count;  i++) {
148         def = resource_def_table[i];
149
150         if (def && !strcasecmp(name, def->name))
151             return def;
152     }
153
154     return NULL;
155 }
156
157 uint32_t mrp_resource_definition_get_resource_id_by_name(const char *name)
158 {
159     mrp_resource_def_t *def = mrp_resource_definition_find_by_name(name);
160
161     if (!def) {
162         return MRP_RESOURCE_ID_INVALID;
163     }
164
165     return def->id;
166 }
167
168 mrp_resource_def_t *mrp_resource_definition_find_by_id(uint32_t id)
169 {
170     if (id < resource_def_count)
171         return resource_def_table[id];
172
173     return NULL;
174 }
175
176 mrp_resource_def_t *mrp_resource_definition_iterate_manager(void **cursor)
177 {
178     mrp_list_hook_t *entry;
179
180     MRP_ASSERT(cursor, "invalid argument");
181
182     entry = (*cursor == NULL) ? manager_list.next : (mrp_list_hook_t *)*cursor;
183
184     if (entry == &manager_list)
185         return NULL;
186
187     *cursor = entry->next;
188
189     return mrp_list_entry(entry, mrp_resource_def_t, manager.list);
190 }
191
192 const char **mrp_resource_definition_get_all_names(uint32_t buflen,
193                                                    const char **buf)
194 {
195     uint32_t i;
196
197     MRP_ASSERT(!buf || (buf && buflen > 1), "invlaid argument");
198
199     if (buf) {
200         if (buflen < resource_def_count + 1)
201             return NULL;
202     }
203     else {
204         buflen = resource_def_count + 1;
205         if (!(buf = mrp_allocz(sizeof(const char *) * buflen))) {
206             mrp_log_error("Memory alloc failure. Can't get resource names");
207             return NULL;
208         }
209     }
210
211     for (i = 0;  i < resource_def_count;  i++)
212         buf[i] = resource_def_table[i]->name;
213
214     buf[i] = NULL;
215
216     return buf;
217 }
218
219 mrp_attr_t *mrp_resource_definition_read_all_attributes(uint32_t resid,
220                                                         uint32_t buflen,
221                                                         mrp_attr_t *buf)
222 {
223     mrp_resource_def_t *rdef   = mrp_resource_definition_find_by_id(resid);
224     mrp_attr_t         *retval;
225
226
227     if (!rdef)
228         retval = mrp_attribute_get_all_values(buflen, buf, 0, NULL, 0);
229     else {
230         retval = mrp_attribute_get_all_values(buflen, buf, rdef->nattr,
231                                               rdef->attrdefs, 0);
232     }
233
234     if (!retval) {
235         mrp_log_error("Memory alloc failure. Can't get all "
236                       "attributes of resource definition");
237     }
238
239     return retval;
240 }
241
242
243
244 mrp_resource_t *mrp_resource_create(const char *name,
245                                     uint32_t    rsetid,
246                                     bool        autorel,
247                                     bool        shared,
248                                     mrp_attr_t *attrs)
249 {
250     mrp_resource_t *res = NULL;
251     mrp_resource_def_t *rdef;
252     size_t base_size;
253     size_t attr_size;
254     size_t total_size;
255     int sts;
256
257     MRP_ASSERT(name, "invalid argument");
258
259     if (!(rdef = mrp_resource_definition_find_by_name(name))) {
260         mrp_log_warning("Can't find resource definition '%s'. "
261                         "No resource created", name);
262     }
263     else {
264         base_size  = sizeof(mrp_resource_t);
265         attr_size  = sizeof(mrp_attr_value_t) * rdef->nattr;
266         total_size = base_size + attr_size;
267
268         if (!(res = mrp_allocz(total_size))) {
269             mrp_log_error("Memory alloc failure. Can't create "
270                           "resource '%s'", name);
271         }
272         else {
273             mrp_list_init(&res->list);
274
275             res->rsetid = rsetid;
276             res->def = rdef;
277             res->shared = rdef->shareable ?  shared : false;
278
279             sts = mrp_attribute_set_values(attrs, rdef->nattr,
280                                            rdef->attrdefs, res->attrs);
281             if (sts < 0) {
282                 mrp_log_error("Memory alloc failure. No '%s' "
283                               "resource created", name);
284                 return NULL;
285             }
286
287             resource_user_insert(res, autorel);
288         }
289     }
290
291     return res;
292 }
293
294 void mrp_resource_destroy(mrp_resource_t *res)
295 {
296     mrp_resource_def_t *rdef;
297     mqi_data_type_t type;
298     uint32_t id;
299
300     if (res) {
301         rdef = res->def;
302
303         MRP_ASSERT(rdef, "invalid_argument");
304
305         resource_user_delete(res);
306
307         mrp_list_delete(&res->list);
308
309         for (id = 0;  id < rdef->nattr;  id++) {
310             type = rdef->attrdefs[id].type;
311
312             if (type == mqi_string)
313                 mrp_free((void *)res->attrs[id].string);
314         }
315
316         mrp_free(res);
317     }
318 }
319
320 uint32_t mrp_resource_get_id(mrp_resource_t *res)
321 {
322     mrp_resource_def_t *def;
323
324     if (res) {
325         def = res->def;
326         MRP_ASSERT(def, "confused with internal data structures");
327         return def->id;
328     }
329
330     return MRP_RESOURCE_ID_INVALID;
331 }
332
333 const char *mrp_resource_get_name(mrp_resource_t *res)
334 {
335     mrp_resource_def_t *def;
336
337     if (res) {
338         def = res->def;
339
340         MRP_ASSERT(def && def->name, "confused with internal data structures");
341
342         return def->name;
343     }
344
345     return "<unknown resource>";
346 }
347
348 mrp_resource_mask_t mrp_resource_get_mask(mrp_resource_t *res)
349 {
350     mrp_resource_def_t *def;
351     mrp_resource_mask_t mask = 0;
352
353     if (res) {
354         def = res->def;
355
356         MRP_ASSERT(def, "confused with internal data structures");
357
358         mask = (mrp_resource_mask_t)1 << def->id;
359     }
360
361     return mask;
362 }
363
364 bool mrp_resource_is_shared(mrp_resource_t *res)
365 {
366     if (res)
367         return res->shared;
368
369     return false;
370 }
371
372 mrp_attr_t *mrp_resource_read_attribute(mrp_resource_t *res,
373                                         uint32_t        idx,
374                                         mrp_attr_t     *value)
375 {
376     mrp_attr_t *retval;
377     mrp_resource_def_t *rdef;
378
379     MRP_ASSERT(res, "invalid argument");
380
381     rdef = res->def;
382
383     MRP_ASSERT(rdef, "confused with data structures");
384
385     retval = mrp_attribute_get_value(idx, value, rdef->nattr,
386                                      rdef->attrdefs, res->attrs);
387
388     if (!retval) {
389         mrp_log_error("Memory alloc failure. Can't get "
390                       "resource '%s' attribute %u", rdef->name, idx);
391     }
392
393     return retval;
394 }
395
396
397 mrp_attr_t *mrp_resource_read_all_attributes(mrp_resource_t *res,
398                                              uint32_t nvalue,
399                                              mrp_attr_t *values)
400 {
401     mrp_attr_t *retval;
402     mrp_resource_def_t *rdef;
403
404     MRP_ASSERT(res, "invalid argument");
405
406     rdef = res->def;
407
408     MRP_ASSERT(rdef, "confused with data structures");
409
410     retval = mrp_attribute_get_all_values(nvalue, values, rdef->nattr,
411                                           rdef->attrdefs, res->attrs);
412
413     if (!retval) {
414         mrp_log_error("Memory alloc failure. Can't get all "
415                       "attributes of resource '%s'", rdef->name);
416     }
417
418     return retval;
419 }
420
421 int mrp_resource_write_attributes(mrp_resource_t *res, mrp_attr_t *values)
422 {
423     int sts;
424     mrp_resource_def_t *rdef;
425
426     MRP_ASSERT(res && values, "invalid argument");
427
428     rdef = res->def;
429
430     MRP_ASSERT(rdef, "confused with data structures");
431
432     sts = mrp_attribute_set_values(values, rdef->nattr,
433                                    rdef->attrdefs, res->attrs);
434
435     if (sts < 0) {
436         mrp_log_error("Memory alloc failure. Can't set attributes "
437                       "of resource '%s'", rdef->name);
438     }
439
440     return sts;
441 }
442
443 const char *mrp_resource_get_application_class(mrp_resource_t *res)
444 {
445     mrp_resource_set_t *rset;
446     mrp_application_class_t *class;
447
448     MRP_ASSERT(res, "invalid argument");
449
450     if (!(rset = mrp_resource_set_find_by_id(res->rsetid)))
451         return NULL;
452
453     if (!(class = rset->class.ptr))
454         return NULL;
455
456     return class->name;
457 }
458
459 void mrp_resource_notify(mrp_resource_t *res,
460                          mrp_resource_set_t *rset,
461                          mrp_resource_event_t event)
462 {
463     mrp_resource_def_t *rdef;
464     mrp_resource_mgr_ftbl_t *ftbl;
465     mrp_manager_notify_func_t notify;
466     mrp_application_class_t *class;
467     mrp_zone_t *zone;
468
469     MRP_ASSERT(res && rset, "inavlid argument");
470
471     rdef = res->def;
472
473     MRP_ASSERT(rdef, "confused with data structures");
474
475     if ((ftbl = rdef->manager.ftbl) &&
476         (notify = ftbl->notify) &&
477         (zone = mrp_zone_find_by_id(rset->zone)) &&
478         (class = rset->class.ptr))
479     {
480         notify(event, zone, class, res, rdef->manager.userdata);
481     }
482 }
483
484 int mrp_resource_print(mrp_resource_t *res, uint32_t mandatory,
485                        size_t indent, char *buf, int len)
486 {
487 #define PRINT(fmt, args...)  if (p<e) { p += snprintf(p, e-p, fmt , ##args); }
488
489     mrp_resource_def_t *rdef;
490     char gap[] = "                         ";
491     char *p, *e;
492     uint32_t m;
493
494     if (len <= 0)
495         return 0;
496
497     MRP_ASSERT(res && indent < sizeof(gap)-1 && buf,
498                "invalid argument");
499
500     rdef = res->def;
501
502     MRP_ASSERT(rdef, "Confused with data structures");
503
504     gap[indent] = '\0';
505
506     e = (p = buf) + len;
507     m = ((mrp_resource_mask_t)1 << rdef->id);
508
509     PRINT("%s%s: 0x%02x %s %s", gap, rdef->name, m,
510           (m & mandatory) ? "mandatory":"optional ",
511           res->shared ? "shared  ":"exlusive");
512
513     p += mrp_resource_attribute_print(res, p, e-p);
514
515     PRINT("\n");
516
517
518     return p - buf;
519
520 #undef PRINT
521 }
522
523 int mrp_resource_attribute_print(mrp_resource_t *res, char *buf, int len)
524 {
525     mrp_resource_def_t *rdef;
526
527     if (len <= 0)
528         return 0;
529
530     MRP_ASSERT(res && buf, "invalid argument");
531
532     rdef = res->def;
533
534     MRP_ASSERT(rdef, "Confused with data structures");
535
536     return mrp_attribute_print(rdef->nattr,rdef->attrdefs,res->attrs, buf,len);
537 }
538
539
540 static uint32_t add_resource_definition(const char *name,
541                                         bool        shareable,
542                                         uint32_t    nattr,
543                                         mrp_resource_mgr_ftbl_t *mgrftbl,
544                                         void       *mgrdata)
545 {
546     mrp_resource_def_t *def;
547     const char         *dup_name;
548     size_t              size;
549     uint32_t            id;
550
551     MRP_ASSERT(name && nattr < ATTRIBUTE_MAX, "invalid argument");
552
553     if (resource_def_count >= RESOURCE_MAX) {
554         mrp_log_error("Resource table overflow. Can't add resource '%s'",name);
555         return MRP_RESOURCE_ID_INVALID;
556     }
557
558     size = sizeof(mrp_resource_def_t) + sizeof(mrp_attr_def_t) * nattr;
559
560     if (!(def = mrp_allocz(size)) || !(dup_name = mrp_strdup(name))) {
561         mrp_log_error("Memory alloc failure. Can't add resource '%s'", name);
562         return MRP_RESOURCE_ID_INVALID;
563     }
564
565     id = resource_def_count++;
566
567     def->id        = id;
568     def->name      = dup_name;
569     def->shareable = shareable;
570     def->nattr     = nattr;
571
572     if (mgrftbl) {
573         def->manager.ftbl = mrp_alloc(sizeof(mrp_resource_mgr_ftbl_t));
574         def->manager.userdata = mgrdata;
575
576         if (def->manager.ftbl)
577             memcpy(def->manager.ftbl, mgrftbl,sizeof(mrp_resource_mgr_ftbl_t));
578         else {
579             mrp_log_error("Memory alloc failure. No manager for resource '%s'",
580                           name);
581         }
582     }
583
584     resource_def_table[id] = def;
585
586     if (!mgrftbl)
587         mrp_list_init(&def->manager.list);
588     else
589         mrp_list_append(&manager_list, &def->manager.list);
590
591     return id;
592 }
593
594
595 #if 0
596 static uint32_t find_resource_attribute_id(mrp_resource_t *res,
597                                            const char *attrnam)
598 {
599     mrp_resource_def_t *rdef;
600     mrp_attr_def_t *adef;
601     uint32_t id;
602
603     if (res && (rdef = res->def) && attrnam) {
604         for (id = 0;  id < rdef->nattr;  id++) {
605             adef = rdef->attrdefs + id;
606
607             if (!strcasecmp(attrnam, adef->name))
608                 return id;
609         }
610     }
611
612     return MRP_RESOURCE_ID_INVALID;
613 }
614
615 static mqi_data_type_t
616 get_resource_attribute_value_type(mrp_resource_t *res, uint32_t id)
617 {
618     mrp_resource_def_t *rdef;
619
620     MRP_ASSERT(res, "invalid argument");
621
622     rdef = res->def;
623
624     MRP_ASSERT(rdef, "confused with data structures");
625     MRP_ASSERT(id < rdef->nattr, "invalid argument");
626
627     return rdef->attrdefs[id].type;
628 }
629
630 static mrp_attr_value_t *
631 get_resource_attribute_default_value(mrp_resource_t *res, uint32_t id)
632 {
633     mrp_resource_def_t *rdef;
634
635     MRP_ASSERT(res, "invalid argument");
636
637     rdef = res->def;
638
639     MRP_ASSERT(rdef, "confused with data structures");
640     MRP_ASSERT(id < rdef->nattr, "invalid argument");
641
642     return &rdef->attrdefs[id].value;
643 }
644 #endif
645
646
647 static int resource_user_create_table(mrp_resource_def_t *rdef)
648 {
649     MQI_COLUMN_DEFINITION_LIST(base_coldefs,
650         MQI_COLUMN_DEFINITION( "rsetid" , MQI_UNSIGNED ),
651         MQI_COLUMN_DEFINITION( "autorel", MQI_INTEGER  ),
652         MQI_COLUMN_DEFINITION( "state"  , MQI_INTEGER  ),
653         MQI_COLUMN_DEFINITION( "grant"  , MQI_INTEGER  )
654     );
655
656     MQI_INDEX_DEFINITION(indexdef,
657         MQI_INDEX_COLUMN( "rsetid" )
658     );
659
660     static bool initialized = false;
661
662     char name[256];
663     mqi_column_def_t  coldefs[MQI_COLUMN_MAX + 1];
664     mqi_column_def_t *col;
665     mrp_attr_def_t *atd;
666     mqi_handle_t table;
667     char c, *p;
668     size_t i,j;
669
670     if (!initialized) {
671         mqi_open();
672         for (i = 0;  i < RESOURCE_MAX;  i++)
673             resource_user_table[i] = MQI_HANDLE_INVALID;
674         initialized = true;
675     }
676
677     MRP_ASSERT(sizeof(base_coldefs) < sizeof(coldefs),"too many base columns");
678     MRP_ASSERT(rdef, "invalid argument");
679     MRP_ASSERT(rdef->id < RESOURCE_MAX, "confused with data structures");
680     MRP_ASSERT(resource_user_table[rdef->id] == MQI_HANDLE_INVALID,
681                "resource user table already exist");
682
683     snprintf(name, sizeof(name), "%s_users", rdef->name);
684     for (p = name; (c = *p);  p++) {
685         if (!isascii(c) || (!isalnum(c) && c != '_'))
686             *p = '_';
687     }
688
689     j = MQI_DIMENSION(base_coldefs) - 1;
690     memcpy(coldefs, base_coldefs, j * sizeof(mqi_column_def_t));
691
692     for (i = 0;  i < rdef->nattr && j < MQI_COLUMN_MAX;  i++, j++) {
693         col = coldefs + j;
694         atd = rdef->attrdefs + i;
695
696         col->name   = atd->name;
697         col->type   = atd->type;
698         col->length = (col->type == mqi_string) ? NAME_LENGTH : 0;
699         col->flags  = 0;
700     }
701
702     memset(coldefs + j, 0, sizeof(mqi_column_def_t));
703
704     table = MQI_CREATE_TABLE(name, MQI_TEMPORARY, coldefs, indexdef);
705
706     if (table == MQI_HANDLE_INVALID) {
707         mrp_log_error("Can't create table '%s': %s", name, strerror(errno));
708         return -1;
709     }
710
711     resource_user_table[rdef->id] = table;
712
713     return 0;
714 }
715
716 static void resource_user_insert(mrp_resource_t *res, bool autorel)
717 {
718     mrp_resource_def_t *rdef = res->def;
719     uint32_t i;
720     int n;
721     user_row_t row;
722     user_row_t *rows[2];
723     mqi_column_desc_t cdsc[FIRST_ATTRIBUTE_IDX + MQI_COLUMN_MAX + 1];
724
725     MRP_ASSERT(FIRST_ATTRIBUTE_IDX + rdef->nattr <= MQI_COLUMN_MAX,
726                "too many attributes for a table");
727
728     row.rsetid   = res->rsetid;
729     row.autorel  = autorel;
730     row.grant    = 0;
731     row.state    = mrp_resource_no_request;
732     memcpy(row.attrs, res->attrs, rdef->nattr * sizeof(mrp_attr_value_t));
733
734     i = 0;
735     cdsc[i].cindex = RSETID_IDX;
736     cdsc[i].offset = MQI_OFFSET(user_row_t, rsetid);
737
738     i++;
739     cdsc[i].cindex = AUTOREL_IDX;
740     cdsc[i].offset = MQI_OFFSET(user_row_t, autorel);
741
742     i++;
743     cdsc[i].cindex = STATE_IDX;
744     cdsc[i].offset = MQI_OFFSET(user_row_t, state);
745
746     i++;
747     cdsc[i].cindex = GRANT_IDX;
748     cdsc[i].offset = MQI_OFFSET(user_row_t, grant);
749
750     set_attr_descriptors(cdsc + (i+1), res);
751
752     rows[0] = &row;
753     rows[1] = NULL;
754
755     if ((n = MQI_INSERT_INTO(resource_user_table[rdef->id], cdsc, rows)) != 1)
756         mrp_log_error("can't insert row into resource user table");
757 }
758
759 static void resource_user_delete(mrp_resource_t *res)
760 {
761     static uint32_t rsetid;
762
763     MQI_WHERE_CLAUSE(where,
764         MQI_EQUAL( MQI_COLUMN(RSETID_IDX), MQI_UNSIGNED_VAR(rsetid) )
765     );
766
767     mrp_resource_def_t *rdef;
768     int n;
769
770     MRP_ASSERT(res, "invalid argument");
771
772     rdef = res->def;
773     rsetid = res->rsetid;
774
775     if ((n = MQI_DELETE(resource_user_table[rdef->id], where)) != 1)
776         mrp_log_error("Could not delete resource user");
777 }
778
779 void mrp_resource_user_update(mrp_resource_t *res, int state, bool grant)
780 {
781     static uint32_t rsetid;
782
783     MQI_WHERE_CLAUSE(where,
784         MQI_EQUAL( MQI_COLUMN(RSETID_IDX), MQI_UNSIGNED_VAR(rsetid) )
785     );
786
787     mrp_resource_def_t *rdef = res->def;
788     uint32_t i;
789     int n;
790     user_row_t row;
791     mqi_column_desc_t cdsc[FIRST_ATTRIBUTE_IDX + MQI_COLUMN_MAX + 1];
792
793     rsetid = res->rsetid;
794
795     MRP_ASSERT(1 + rdef->nattr <= MQI_COLUMN_MAX,
796                "too many attributes for a table");
797
798     row.state = state;
799     row.grant = grant;
800     memcpy(row.attrs, res->attrs, rdef->nattr * sizeof(mrp_attr_value_t));
801
802     i = 0;
803     cdsc[i].cindex = STATE_IDX;
804     cdsc[i].offset = MQI_OFFSET(user_row_t, state);
805
806     i++;
807     cdsc[i].cindex = GRANT_IDX;
808     cdsc[i].offset = MQI_OFFSET(user_row_t, grant);
809
810     set_attr_descriptors(cdsc + (i+1), res);
811
812     if ((n = MQI_UPDATE(resource_user_table[rdef->id], cdsc,&row, where)) != 1)
813         mrp_log_error("can't update row in resource user table");
814 }
815
816 static void set_attr_descriptors(mqi_column_desc_t *cdsc, mrp_resource_t *res)
817 {
818     mrp_resource_def_t *rdef = res->def;
819     uint32_t i,j;
820     int o;
821
822     for (i = j = 0;  j < rdef->nattr;  j++) {
823         switch (rdef->attrdefs[j].type) {
824         case mqi_string:   o = MQI_OFFSET(user_row_t,attrs[j].string);  break;
825         case mqi_integer:  o = MQI_OFFSET(user_row_t,attrs[j].integer); break;
826         case mqi_unsignd:  o = MQI_OFFSET(user_row_t,attrs[j].unsignd); break;
827         case mqi_floating: o = MQI_OFFSET(user_row_t,attrs[j].floating);break;
828         default:           /* skip this */                            continue;
829         }
830
831         cdsc[i].cindex = FIRST_ATTRIBUTE_IDX + j;
832         cdsc[i].offset = o;
833         i++;
834     }
835
836     cdsc[i].cindex = -1;
837     cdsc[i].offset =  1;
838 }
839
840
841
842 /*
843  * Local Variables:
844  * c-basic-offset: 4
845  * indent-tabs-mode: nil
846  * End:
847  *
848  */