static void free_dirlist(struct wh_dirlist **ls0, int type) { struct wh_dirlist *prev = NULL, *next, *ls = *ls0; *ls0 = NULL; DBG(LIST, ul_debugobj(*ls0, "free dirlist")); while (ls) { if (ls->type & type) { next = ls->next; DBG(LIST, ul_debugobj(*ls0, " free: %s", ls->path)); free(ls->path); free(ls); ls = next; if (prev) prev->next = ls; } else { if (!prev) *ls0 = ls; /* first unremoved */ prev = ls; ls = ls->next; } } return; }
/* * Zeros in-memory first sector buffer */ int fdisk_init_firstsector_buffer(struct fdisk_context *cxt) { if (!cxt) return -EINVAL; if (!cxt->firstsector || cxt->firstsector_bufsz != cxt->sector_size) { /* Let's allocate a new buffer if no allocated yet, or the * current buffer has incorrect size */ if (!cxt->parent || cxt->parent->firstsector != cxt->firstsector) free(cxt->firstsector); DBG(CXT, ul_debugobj(cxt, "initialize in-memory first sector " "buffer [sector_size=%lu]", cxt->sector_size)); cxt->firstsector = calloc(1, cxt->sector_size); if (!cxt->firstsector) return -ENOMEM; cxt->firstsector_bufsz = cxt->sector_size; return 0; } DBG(CXT, ul_debugobj(cxt, "zeroize in-memory first sector buffer")); memset(cxt->firstsector, 0, cxt->firstsector_bufsz); return 0; }
/** * fdisk_add_partition: * @cxt: fdisk context * @pa: template for the partition (or NULL) * @partno: NULL or returns new partition number * * If @pa is not specified or any @pa item is missiong the libfdisk will ask by * fdisk_ask_ API. * * Adds a new partition to disklabel. * * Returns: 0 on success, <0 on error. */ int fdisk_add_partition(struct fdisk_context *cxt, struct fdisk_partition *pa, size_t *partno) { int rc; assert(cxt); assert(cxt->label); if (!cxt || !cxt->label) return -EINVAL; if (!cxt->label->op->add_part) return -ENOSYS; if (fdisk_missing_geometry(cxt)) return -EINVAL; if (pa) DBG(CXT, ul_debugobj(cxt, "adding new partition %p (start=%ju, end=%ju, size=%ju, " "defaults(start=%s, end=%s, partno=%s)", pa, (uintmax_t) fdisk_partition_get_start(pa), (uintmax_t) fdisk_partition_get_end(pa), (uintmax_t) fdisk_partition_get_size(pa), pa->start_follow_default ? "yes" : "no", pa->end_follow_default ? "yes" : "no", pa->partno_follow_default ? "yes" : "no")); else DBG(CXT, ul_debugobj(cxt, "adding partition")); rc = cxt->label->op->add_part(cxt, pa, partno); DBG(CXT, ul_debugobj(cxt, "add partition done (rc=%d)", rc)); return rc; }
/** * fdisk_partition_next_partno: * @pa: partition * @cxt: context * @n: returns partition number * * If partno-follow-default (see fdisk_partition_partno_follow_default()) * enabled then returns next expected partno, otherwise use Ask API to ask user * for the next partno. * * Returns: 0 on success, <0 on error */ int fdisk_partition_next_partno( struct fdisk_partition *pa, struct fdisk_context *cxt, size_t *n) { assert(cxt); assert(n); if (pa && pa->partno_follow_default) { size_t i; DBG(PART, ul_debugobj(pa, "next partno (follow default)")); for (i = 0; i < cxt->label->nparts_max; i++) { if (!fdisk_is_partition_used(cxt, i)) { *n = i; return 0; } } return -ERANGE; } else if (pa && fdisk_partition_has_partno(pa)) { DBG(PART, ul_debugobj(pa, "next partno (specified=%zu)", pa->partno)); if (pa->partno >= cxt->label->nparts_max) return -ERANGE; *n = pa->partno; } else return fdisk_ask_partnum(cxt, n, 1); return 0; }
int fdisk_read_firstsector(struct fdisk_context *cxt) { ssize_t r; int rc; assert(cxt); assert(cxt->sector_size); rc = fdisk_init_firstsector_buffer(cxt); if (rc) return rc; assert(cxt->sector_size == cxt->firstsector_bufsz); DBG(CXT, ul_debugobj(cxt, "reading first sector " "buffer [sector_size=%lu]", cxt->sector_size)); r = lseek(cxt->dev_fd, 0, SEEK_SET); if (r == -1) { DBG(CXT, ul_debugobj(cxt, "failed to seek to first sector %m")); return -errno; } r = read(cxt->dev_fd, cxt->firstsector, cxt->sector_size); if (r != cxt->sector_size) { if (!errno) errno = EINVAL; /* probably too small file/device */ DBG(CXT, ul_debugobj(cxt, "failed to read first sector %m")); return -errno; } return 0; }
/** * mnt_context_next_umount: * @cxt: context * @itr: iterator * @fs: returns the current filesystem * @mntrc: returns the return code from mnt_context_umount() * @ignored: returns 1 for not matching * * This function tries to umount the next filesystem from mtab (as returned by * mnt_context_get_mtab()). * * You can filter out filesystems by: * mnt_context_set_options_pattern() to simulate umount -a -O pattern * mnt_context_set_fstype_pattern() to simulate umount -a -t pattern * * If the filesystem is not mounted or does not match the defined criteria, * then the function mnt_context_next_umount() returns zero, but the @ignored is * non-zero. Note that the root filesystem is always ignored. * * If umount(2) syscall or umount.type helper failed, then the * mnt_context_next_umount() function returns zero, but the @mntrc is non-zero. * Use also mnt_context_get_status() to check if the filesystem was * successfully umounted. * * Returns: 0 on success, * <0 in case of error (!= umount(2) errors) * 1 at the end of the list. */ int mnt_context_next_umount(struct libmnt_context *cxt, struct libmnt_iter *itr, struct libmnt_fs **fs, int *mntrc, int *ignored) { struct libmnt_table *mtab; const char *tgt; int rc; if (ignored) *ignored = 0; if (mntrc) *mntrc = 0; if (!cxt || !fs || !itr) return -EINVAL; rc = mnt_context_get_mtab(cxt, &mtab); cxt->mtab = NULL; /* do not reset mtab */ mnt_reset_context(cxt); cxt->mtab = mtab; if (rc) return rc; do { rc = mnt_table_next_fs(mtab, itr, fs); if (rc != 0) return rc; /* no more filesystems (or error) */ tgt = mnt_fs_get_target(*fs); } while (!tgt); DBG(CXT, ul_debugobj(cxt, "next-umount: trying %s [fstype: %s, t-pattern: %s, options: %s, O-pattern: %s]", tgt, mnt_fs_get_fstype(*fs), cxt->fstype_pattern, mnt_fs_get_options(*fs), cxt->optstr_pattern)); /* ignore filesystems which don't match options patterns */ if ((cxt->fstype_pattern && !mnt_fs_match_fstype(*fs, cxt->fstype_pattern)) || /* ignore filesystems which don't match type patterns */ (cxt->optstr_pattern && !mnt_fs_match_options(*fs, cxt->optstr_pattern))) { if (ignored) *ignored = 1; DBG(CXT, ul_debugobj(cxt, "next-umount: not-match")); return 0; } rc = mnt_context_set_fs(cxt, *fs); if (rc) return rc; rc = mnt_context_umount(cxt); if (mntrc) *mntrc = rc; return 0; }
/** * mnt_table_parse_stream: * @tb: tab pointer * @f: file stream * @filename: filename used for debug and error messages * * Returns: 0 on success, negative number in case of error. */ int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filename) { int nlines = 0; int rc = -1; int flags = 0; pid_t tid = -1; assert(tb); assert(f); assert(filename); DBG(TAB, ul_debugobj(tb, "%s: start parsing [entries=%d, filter=%s]", filename, mnt_table_get_nents(tb), tb->fltrcb ? "yes" : "not")); /* necessary for /proc/mounts only, the /proc/self/mountinfo * parser sets the flag properly */ if (filename && strcmp(filename, _PATH_PROC_MOUNTS) == 0) flags = MNT_FS_KERNEL; while (!feof(f)) { struct libmnt_fs *fs = mnt_new_fs(); if (!fs) goto err; rc = mnt_table_parse_next(tb, f, fs, filename, &nlines); if (!rc && tb->fltrcb && tb->fltrcb(fs, tb->fltrcb_data)) rc = 1; /* filtered out by callback... */ if (!rc) { rc = mnt_table_add_fs(tb, fs); fs->flags |= flags; if (rc == 0 && tb->fmt == MNT_FMT_MOUNTINFO) rc = kernel_fs_postparse(tb, fs, &tid, filename); } mnt_unref_fs(fs); if (rc) { if (rc == 1) continue; /* recoverable error */ if (feof(f)) break; goto err; /* fatal error */ } } DBG(TAB, ul_debugobj(tb, "%s: stop parsing (%d entries)", filename, mnt_table_get_nents(tb))); return 0; err: DBG(TAB, ul_debugobj(tb, "%s: parse error (rc=%d)", filename, rc)); return rc; }
/** * fdisk_new_nested_context: * @parent: parental context * @name: optional label name (e.g. "bsd") * * This is supported for MBR+BSD and GPT+pMBR only. * * Returns: new context for nested partiton table. */ struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent, const char *name) { struct fdisk_context *cxt; struct fdisk_label *lb = NULL; assert(parent); cxt = calloc(1, sizeof(*cxt)); if (!cxt) return NULL; DBG(CXT, ul_debugobj(parent, "alloc nested [%p]", cxt)); cxt->dev_fd = parent->dev_fd; cxt->refcount = 1; cxt->parent = parent; cxt->io_size = parent->io_size; cxt->optimal_io_size = parent->optimal_io_size; cxt->min_io_size = parent->min_io_size; cxt->phy_sector_size = parent->phy_sector_size; cxt->sector_size = parent->sector_size; cxt->alignment_offset = parent->alignment_offset; cxt->grain = parent->grain; cxt->first_lba = parent->first_lba; cxt->total_sectors = parent->total_sectors; cxt->firstsector = parent->firstsector; cxt->ask_cb = parent->ask_cb; cxt->ask_data = parent->ask_data; cxt->geom = parent->geom; if (name) { if (strcmp(name, "bsd") == 0) lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt); else if (strcmp(name, "dos") == 0) lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt); } if (lb) { DBG(CXT, ul_debugobj(cxt, "probing for nested %s", lb->name)); cxt->label = lb; if (lb->op->probe(cxt) == 1) __fdisk_switch_label(cxt, lb); else { DBG(CXT, ul_debugobj(cxt, "not found %s label", lb->name)); if (lb->op->deinit) lb->op->deinit(lb); cxt->label = NULL; } } return cxt; }
/** * fdisk_label_parse_parttype: * @lb: label * @str: string to parse from * * Parses partition type from @str according to the label. The function returns * a pointer to static table of the partition types, or newly allocated * partition type for unknown types (see fdisk_parttype_is_unknown(). It's * safe to call fdisk_unref_parttype() for all results. * * Returns: pointer to type or NULL on error. */ struct fdisk_parttype *fdisk_label_parse_parttype( const struct fdisk_label *lb, const char *str) { struct fdisk_parttype *types, *ret = NULL; char *end = NULL; assert(lb); if (!lb->nparttypes) return NULL; DBG(LABEL, ul_debugobj(lb, "parsing '%s' (%s) partition type", str, lb->name)); types = lb->parttypes; if (types[0].typestr == NULL && isxdigit(*str)) { unsigned int code = 0; errno = 0; code = strtol(str, &end, 16); if (errno || *end != '\0') { DBG(LABEL, ul_debugobj(lb, "parsing failed: %m")); return NULL; } ret = fdisk_label_get_parttype_from_code(lb, code); if (ret) goto done; ret = fdisk_new_unknown_parttype(code, NULL); } else { int i; /* maybe specified by type string (e.g. UUID) */ ret = fdisk_label_get_parttype_from_string(lb, str); if (ret) goto done; /* maybe specified by order number */ errno = 0; i = strtol(str, &end, 0); if (errno == 0 && *end == '\0' && i > 0 && i - 1 < (int) lb->nparttypes) { ret = &types[i - 1]; goto done; } ret = fdisk_new_unknown_parttype(0, str); } done: DBG(PARTTYPE, ul_debugobj(ret, "returns parsed '%s' [%s] partition type", ret->name, ret->typestr ? : "")); return ret; }
is_mounted_same_loopfile(struct libmnt_context *cxt, const char *target, const char *backing_file, uint64_t offset) { struct libmnt_table *tb; struct libmnt_iter itr; struct libmnt_fs *fs; struct libmnt_cache *cache; const char *bf; int rc = 0; assert(cxt); assert(cxt->fs); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); if (mnt_context_get_mtab(cxt, &tb)) return 0; DBG(LOOP, ul_debugobj(cxt, "checking if %s mounted on %s", backing_file, target)); cache = mnt_context_get_cache(cxt); mnt_reset_iter(&itr, MNT_ITER_BACKWARD); bf = cache ? mnt_resolve_path(backing_file, cache) : backing_file; /* Search for a mountpoint node in mtab, proceed if any of these have the * loop option set or the device is a loop device */ while (rc == 0 && mnt_table_next_fs(tb, &itr, &fs) == 0) { const char *src = mnt_fs_get_source(fs); const char *opts = mnt_fs_get_user_options(fs); char *val; size_t len; if (!src || !mnt_fs_match_target(fs, target, cache)) continue; rc = 0; if (strncmp(src, "/dev/loop", 9) == 0) { rc = loopdev_is_used((char *) src, bf, offset, 0, LOOPDEV_FL_OFFSET); } else if (opts && (cxt->user_mountflags & MNT_MS_LOOP) && mnt_optstr_get_option(opts, "loop", &val, &len) == 0 && val) { val = strndup(val, len); rc = loopdev_is_used((char *) val, bf, offset, 0, LOOPDEV_FL_OFFSET); free(val); } } if (rc) DBG(LOOP, ul_debugobj(cxt, "%s already mounted", backing_file)); return rc; }
int mnt_context_is_loopdev(struct libmnt_context *cxt) { const char *type, *src; assert(cxt); /* The mount flags have to be merged, otherwise we have to use * expensive mnt_context_get_user_mflags() instead of cxt->user_mountflags. */ assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); if (!cxt->fs) return 0; src = mnt_fs_get_srcpath(cxt->fs); if (!src) return 0; /* backing file not set */ if (cxt->user_mountflags & (MNT_MS_LOOP | MNT_MS_OFFSET | MNT_MS_SIZELIMIT)) { DBG(LOOP, ul_debugobj(cxt, "loopdev specific options detected")); return 1; } if ((cxt->mountflags & (MS_BIND | MS_MOVE)) || mnt_context_propagation_only(cxt)) return 0; /* Automatically create a loop device from a regular file if a * filesystem is not specified or the filesystem is known for libblkid * (these filesystems work with block devices only). The file size * should be at least 1KiB, otherwise we will create an empty loopdev with * no mountable filesystem... * * Note that there is no restriction (on kernel side) that would prevent a regular * file as a mount(2) source argument. A filesystem that is able to mount * regular files could be implemented. */ type = mnt_fs_get_fstype(cxt->fs); if (mnt_fs_is_regular(cxt->fs) && (!type || strcmp(type, "auto") == 0 || blkid_known_fstype(type))) { struct stat st; if (stat(src, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 1024) { DBG(LOOP, ul_debugobj(cxt, "automatically enabling loop= option")); cxt->user_mountflags |= MNT_MS_LOOP; mnt_optstr_append_option(&cxt->fs->user_optstr, "loop", NULL); return 1; } } return 0; }
int __fdisk_switch_label(struct fdisk_context *cxt, struct fdisk_label *lb) { if (!lb || !cxt) return -EINVAL; if (lb->disabled) { DBG(CXT, ul_debugobj(cxt, "*** attempt to switch to disabled label %s -- ignore!", lb->name)); return -EINVAL; } cxt->label = lb; DBG(CXT, ul_debugobj(cxt, "--> switching context to %s!", lb->name)); return 0; }
/** * fdisk_new_nested_context: * @parent: parental context * @name: optional label name (e.g. "bsd") * * Create a new nested fdisk context for nested disk labels (e.g. BSD or PMBR). * The function also probes for the nested label on the device if device is * already assigned to parent. * * The new context is initialized according to @parent and both context shares * some settings and file descriptor to the device. The child propagate some * changes (like fdisk_assign_device()) to parent, but it does not work * vice-versa. The behavior is undefined if you assign another device to * parent. * * Returns: new context for nested partition table. */ struct fdisk_context *fdisk_new_nested_context(struct fdisk_context *parent, const char *name) { struct fdisk_context *cxt; struct fdisk_label *lb = NULL; assert(parent); cxt = calloc(1, sizeof(*cxt)); if (!cxt) return NULL; DBG(CXT, ul_debugobj(parent, "alloc nested [%p] [name=%s]", cxt, name)); cxt->refcount = 1; fdisk_ref_context(parent); cxt->parent = parent; if (init_nested_from_parent(cxt, 1) != 0) { cxt->parent = NULL; fdisk_unref_context(cxt); return NULL; } if (name) { if (strcasecmp(name, "bsd") == 0) lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt); else if (strcasecmp(name, "dos") == 0 || strcasecmp(name, "mbr") == 0) lb = cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt); } if (lb && parent->dev_fd >= 0) { DBG(CXT, ul_debugobj(cxt, "probing for nested %s", lb->name)); cxt->label = lb; if (lb->op->probe(cxt) == 1) __fdisk_switch_label(cxt, lb); else { DBG(CXT, ul_debugobj(cxt, "not found %s label", lb->name)); if (lb->op->deinit) lb->op->deinit(lb); cxt->label = NULL; } } return cxt; }
/* * This function uses @uf to find a corresponding record in @tb, then the record * from @tb is updated (user specific mount options are added). * * Note that @uf must contain only user specific mount options instead of * VFS options (note that FS options are ignored). * * Returns modified filesystem (from @tb) or NULL. */ static struct libmnt_fs *mnt_table_merge_user_fs(struct libmnt_table *tb, struct libmnt_fs *uf) { struct libmnt_fs *fs; struct libmnt_iter itr; const char *optstr, *src, *target, *root, *attrs; assert(tb); assert(uf); if (!tb || !uf) return NULL; DBG(TAB, ul_debugobj(tb, "merging user fs")); src = mnt_fs_get_srcpath(uf); target = mnt_fs_get_target(uf); optstr = mnt_fs_get_user_options(uf); attrs = mnt_fs_get_attributes(uf); root = mnt_fs_get_root(uf); if (!src || !target || !root || (!attrs && !optstr)) return NULL; mnt_reset_iter(&itr, MNT_ITER_BACKWARD); while(mnt_table_next_fs(tb, &itr, &fs) == 0) { const char *r = mnt_fs_get_root(fs); if (fs->flags & MNT_FS_MERGED) continue; if (r && strcmp(r, root) == 0 && mnt_fs_streq_target(fs, target) && mnt_fs_streq_srcpath(fs, src)) break; } if (fs) { DBG(TAB, ul_debugobj(tb, "found fs -- appending user optstr")); mnt_fs_append_options(fs, optstr); mnt_fs_append_attributes(fs, attrs); mnt_fs_set_bindsrc(fs, mnt_fs_get_bindsrc(uf)); fs->flags |= MNT_FS_MERGED; DBG(TAB, ul_debugobj(tb, "found fs:")); DBG(TAB, mnt_fs_print_debug(fs, stderr)); } return fs; }
/** * fdisk_unref_context: * @cxt: fdisk context * * Deallocates context struct. */ void fdisk_unref_context(struct fdisk_context *cxt) { int i; if (!cxt) return; cxt->refcount--; if (cxt->refcount <= 0) { DBG(CXT, ul_debugobj(cxt, "freeing context %p for %s", cxt, cxt->dev_path)); reset_context(cxt); /* this is sensitive to parent<->child relationship! */ /* deallocate label's private stuff */ for (i = 0; i < cxt->nlabels; i++) { if (!cxt->labels[i]) continue; if (cxt->labels[i]->op->free) cxt->labels[i]->op->free(cxt->labels[i]); else free(cxt->labels[i]); } fdisk_unref_context(cxt->parent); cxt->parent = NULL; free(cxt); } }
/** * fdisk_set_partition: * @cxt: context * @partno: partition number (0 is the first partition) * @pa: new partition setting * * Modifies disklabel according to setting with in @pa. * * Returns: 0 on success, <0 on error. */ int fdisk_set_partition(struct fdisk_context *cxt, size_t partno, struct fdisk_partition *pa) { struct fdisk_partition *xpa = pa; int rc; if (!cxt || !cxt->label || !pa) return -EINVAL; if (!cxt->label->op->set_part) return -ENOSYS; if (pa->resize || fdisk_partition_has_start(pa) || fdisk_partition_has_size(pa)) { xpa = __copy_partition(pa); xpa->movestart = 0; xpa->resize = 0; FDISK_INIT_UNDEF(xpa->size); FDISK_INIT_UNDEF(xpa->start); rc = recount_resize(cxt, partno, xpa, pa); if (rc) goto done; } DBG(CXT, ul_debugobj(cxt, "setting partition %zu %p (start=%ju, end=%ju, size=%ju)", partno, xpa, (uintmax_t) fdisk_partition_get_start(xpa), (uintmax_t) fdisk_partition_get_end(xpa), (uintmax_t) fdisk_partition_get_size(xpa))); rc = cxt->label->op->set_part(cxt, partno, xpa); done: if (xpa != pa) fdisk_unref_partition(xpa); return rc; }
/** * scols_line_alloc_cells: * @ln: a pointer to a struct libscols_line instance * @n: the number of elements * * Allocates space for @n cells. This function is optional, * and libsmartcols automatically allocates necessary cells * according to number of columns in the table when you add * the line to the table. See scols_table_add_line(). * * Returns: 0, a negative value in case of an error. */ int scols_line_alloc_cells(struct libscols_line *ln, size_t n) { struct libscols_cell *ce; if (!ln) return -EINVAL; if (ln->ncells == n) return 0; if (!n) { scols_line_free_cells(ln); return 0; } DBG(LINE, ul_debugobj(ln, "alloc %zu cells", n)); ce = realloc(ln->cells, n * sizeof(struct libscols_cell)); if (!ce) return -errno; if (n > ln->ncells) memset(ce + ln->ncells, 0, (n - ln->ncells) * sizeof(struct libscols_cell)); ln->cells = ce; ln->ncells = n; return 0; }
/** * fdisk_create_disklabel: * @cxt: fdisk context * @name: label name * * Creates a new disk label of type @name. If @name is NULL, then it * will create a default system label type, either SUN or DOS. * * Returns 0 on success, otherwise, a corresponding error. */ int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name) { int haslabel = 0; struct fdisk_label *lb; if (!cxt) return -EINVAL; if (!name) { /* use default label creation */ #ifdef __sparc__ name = "sun"; #else name = "dos"; #endif } if (cxt->label) { fdisk_deinit_label(cxt->label); haslabel = 1; } lb = fdisk_context_get_label(cxt, name); if (!lb || lb->disabled) return -EINVAL; if (!lb->op->create) return -ENOSYS; __fdisk_context_switch_label(cxt, lb); if (haslabel && !cxt->parent) fdisk_reset_device_properties(cxt); DBG(CXT, ul_debugobj(cxt, "create a new %s label", lb->name)); return cxt->label->op->create(cxt); }
/* note that the @key could be the same pointer as @value */ static int cache_add_entry(struct libmnt_cache *cache, char *key, char *value, int flag) { struct mnt_cache_entry *e; assert(cache); assert(value); assert(key); if (cache->nents == cache->nallocs) { size_t sz = cache->nallocs + MNT_CACHE_CHUNKSZ; e = realloc(cache->ents, sz * sizeof(struct mnt_cache_entry)); if (!e) return -ENOMEM; cache->ents = e; cache->nallocs = sz; } e = &cache->ents[cache->nents]; e->key = key; e->value = value; e->flag = flag; cache->nents++; DBG(CACHE, ul_debugobj(cache, "add entry [%2zd] (%s): %s: %s", cache->nents, (flag & MNT_CACHE_ISPATH) ? "path" : "tag", value, key)); return 0; }
static int append_comment(struct libmnt_table *tb, struct libmnt_fs *fs, const char *comm, int eof) { int rc, intro = mnt_table_get_nents(tb) == 0; if (intro && is_terminated_by_blank(mnt_table_get_intro_comment(tb))) intro = 0; DBG(TAB, ul_debugobj(tb, "appending %s comment", intro ? "intro" : eof ? "trailing" : "fs")); if (intro) rc = mnt_table_append_intro_comment(tb, comm); else if (eof) { rc = mnt_table_set_trailing_comment(tb, mnt_fs_get_comment(fs)); if (!rc) rc = mnt_table_append_trailing_comment(tb, comm); if (!rc) rc = mnt_fs_set_comment(fs, NULL); } else rc = mnt_fs_append_comment(fs, comm); return rc; }
struct fdisk_context *fdisk_new_context(void) { struct fdisk_context *cxt; cxt = calloc(1, sizeof(*cxt)); if (!cxt) return NULL; DBG(CXT, ul_debugobj(cxt, "alloc")); cxt->dev_fd = -1; /* * Allocate label specific structs. * * This is necessary (for example) to store label specific * context setting. */ cxt->labels[ cxt->nlabels++ ] = fdisk_new_gpt_label(cxt); cxt->labels[ cxt->nlabels++ ] = fdisk_new_dos_label(cxt); cxt->labels[ cxt->nlabels++ ] = fdisk_new_bsd_label(cxt); cxt->labels[ cxt->nlabels++ ] = fdisk_new_sgi_label(cxt); cxt->labels[ cxt->nlabels++ ] = fdisk_new_sun_label(cxt); return cxt; }
int scols_line_move_cells(struct libscols_line *ln, size_t newn, size_t oldn) { struct libscols_cell ce; if (!ln || newn >= ln->ncells || oldn >= ln->ncells) return -EINVAL; if (oldn == newn) return 0; DBG(LINE, ul_debugobj(ln, "move cells[%zu] -> cells[%zu]", oldn, newn)); /* remember data from old position */ memcpy(&ce, &ln->cells[oldn], sizeof(struct libscols_cell)); /* remove old position (move data behind oldn to oldn) */ if (oldn + 1 < ln->ncells) memmove(ln->cells + oldn, ln->cells + oldn + 1, (ln->ncells - oldn - 1) * sizeof(struct libscols_cell)); /* create a space for new position */ if (newn + 1 < ln->ncells) memmove(ln->cells + newn + 1, ln->cells + newn, (ln->ncells - newn - 1) * sizeof(struct libscols_cell)); /* copy original data to new position */ memcpy(&ln->cells[newn], &ce, sizeof(struct libscols_cell)); return 0; }
static int tabdiff_reset(struct libmnt_tabdiff *df) { assert(df); DBG(DIFF, ul_debugobj(df, "resetting")); /* zeroize all entries and move them to the list of unused */ while (!list_empty(&df->changes)) { struct tabdiff_entry *de = list_entry(df->changes.next, struct tabdiff_entry, changes); list_del(&de->changes); list_add_tail(&de->changes, &df->unused); mnt_unref_fs(de->new_fs); mnt_unref_fs(de->old_fs); de->new_fs = de->old_fs = NULL; de->oper = 0; } df->nchanges = 0; return 0; }
static void reset_context(struct fdisk_context *cxt) { size_t i; DBG(CXT, ul_debugobj(cxt, "*** resetting context")); /* reset drives' private data */ for (i = 0; i < cxt->nlabels; i++) fdisk_deinit_label(cxt->labels[i]); if (cxt->parent) { /* the first sector may be independent on parent */ if (cxt->parent->firstsector != cxt->firstsector) free(cxt->firstsector); } else { /* we close device only in primary context */ if (cxt->dev_fd > -1) close(cxt->dev_fd); free(cxt->firstsector); } free(cxt->dev_path); cxt->dev_path = NULL; cxt->dev_fd = -1; cxt->firstsector = NULL; cxt->firstsector_bufsz = 0; fdisk_zeroize_device_properties(cxt); fdisk_unref_script(cxt->script); cxt->script = NULL; cxt->label = NULL; }
static int prepare_helper_from_options(struct libmnt_context *cxt, const char *name) { char *suffix = NULL; const char *opts; size_t valsz; if (mnt_context_is_nohelpers(cxt)) return 0; opts = mnt_fs_get_user_options(cxt->fs); if (!opts) return 0; if (mnt_optstr_get_option(opts, name, &suffix, &valsz)) return 0; suffix = strndup(suffix, valsz); if (!suffix) return -ENOMEM; DBG(CXT, ul_debugobj(cxt, "umount: umount.%s %s requested", suffix, name)); return mnt_context_prepare_helper(cxt, "umount", suffix); }
/* special case for '*' in the paths */ static void dirlist_add_subdir(struct wh_dirlist **ls, int type, const char *dir) { char buf[PATH_MAX], *d; DIR *dirp; struct dirent *dp; strncpy(buf, dir, PATH_MAX); buf[PATH_MAX - 1] = '\0'; d = strchr(buf, '*'); if (!d) return; *d = 0; dirp = opendir(buf); if (!dirp) return; DBG(LIST, ul_debugobj(*ls, " scanning subdir: %s", dir)); while ((dp = readdir(dirp)) != NULL) { if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; snprintf(d, PATH_MAX - (d - buf), "%s", dp->d_name); /* a dir definition can have a star in middle of path */ strcat(buf, strchr(dir, '*') + 1); dirlist_add_dir(ls, type, buf); } closedir(dirp); return; }
/** * scols_copy_column: * @cl: a pointer to a struct libscols_column instance * * Creates a new column and copies @cl's data over to it. * * Returns: a pointer to a new struct libscols_column instance. */ struct libscols_column *scols_copy_column(const struct libscols_column *cl) { struct libscols_column *ret; if (!cl) return NULL; ret = scols_new_column(); if (!ret) return NULL; DBG(COL, ul_debugobj((void *) cl, "copy to %p", ret)); if (scols_column_set_color(ret, cl->color)) goto err; if (scols_cell_copy_content(&ret->header, &cl->header)) goto err; ret->width = cl->width; ret->width_min = cl->width_min; ret->width_max = cl->width_max; ret->width_avg = cl->width_avg; ret->width_hint = cl->width_hint; ret->flags = cl->flags; ret->is_extreme = cl->is_extreme; return ret; err: scols_unref_column(ret); return NULL; }
static void reset_context(struct fdisk_context *cxt) { size_t i; DBG(CXT, ul_debugobj(cxt, "*** resetting context")); /* reset drives' private data */ for (i = 0; i < cxt->nlabels; i++) fdisk_deinit_label(cxt->labels[i]); /* free device specific stuff */ if (!cxt->parent && cxt->dev_fd > -1) close(cxt->dev_fd); free(cxt->dev_path); if (cxt->parent == NULL || cxt->parent->firstsector != cxt->firstsector) free(cxt->firstsector); /* initialize */ cxt->dev_fd = -1; cxt->dev_path = NULL; cxt->firstsector = NULL; fdisk_zeroize_device_properties(cxt); cxt->label = NULL; }
static char *canonicalize_path_and_cache(const char *path, struct libmnt_cache *cache) { char *p = NULL; char *key = NULL; char *value = NULL; DBG(CACHE, ul_debugobj(cache, "canonicalize path %s", path)); p = canonicalize_path(path); if (p && cache) { value = p; key = strcmp(path, p) == 0 ? value : strdup(path); if (!key || !value) goto error; if (cache_add_entry(cache, key, value, MNT_CACHE_ISPATH)) goto error; } return p; error: if (value != key) free(value); free(key); return NULL; }
/* * Deletes loop device */ int mnt_context_delete_loopdev(struct libmnt_context *cxt) { const char *src; int rc; assert(cxt); assert(cxt->fs); if (!cxt) return -EINVAL; src = mnt_fs_get_srcpath(cxt->fs); if (!src) return -EINVAL; if (cxt->loopdev_fd > -1) close(cxt->loopdev_fd); rc = loopdev_delete(src); cxt->flags &= ~MNT_FL_LOOPDEV_READY; cxt->loopdev_fd = -1; DBG(CXT, ul_debugobj(cxt, "loopdev deleted [rc=%d]", rc)); return rc; }