GoatError goat_message_get_tag_value( const GoatMessage *message, const char *key, char *value, size_t *size ) { if (NULL == message) return EINVAL; if (NULL == key) return EINVAL; if (NULL == value) return EINVAL; if (NULL == size) return EINVAL; const MessageTags *tags = message->m_tags; if (NULL == tags || 0 == strlen(tags->m_bytes)) return GOAT_E_NOTAG; const char *p, *v, *end; p = _find_tag(tags->m_bytes, key); if (NULL == p) return GOAT_E_NOTAG; v = _find_value(p); if (NULL == v) return GOAT_E_NOTAGVAL; end = _next_tag(v); if ('\0' != *end) end--; // account for separator char unescaped[GOAT_MESSAGE_MAX_TAGS]; size_t unescaped_len = sizeof(unescaped); _unescape_value(v, unescaped, &unescaped_len); if (*size <= unescaped_len) return EOVERFLOW; memset(value, 0, *size); strncpy(value, unescaped, unescaped_len); *size = unescaped_len; return 0; }
/* * Find the last tag in the tag list. */ static inline NkTagHeader* _find_last_tag (NkTagHeader* t) { while (t->size != 0) { t = _next_tag(t); } return t; }
/* * Remove a tag from the tag list */ void remove_tag (NkTagHeader* t) { NkTagHeader* next; nku32_f size; next = _next_tag(t); size = tags_len(next); memcpy(t, next, size); }
/* * Find a tag in the tag list */ NkTagHeader* find_tag (NkTagHeader* t, nku32_f tag) { while (t->size != 0) { if (t->tag == tag) { return t; } t = _next_tag(t); } return 0; }
/* * Add a command line tag to the tag list. * Check if the resulting tag list exceeds its size limit. * Return added tag. */ NkTagHeader* add_cmd_line_tag (NkTagHeader* t, char* cmd_line, nku32_f limit) { NkTagHeader* last; NkTagHeader* cmdl; NkTagHeader ltag; nku32_f size; last = _find_last_tag(t); ltag = *last; /* * Calculate new tag size (at first in bytes, then in words) */ size = strlen(cmd_line) + 1 + sizeof(NkTagHeader); size = (size + sizeof(nku32_f) - 1)/sizeof(nku32_f); /* * Check for overflow */ if (_tags_len(t, last) + size * sizeof(nku32_f) > limit) { return 0; } /* * Add a new command line tag */ last->tag = ATAG_CMDLINE; last->size = size; strcpy((char*)(last+1), cmd_line); cmdl = last; /* * Add a termination tag */ last = _next_tag(last); *last = ltag; return cmdl; }
const char *_find_tag(const char *str, const char *key) { assert(str != NULL); assert(key != NULL); const char *p = str; const size_t key_len = strlen(key); while (*p) { if (0 == strncmp(p, key, key_len)) { switch (*(p + key_len)) { case '\0': case '=': case ';': return p; } } p = _next_tag(p); } return NULL; }
/* * Add an init ram disk tag to the tag list. * Check if the resulting tag list exceeds its size limit. * Return added tag. */ NkTagHeader* add_ram_disk_tag (NkTagHeader* t, NkPhAddr start, NkPhSize size, nku32_f limit) { NkTagHeader* last; NkTagHeader* rdsk; NkTagHeader ltag; nku32_f* tag; last = _find_last_tag(t); ltag = *last; /* * Check for overflow */ if (_tags_len(t, last) + sizeof(NkTagHeader) + 2*sizeof(nku32_f) > limit) { return 0; } /* * Add a new initrd tag */ last->tag = ATAG_INITRD2; last->size = sizeof(NkTagHeader)/sizeof(nku32_f) + 2; tag = (nku32_f*)(last+1); tag[0] = start; tag[1] = size; rdsk = last; /* * Add a termination tag */ last = _next_tag(last); *last = ltag; return rdsk; }
GoatError goat_message_unset_tag(GoatMessage *message, const char *key) { if (NULL == message) return EINVAL; if (NULL == key) return EINVAL; MessageTags *tags = message->m_tags; if (NULL == tags || 0 == strlen(tags->m_bytes)) return 0; char *p1, *p2, *end; end = &tags->m_bytes[tags->m_len]; p1 = (char *) _find_tag(tags->m_bytes, key); if (p1[0] == '\0') return 0; // => p1 is the start of the tag to be replaced p2 = (char *) _next_tag(p1); // => p2 is the start of the rest of the string (if any) if (p2[0] != '\0') { memmove(p1, p2, end - p2); tags->m_len -= (p2 - p1); memset(&tags->m_bytes[tags->m_len], 0, sizeof(tags->m_bytes) - tags->m_len); } else { tags->m_len = p1 - tags->m_bytes; memset(p1, 0, sizeof(tags->m_bytes) - tags->m_len); } // may be a trailing semicolon if tag removed from end, chomp it if (tags->m_bytes[tags->m_len - 1] == ';') { tags->m_bytes[-- tags->m_len] = '\0'; } return 0; }
/* * Dump a tag list */ void dump_taglist(NkTagHeader* t) { if (t->tag != ATAG_CORE) { printk("No tag list found at 0x%08x\n", (unsigned int)t); return; } printk(" === dump tag list at 0x%08x ===\n", (unsigned int)t); for (;;) { printk(" tag = 0x%08x size = 0x%08x\n", t->tag, t->size); if (t->size == 0) break; switch (t->tag) { case ATAG_CORE: { nku32_f* tag = (nku32_f*)(t+1); printk(" core tag: 0x%08x 0x%08x 0x%08x\n", tag[0], tag[1], tag[2]); break; } case ATAG_CMDLINE: { printk(" cmd line tag: <%s>\n", (char*)(t+1)); break; } case ATAG_MEM: { nku32_f* tag = (nku32_f*)(t+1); printk(" mem chunk tag: start = 0x%08x size = 0x%08x\n", tag[1], tag[0]); break; } case ATAG_RAMDISK: { nku32_f* tag = (nku32_f*)(t+1); printk(" ram disk tag: start = 0x%08x size = 0x%08x" " flags =%d\n", tag[2], tag[1], tag[0]); break; } case ATAG_INITRD: { nku32_f* tag = (nku32_f*)(t+1); printk(" initrd tag: start = 0x%08x size = 0x%08x\n", tag[0], tag[1]); break; } case ATAG_INITRD2: { nku32_f* tag = (nku32_f*)(t+1); printk(" initrd2 tag: start = 0x%08x size = 0x%08x\n", tag[0], tag[1]); break; } case ATAG_SERIAL: { nku32_f* tag = (nku32_f*)(t+1); printk(" serial number: 0x%08x%08x\n", tag[1], tag[0]); break; } case ATAG_REVISION: { nku32_f* tag = (nku32_f*)(t+1); printk(" board revision: 0x%08x\n", tag[0]); break; } case ATAG_ARCH_ID: { nku32_f* tag = (nku32_f*)(t+1); printk(" arch id tag: %d\n", tag[0]); break; } case ATAG_MAP_DESC: { nku32_f* tag = (nku32_f*)(t+1); printk(" map desc tag: pstart = 0x%08x plimit = 0x%08x\n", tag[0], tag[1]); printk(" vstart = 0x%08x pte_attr = 0x%03x\n", tag[2], tag[3]); printk(" mem_type = %d mem_owner = %d\n", tag[4], tag[5]); break; } case ATAG_TAG_REF: { nku32_f* tag = (nku32_f*)(t+1); printk(" tag ref: addr = 0x%08x\n", tag[0]); break; } } t = _next_tag(t); } printk("\n"); }
/* * Next tag in the tag list */ NkTagHeader* next_tag(NkTagHeader* t) { return _next_tag(t); }