/** * mnt_init_debug: * @mask: debug mask (0xffff to enable full debugging) * * If the @mask is not specified, then this function reads * the LIBMOUNT_DEBUG environment variable to get the mask. * * Already initialized debugging stuff cannot be changed. Calling * this function twice has no effect. */ void mnt_init_debug(int mask) { if (libmount_debug_mask) return; __UL_INIT_DEBUG(libmount, MNT_DEBUG_, mask, LIBMOUNT_DEBUG); if (libmount_debug_mask != MNT_DEBUG_INIT && libmount_debug_mask != (MNT_DEBUG_HELP|MNT_DEBUG_INIT)) { const char *ver = NULL; const char **features = NULL, **p; mnt_get_library_version(&ver); mnt_get_library_features(&features); DBG(INIT, ul_debug("library debug mask: 0x%04x", libmount_debug_mask)); DBG(INIT, ul_debug("library version: %s", ver)); p = features; while (p && *p) DBG(INIT, ul_debug(" feature: %s", *p++)); } ON_DBG(HELP, ul_debug_print_masks("LIBMOUNT_DEBUG", UL_DEBUG_MASKNAMES(libmount))); }
/** * blkid_init_debug: * @mask: debug mask (0xffff to enable full debugging) * * If the @mask is not specified then this function reads * LIBBLKID_DEBUG environment variable to get the mask. * * Already initialized debugging stuff cannot be changed. It does not * have effect to call this function twice. */ void blkid_init_debug(int mask) { if (libblkid_debug_mask) return; __UL_INIT_DEBUG(libblkid, BLKID_DEBUG_, mask, LIBBLKID_DEBUG); if (libblkid_debug_mask != BLKID_DEBUG_INIT && libblkid_debug_mask != (BLKID_DEBUG_HELP|BLKID_DEBUG_INIT)) { const char *ver = NULL; const char *date = NULL; blkid_get_library_version(&ver, &date); DBG(INIT, ul_debug("library debug mask: 0x%04x", libblkid_debug_mask)); DBG(INIT, ul_debug("library version: %s [%s]", ver, date)); } ON_DBG(HELP, ul_debug_print_masks("LIBBLKID_DEBUG", UL_DEBUG_MASKNAMES(libblkid))); }
/** * scols_new_table: * * Returns: A newly allocated table. */ struct libscols_table *scols_new_table(void) { struct libscols_table *tb; tb = calloc(1, sizeof(struct libscols_table)); if (!tb) return NULL; tb->refcount = 1; tb->out = stdout; tb->termwidth = get_terminal_width(80); INIT_LIST_HEAD(&tb->tb_lines); INIT_LIST_HEAD(&tb->tb_columns); DBG(TAB, ul_debugobj(tb, "alloc")); ON_DBG(INIT, check_padding_debug(tb)); return tb; }
int mnt_context_setup_loopdev(struct libmnt_context *cxt) { const char *backing_file, *optstr, *loopdev = NULL; char *val = NULL; size_t len; struct loopdev_cxt lc; int rc = 0, lo_flags = 0; uint64_t offset = 0, sizelimit = 0; assert(cxt->fs); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); if (!cxt) return -EINVAL; backing_file = mnt_fs_get_srcpath(cxt->fs); if (!backing_file) return -EINVAL; DBG(CXT, ul_debugobj(cxt, "trying to setup loopdev for %s", backing_file)); if (cxt->mountflags & MS_RDONLY) { DBG(CXT, ul_debugobj(cxt, "enabling READ-ONLY flag")); lo_flags |= LO_FLAGS_READ_ONLY; } rc = loopcxt_init(&lc, 0); if (rc) return rc; ON_DBG(CXT, loopcxt_enable_debug(&lc, 1)); optstr = mnt_fs_get_user_options(cxt->fs); /* * loop= */ if (rc == 0 && (cxt->user_mountflags & MNT_MS_LOOP) && mnt_optstr_get_option(optstr, "loop", &val, &len) == 0 && val) { val = strndup(val, len); rc = val ? loopcxt_set_device(&lc, val) : -ENOMEM; free(val); if (rc == 0) loopdev = loopcxt_get_device(&lc); } /* * offset= */ if (rc == 0 && (cxt->user_mountflags & MNT_MS_OFFSET) && mnt_optstr_get_option(optstr, "offset", &val, &len) == 0) { rc = mnt_parse_offset(val, len, &offset); if (rc) { DBG(CXT, ul_debugobj(cxt, "failed to parse offset=")); rc = -MNT_ERR_MOUNTOPT; } } /* * sizelimit= */ if (rc == 0 && (cxt->user_mountflags & MNT_MS_SIZELIMIT) && mnt_optstr_get_option(optstr, "sizelimit", &val, &len) == 0) { rc = mnt_parse_offset(val, len, &sizelimit); if (rc) { DBG(CXT, ul_debugobj(cxt, "failed to parse sizelimit=")); rc = -MNT_ERR_MOUNTOPT; } } /* * encryption= */ if (rc == 0 && (cxt->user_mountflags & MNT_MS_ENCRYPTION) && mnt_optstr_get_option(optstr, "encryption", &val, &len) == 0) { DBG(CXT, ul_debugobj(cxt, "encryption no longer supported")); rc = -MNT_ERR_MOUNTOPT; } if (rc == 0 && is_mounted_same_loopfile(cxt, mnt_context_get_target(cxt), backing_file, offset)) rc = -EBUSY; if (rc) goto done; /* since 2.6.37 we don't have to store backing filename to mtab * because kernel provides the name in /sys. */ if (get_linux_version() >= KERNEL_VERSION(2, 6, 37) || !mnt_context_mtab_writable(cxt)) { DBG(CXT, ul_debugobj(cxt, "enabling AUTOCLEAR flag")); lo_flags |= LO_FLAGS_AUTOCLEAR; } do { /* found free device */ if (!loopdev) { rc = loopcxt_find_unused(&lc); if (rc) goto done; DBG(CXT, ul_debugobj(cxt, "trying to use %s", loopcxt_get_device(&lc))); } /* set device attributes * -- note that loopcxt_find_unused() resets "lc" */ rc = loopcxt_set_backing_file(&lc, backing_file); if (!rc && offset) rc = loopcxt_set_offset(&lc, offset); if (!rc && sizelimit) rc = loopcxt_set_sizelimit(&lc, sizelimit); if (!rc) loopcxt_set_flags(&lc, lo_flags); if (rc) { DBG(CXT, ul_debugobj(cxt, "failed to set loopdev attributes")); goto done; } /* setup the device */ rc = loopcxt_setup_device(&lc); if (!rc) break; /* success */ if (loopdev || rc != -EBUSY) { DBG(CXT, ul_debugobj(cxt, "failed to setup device")); rc = -MNT_ERR_LOOPDEV; goto done; } DBG(CXT, ul_debugobj(cxt, "loopdev stolen...trying again")); } while (1); if (!rc) rc = mnt_fs_set_source(cxt->fs, loopcxt_get_device(&lc)); if (!rc) { /* success */ cxt->flags |= MNT_FL_LOOPDEV_READY; if ((cxt->user_mountflags & MNT_MS_LOOP) && loopcxt_is_autoclear(&lc)) { /* * autoclear flag accepted by the kernel, don't store * the "loop=" option to mtab. */ cxt->user_mountflags &= ~MNT_MS_LOOP; mnt_optstr_remove_option(&cxt->fs->user_optstr, "loop"); } if (!(cxt->mountflags & MS_RDONLY) && loopcxt_is_readonly(&lc)) /* * mount planned read-write, but loopdev is read-only, * let's fix mount options... */ mnt_context_set_mflags(cxt, cxt->mountflags | MS_RDONLY); /* we have to keep the device open until mount(1), * otherwise it will be auto-cleared by kernel */ cxt->loopdev_fd = loopcxt_get_fd(&lc); loopcxt_set_fd(&lc, -1, 0); } done: loopcxt_deinit(&lc); return rc; }
/* * This function counts column width. * * For the SCOLS_FL_NOEXTREMES columns it is possible to call this function * two times. The first pass counts the width and average width. If the column * contains fields that are too large (a width greater than 2 * average) then * the column is marked as "extreme". In the second pass all extreme fields * are ignored and the column width is counted from non-extreme fields only. */ static int count_column_width(struct libscols_table *tb, struct libscols_column *cl, struct libscols_buffer *buf) { int rc = 0, no_header = 0; assert(tb); assert(cl); cl->width = 0; if (!cl->width_min) { if (cl->width_hint < 1 && scols_table_is_maxout(tb) && tb->is_term) { cl->width_min = (size_t) (cl->width_hint * tb->termwidth); if (cl->width_min && !is_last_column(cl)) cl->width_min--; } if (scols_cell_get_data(&cl->header)) { size_t len = mbs_safe_width(scols_cell_get_data(&cl->header)); cl->width_min = max(cl->width_min, len); } else no_header = 1; if (!cl->width_min) cl->width_min = 1; } if (scols_table_is_tree(tb)) { /* Count width for tree */ rc = scols_walk_tree(tb, cl, walk_count_cell_width, (void *) buf); if (rc) goto done; } else { /* Count width for list */ struct libscols_iter itr; struct libscols_line *ln; scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (scols_table_next_line(tb, &itr, &ln) == 0) { rc = count_cell_width(tb, ln, cl, buf); if (rc) goto done; } } if (scols_column_is_tree(cl) && has_groups(tb)) { /* We don't fill buffer with groups tree ascii art during width * calcualtion. The print function only enlarge grpset[] and we * calculate final width from grpset_size. */ size_t gprwidth = tb->grpset_size + 1; cl->width_treeart += gprwidth; cl->width_max += gprwidth; cl->width += gprwidth; if (cl->extreme_count) cl->extreme_sum += gprwidth; } if (cl->extreme_count && cl->width_avg == 0) { cl->width_avg = cl->extreme_sum / cl->extreme_count; if (cl->width_avg && cl->width_max > cl->width_avg * 2) cl->is_extreme = 1; } /* enlarge to minimal width */ if (cl->width < cl->width_min && !scols_column_is_strict_width(cl)) cl->width = cl->width_min; /* use absolute size for large columns */ else if (cl->width_hint >= 1 && cl->width < (size_t) cl->width_hint && cl->width_min < (size_t) cl->width_hint) cl->width = (size_t) cl->width_hint; /* Column without header and data, set minimal size to zero (default is 1) */ if (cl->width_max == 0 && no_header && cl->width_min == 1 && cl->width <= 1) cl->width = cl->width_min = 0; done: ON_DBG(COL, dbg_column(tb, cl)); return rc; }
/* * This is core of the scols_* voodoo... */ int __scols_calculate(struct libscols_table *tb, struct libscols_buffer *buf) { struct libscols_column *cl; struct libscols_iter itr; size_t width = 0, width_min = 0; /* output width */ int stage, rc = 0; int extremes = 0, group_ncolumns = 0; size_t colsepsz; DBG(TAB, ul_debugobj(tb, "-----calculate-(termwidth=%zu)-----", tb->termwidth)); tb->is_dummy_print = 1; colsepsz = mbs_safe_width(colsep(tb)); if (has_groups(tb)) group_ncolumns = 1; /* set basic columns width */ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (scols_table_next_column(tb, &itr, &cl) == 0) { int is_last; if (scols_column_is_hidden(cl)) continue; /* we print groups chart only for the for the first tree column */ if (scols_column_is_tree(cl) && group_ncolumns == 1) { cl->is_groups = 1; group_ncolumns++; } rc = count_column_width(tb, cl, buf); if (rc) goto done; is_last = is_last_column(cl); width += cl->width + (is_last ? 0 : colsepsz); /* separator for non-last column */ width_min += cl->width_min + (is_last ? 0 : colsepsz); if (cl->is_extreme) extremes++; } if (!tb->is_term) { DBG(TAB, ul_debugobj(tb, " non-terminal output")); goto done; } /* be paranoid */ if (width_min > tb->termwidth && scols_table_is_maxout(tb)) { DBG(TAB, ul_debugobj(tb, " min width larger than terminal! [width=%zu, term=%zu]", width_min, tb->termwidth)); scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (width_min > tb->termwidth && scols_table_next_column(tb, &itr, &cl) == 0) { if (scols_column_is_hidden(cl)) continue; width_min--; cl->width_min--; } DBG(TAB, ul_debugobj(tb, " min width reduced to %zu", width_min)); } /* reduce columns with extreme fields */ if (width > tb->termwidth && extremes) { DBG(TAB, ul_debugobj(tb, " reduce width (extreme columns)")); scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (scols_table_next_column(tb, &itr, &cl) == 0) { size_t org_width; if (!cl->is_extreme || scols_column_is_hidden(cl)) continue; org_width = cl->width; rc = count_column_width(tb, cl, buf); if (rc) goto done; if (org_width > cl->width) width -= org_width - cl->width; else extremes--; /* hmm... nothing reduced */ } } if (width < tb->termwidth) { if (extremes) { DBG(TAB, ul_debugobj(tb, " enlarge width (extreme columns)")); /* enlarge the first extreme column */ scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (scols_table_next_column(tb, &itr, &cl) == 0) { size_t add; if (!cl->is_extreme || scols_column_is_hidden(cl)) continue; /* this column is too large, ignore? if (cl->width_max - cl->width > (tb->termwidth - width)) continue; */ add = tb->termwidth - width; if (add && cl->width + add > cl->width_max) add = cl->width_max - cl->width; cl->width += add; width += add; if (width == tb->termwidth) break; } } if (width < tb->termwidth && scols_table_is_maxout(tb)) { DBG(TAB, ul_debugobj(tb, " enlarge width (max-out)")); /* try enlarging all columns */ while (width < tb->termwidth) { scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (scols_table_next_column(tb, &itr, &cl) == 0) { if (scols_column_is_hidden(cl)) continue; cl->width++; width++; if (width == tb->termwidth) break; } } } else if (width < tb->termwidth) { /* enlarge the last column */ struct libscols_column *col = list_entry( tb->tb_columns.prev, struct libscols_column, cl_columns); DBG(TAB, ul_debugobj(tb, " enlarge width (last column)")); if (!scols_column_is_right(col) && tb->termwidth - width > 0) { col->width += tb->termwidth - width; width = tb->termwidth; } } } /* bad, we have to reduce output width, this is done in three stages: * * 1) trunc relative with trunc flag if the column width is greater than * expected column width (it means "width_hint * terminal_width"). * * 2) trunc all with trunc flag * * 3) trunc relative without trunc flag * * Note that SCOLS_FL_WRAP (if no custom wrap function is specified) is * interpreted as SCOLS_FL_TRUNC. */ for (stage = 1; width > tb->termwidth && stage <= 3; ) { size_t org_width = width; DBG(TAB, ul_debugobj(tb, " reduce width - #%d stage (current=%zu, wanted=%zu)", stage, width, tb->termwidth)); scols_reset_iter(&itr, SCOLS_ITER_FORWARD); while (scols_table_next_column(tb, &itr, &cl) == 0) { int trunc_flag = 0; DBG(TAB, ul_debugobj(cl, " checking %s (width=%zu, treeart=%zu)", cl->header.data, cl->width, cl->width_treeart)); if (scols_column_is_hidden(cl)) continue; if (width <= tb->termwidth) break; /* never truncate if already minimal width */ if (cl->width == cl->width_min) continue; /* never truncate the tree */ if (scols_column_is_tree(cl) && width <= cl->width_treeart) continue; /* nothing to truncate */ if (cl->width == 0 || width == 0) continue; trunc_flag = scols_column_is_trunc(cl) || (scols_column_is_wrap(cl) && !scols_column_is_customwrap(cl)); switch (stage) { /* #1 stage - trunc relative with TRUNC flag */ case 1: if (!trunc_flag) /* ignore: missing flag */ break; if (cl->width_hint <= 0 || cl->width_hint >= 1) /* ignore: no relative */ break; if (cl->width < (size_t) (cl->width_hint * tb->termwidth)) /* ignore: smaller than expected width */ break; DBG(TAB, ul_debugobj(tb, " reducing (relative with flag)")); cl->width--; width--; break; /* #2 stage - trunc all with TRUNC flag */ case 2: if (!trunc_flag) /* ignore: missing flag */ break; DBG(TAB, ul_debugobj(tb, " reducing (all with flag)")); cl->width--; width--; break; /* #3 stage - trunc relative without flag */ case 3: if (cl->width_hint <= 0 || cl->width_hint >= 1) /* ignore: no relative */ break; DBG(TAB, ul_debugobj(tb, " reducing (relative without flag)")); cl->width--; width--; break; } /* hide zero width columns */ if (cl->width == 0) cl->flags |= SCOLS_FL_HIDDEN; } /* the current stage is without effect, go to the next */ if (org_width == width) stage++; } /* ignore last column(s) or force last column to be truncated if * nowrap mode enabled */ if (tb->no_wrap && width > tb->termwidth) { scols_reset_iter(&itr, SCOLS_ITER_BACKWARD); while (scols_table_next_column(tb, &itr, &cl) == 0) { if (scols_column_is_hidden(cl)) continue; if (width <= tb->termwidth) break; if (width - cl->width < tb->termwidth) { size_t r = width - tb->termwidth; cl->flags |= SCOLS_FL_TRUNC; cl->width -= r; width -= r; } else { cl->flags |= SCOLS_FL_HIDDEN; width -= cl->width + colsepsz; } } } done: tb->is_dummy_print = 0; DBG(TAB, ul_debugobj(tb, "-----final width: %zu (rc=%d)-----", width, rc)); ON_DBG(TAB, dbg_columns(tb)); return rc; }