+ /* Count capability list. */
+ for (; off; off = next) {
+ cap = tdb_access_read(tdb, off, sizeof(*cap), true);
+ if (TDB_PTR_IS_ERR(cap)) {
+ break;
+ }
+ count++;
+ next = cap->next;
+ tdb_access_release(tdb, cap);
+ }
+ return count;
+}
+
+static void add_capabilities(struct tdb_context *tdb, size_t num, char *summary)
+{
+ tdb_off_t off, next;
+ const struct tdb_capability *cap;
+ size_t count = 0;
+
+ /* Append to summary. */
+ summary += strlen(summary);
+
+ off = tdb_read_off(tdb, offsetof(struct tdb_header, capabilities));
+ if (TDB_OFF_IS_ERR(off))
+ return;
+
+ /* Walk capability list. */
+ for (; off; off = next) {
+ cap = tdb_access_read(tdb, off, sizeof(*cap), true);
+ if (TDB_PTR_IS_ERR(cap)) {
+ break;
+ }
+ count++;
+ sprintf(summary, CAPABILITY_FORMAT,
+ cap->type & TDB_CAP_TYPE_MASK,
+ /* Noopen? How did we get here? */
+ (cap->type & TDB_CAP_NOOPEN) ? " (unopenable)"
+ : ((cap->type & TDB_CAP_NOWRITE)
+ && (cap->type & TDB_CAP_NOCHECK)) ? " (uncheckable,read-only)"
+ : (cap->type & TDB_CAP_NOWRITE) ? " (read-only)"
+ : (cap->type & TDB_CAP_NOCHECK) ? " (uncheckable)"
+ : "");
+ summary += strlen(summary);
+ next = cap->next;
+ tdb_access_release(tdb, cap);
+ }
+}