#include "state.h" // FREE void Free_interface_configuration(interface_configuration *E) { free(E->Name); switch(E->Type) { case interface_type_eiface: break; case interface_type_steal: free(E->steal.Interface); break; case interface_type_COUNT: default: __builtin_unreachable(); } } void Free_interfaces_configuration(interfaces_configuration *E) { for(size_t i = 0; i < E->Count; ++i) Free_interface_configuration(E->_ + i); free(E->_); } void Free_mapping(mapping *E) { free(E->Source); free(E->Target); } void Free_filesystem_configuration(filesystem_configuration *E) { for(size_t i = 0; i < E->LayerCount; ++i) free(E->Layer[i]); if(E->Layer != NULL) free(E->Layer); if(E->Temporary != NULL) free(E->Temporary); for(size_t i = 0; i < E->VolumeCount; ++i) Free_mapping(E->Volume + i); if(E->Volume != NULL) free(E->Volume); } void Free_configuration(configuration *E) { Free_filesystem_configuration(&E->Filesystem); Free_interfaces_configuration(&E->Interfaces); Free_string_array(&E->Init); Free_string_array(&E->Shutdown); } void Free_interface(interface *E) { UNUSED(E); } void Free_interfaces(interfaces *E) { for(size_t i = 0; i < E->Count; ++i) Free_interface(E->_ + i); free(E->_); } void Free_data(data *E) { Free_interfaces(&E->Interfaces); } // PARSE char * Parse_interface_type(interface_type *E, ucl_object_t const *root, char const *Position) { char *Error; UCL_CHECK_ROOT(STRING); char const *Type = ucl_object_tostring(root); for(interface_type i = 0; i < interface_type_COUNT; ++i) { if(strcmp(interface_type_Names[i], Type) == 0) { *E = i; return NULL; } } asprintf(&Error, "%s invalid interface type '%s'", Position, Type); goto error; error: return Error; } char * Parse_interface_configuration(interface_configuration *E, ucl_object_t const *root, char const *Position) { char *Error; UCL_CHECK_ROOT(OBJECT); { char *NewPosition; asprintf(&NewPosition, "%s.type", Position); Error = Parse_interface_type(&E->Type, ucl_object_lookup(root, "type"), NewPosition); free(NewPosition); if(Error != NULL) goto error; } switch(E->Type) { case interface_type_eiface: break; case interface_type_steal: { ucl_object_t const *interface = ucl_object_lookup(root, "interface"); UCL_CHECK(interface, STRING); E->steal.Interface = strdup(ucl_object_tostring(interface)); break; } case interface_type_COUNT: default: __builtin_unreachable(); } return NULL; error: return Error; } char * Parse_interfaces_configuration(interfaces_configuration *E, ucl_object_t const *root, char const *Position) { char *Error; UCL_CHECK_ROOT(OBJECT); E->Count = root->len; E->_ = calloc(sizeof(interface_configuration), E->Count); { ucl_object_iter_t it = NULL; for(E->Count = 0; E->Count < root->len; ++E->Count) { ucl_object_t const *v = ucl_iterate_object(root, &it, true); if(v == NULL) break; char const *k = ucl_object_key(v); if(k == NULL) continue; interface_configuration *I = E->_ + E->Count; char *NewPosition; asprintf(&NewPosition, "%s['%s']", Position, k); Error = Parse_interface_configuration(I, v, NewPosition); free(NewPosition); if(Error != NULL) goto error; I->Name = strdup(k); } } return NULL; error: Free_interfaces_configuration(E); return Error; } char * Parse_mapping(mapping *E, ucl_object_t const *root, char const *Position) { char *Error; UCL_CHECK_ROOT(OBJECT); ucl_object_t const *source = ucl_object_lookup(root, "source"); UCL_CHECK(source, STRING); ucl_object_t const *target = ucl_object_lookup(root, "target"); UCL_CHECK(target, STRING); E->Source = strdup(ucl_object_tostring(source)); E->Target = strdup(ucl_object_tostring(target)); return NULL; error: return Error; } char * Parse_filesystem_configuration(filesystem_configuration *E, ucl_object_t const *root, char const *Position) { char *Error; UCL_CHECK_ROOT(OBJECT); ucl_object_t const *layers = ucl_object_lookup(root, "layers"); UCL_CHECK_OPTIONAL(layers, ARRAY); ucl_object_t const *temporary = ucl_object_lookup(root, "temporary"); UCL_CHECK_OPTIONAL(temporary, STRING); ucl_object_t const *volumes = ucl_object_lookup(root, "volumes"); UCL_CHECK_OPTIONAL(volumes, ARRAY); ucl_object_t const *devfs = ucl_object_lookup(root, "devfs"); UCL_CHECK_OPTIONAL(devfs, INT); if(layers != NULL) { E->Layer = calloc(sizeof(char *), layers->len); ucl_object_iter_t it = NULL; for(E->LayerCount = 0; E->LayerCount < layers->len; ++E->LayerCount) { ucl_object_t const *v = ucl_iterate_object(layers, &it, true); if(v == NULL) break; char const *k = ucl_object_key(v); if(k != NULL) continue; if(v->type != UCL_STRING) { asprintf(&Error, "%s.layers[%zu] is not " UCL_CHECK_HELPER(STRING), Position, E->LayerCount); goto error; } E->Layer[E->LayerCount] = strdup(ucl_object_tostring(v)); } } if(temporary != NULL) E->Temporary = strdup(ucl_object_tostring(temporary)); if(volumes != NULL) { E->Volume = calloc(sizeof(mapping), volumes->len); ucl_object_iter_t it = NULL; for(E->VolumeCount = 0; E->VolumeCount < volumes->len; ++E->VolumeCount) { ucl_object_t const *v = ucl_iterate_object(volumes, &it, true); if(v == NULL) break; char const *k = ucl_object_key(v); if(k != NULL) continue; mapping *I = E->Volume + E->VolumeCount; char *NewPosition; asprintf(&NewPosition, "%s.volumes[%zu]", Position, E->VolumeCount); Error = Parse_mapping(I, v, NewPosition); free(NewPosition); if(Error != NULL) goto error; } } E->DevfsRuleset = ucl_object_toint(devfs); return NULL; error: Free_filesystem_configuration(E); return Error; } char * Parse_configuration(configuration *E, ucl_object_t const *root, char const *Position) { char *Error; UCL_CHECK_ROOT(OBJECT); { char *NewPosition; asprintf(&NewPosition, "%s.interfaces", Position); Error = Parse_interfaces_configuration(&E->Interfaces, ucl_object_lookup(root, "interfaces"), NewPosition); free(NewPosition); if(Error != NULL) goto error; } { char *NewPosition; asprintf(&NewPosition, "%s.filesystem", Position); Error = Parse_filesystem_configuration(&E->Filesystem, ucl_object_lookup(root, "filesystem"), NewPosition); free(NewPosition); if(Error != NULL) goto error; } { char *NewPosition; asprintf(&NewPosition, "%s.init", Position); Error = Parse_string_array(&E->Init, ucl_object_lookup(root, "init"), NewPosition); free(NewPosition); if(Error != NULL) goto error; } { char *NewPosition; asprintf(&NewPosition, "%s.shutdown", Position); Error = Parse_string_array(&E->Shutdown, ucl_object_lookup(root, "shutdown"), NewPosition); free(NewPosition); if(Error != NULL) goto error; } return NULL; error: return Error; } char * Parse_interface(interface *E, ucl_object_t const *root, char const *Position) { char *Error; UCL_CHECK_ROOT(OBJECT); { char *NewPosition; asprintf(&NewPosition, "%s.type", Position); Error = Parse_interface_type(&E->Type, ucl_object_lookup(root, "type"), NewPosition); free(NewPosition); if(Error != NULL) goto error; } switch(E->Type) { case interface_type_eiface: { ucl_object_t const *id = ucl_object_lookup(root, "id"); UCL_CHECK(id, INT); s64 ID = ucl_object_toint(id); if(ID < 0 || ID > INT32_MAX) { asprintf(&Error, "%s id invalid (%ld)", Position, ID); goto error; } E->ID = (u32)ID; break; } case interface_type_steal: break; case interface_type_COUNT: default: __builtin_unreachable(); } return NULL; error: return Error; } char * Parse_interfaces(interfaces *E, ucl_object_t const *root, char const *Position) { char *Error; UCL_CHECK_ROOT(ARRAY); E->Count = root->len; E->_ = calloc(sizeof(interface_configuration), E->Count); { ucl_object_iter_t it = NULL; for(E->Count = 0; E->Count < root->len; ++E->Count) { ucl_object_t const *v = ucl_iterate_object(root, &it, true); if(v == NULL) break; char const *k = ucl_object_key(v); if(k != NULL) continue; interface *I = E->_ + E->Count; char *NewPosition; asprintf(&NewPosition, "%s['%zu']", Position, E->Count); Error = Parse_interface(I, v, NewPosition); free(NewPosition); if(Error != NULL) goto error; } } return NULL; error: Free_interfaces(E); return Error; } char * Parse_data(data *E, ucl_object_t const *root, char const *Position) { char *Error; UCL_CHECK_ROOT(OBJECT); ucl_object_t const *jid = ucl_object_lookup(root, "jid"); UCL_CHECK(jid, INT); int64_t JID = ucl_object_toint(jid); if(JID < 0 || JID > INT32_MAX) { asprintf(&Error, "%s jid invalid (%ld)", Position, JID); goto error; } E->JID = (jid_t)JID; { char *NewPosition; asprintf(&NewPosition, "%s.interfaces", Position); Error = Parse_interfaces(&E->Interfaces, ucl_object_lookup(root, "interfaces"), NewPosition); free(NewPosition); if(Error != NULL) goto error; } return NULL; error: return Error; } // SAVE void Save_interface(jprint_state *S, interface const *E) { JPrintObjectBegin(S); JPrintMember(S, "type"); JPrint_string(S, interface_type_Names[E->Type]); switch(E->Type) { case interface_type_eiface: { JPrintMember(S, "id"); JPrint_ssize_t(S, E->ID); break; } case interface_type_steal: break; case interface_type_COUNT: default: __builtin_unreachable(); } JPrintObjectEnd(S); } void Save_interfaces(jprint_state *S, interfaces const *E) { JPrintArrayBegin(S); for(size_t i = 0; i < E->Count; ++i) Save_interface(S, E->_ + i); JPrintArrayEnd(S); } void Save_data(jprint_state *S, data const *E) { JPrintObjectBegin(S); JPrintMember(S, "jid"); JPrint_ssize_t(S, E->JID); JPrintMember(S, "interfaces"); Save_interfaces(S, &E->Interfaces); JPrintObjectEnd(S); }