[no subject]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



To free dynamically allocated Rust data, C functions registering callbacks
should have a signature like the one shown below:

```C
void widget_register_callback(
    widget_t *widget,
    void *data,
    void (*callback)(void*, event_t),
    void (*destroy)(void*)
);
```

See this blog post [Neat Rust Tricks: Passing Rust Closures to
C](http://blog.sagetheprogrammer.com/neat-rust-tricks-passing-rust-closures-to-c)
for a presentation of what I dream `util-linux` had. (���)�

While reading `util-linux`'s source code, I identified three types of functions
to register callbacks:

- functions for which it is essentially impossible to create Rust bindings,
  case in point: `fdisk_table_sort_partitions` (see documentation further down).
  This function has a signature that looks like the example below.

  ```C
  void widget_register_callback(
      widget_t *widget,
      void (*callback)(event_t),
  );
  ```

  You will notice that it does not:
  + have a data pointer (`void *data`),
  + provide a callback function that accepts a `void*` parameter,
  + offer a way to set a destructor.

- functions for registering long-lived callbacks with a signature like the one
  shown below

  ```C
  void widget_register_callback(
      widget_t *widget,
      void (*callback)(void*, event_t),
  );
  ```
  For example, `mnt_table_set_parser_errcb` that acts on a `struct
  libmnt_table`. This structure has an internal field to store a data pointer,
  along with specialized accessor functions to get/set it (respectively
  `mnt_table_get_userdata `, and `mnt_table_set_userdata `). However, lacking a
  way to define a destructor, this function will leak memory each time it is
  called to replace a callback.

- functions for registering short-lived callbacks with a signature like the one
  shown below

  ```C
  void widget_register_callback(
      widget_t *widget,
      void *data,
      void (*callback)(void*, event_t),
  );
  ```
  For example, `mnt_table_find_next_fs` which is the closest to the ideal form.
  Although it lacks a way to define a destructor, being short-lived, it allows
  the enclosing Rust binding to take care of releasing resources allocated on
  the heap.

https://github.com/util-linux/util-linux/blob/stable/v2.39/libfdisk/src/fdiskP.h#L200-L205

```C
struct fdisk_table {
struct list_head parts; /* partitions */
int refcount;
size_t nents; /* number of partitions */
};

```

https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.39/libfdisk-docs/libfdisk-Table.html#fdisk-table-sort-partitions

```text
int
fdisk_table_sort_partitions (struct fdisk_table *tb,
                             int (*cmp) (struct fdisk_partition *, struct fdisk_partition *));

Sort partition in the table.

Parameters

tb table

cmp compare function

Returns

0 on success, <0 on error.
```

https://github.com/util-linux/util-linux/blob/stable/v2.39/libmount/src/mountP.h#L249-L273

```C
/*
 * fstab/mountinfo file
 */
struct libmnt_table {
int fmt; /* MNT_FMT_* file format */
int nents; /* number of entries */
int refcount; /* reference counter */
int comms; /* enable/disable comment parsing */
char *comm_intro; /* First comment in file */
char *comm_tail; /* Last comment in file */


struct libmnt_cache *cache; /* canonicalized paths/tags cache */


        int (*errcb)(struct libmnt_table *tb,
const char *filename, int line);


int (*fltrcb)(struct libmnt_fs *fs, void *data);
void *fltrcb_data;


int noautofs; /* ignore autofs mounts */


struct list_head ents; /* list of entries (libmnt_fs) */
void *userdata;
};
```

https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.39/libmount-docs/libmount-Table-of-filesystems.html#mnt-table-set-parser-errcb

```text
int
mnt_table_set_parser_errcb (struct libmnt_table *tb,
                            int (*cb) (struct libmnt_table *tb, const char *filename, int line));

The error callback function is called by table parser (mnt_table_parse_file())
in case of a syntax error. The callback function could be used for error
evaluation, libmount will continue/stop parsing according to callback return
codes:

<0 : fatal error (abort parsing) 0 : success (parsing continues) >0 :
recoverable error (the line is ignored, parsing continues).

Parameters

tb pointer to table

cb pointer to callback function

Returns

0 on success or negative number in case of error.
```

https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.39/libmount-docs/libmount-Table-of-filesystems.html#mnt-table-get-userdata

```text
void *
mnt_table_get_userdata (struct libmnt_table *tb);

Parameters

tb pointer to tab

Returns

pointer to user's data.
```

https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.39/libmount-docs/libmount-Table-of-filesystems.html#mnt-table-set-userdata

```text
int
mnt_table_set_userdata (struct libmnt_table *tb,
                        void *data);

Sets pointer to the private user data.
Parameters

tb pointer to tab


data pointer to user data

Returns

0 on success or negative number in case of error.
```

https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.39/libmount-docs/libmount-Table-of-filesystems.html#mnt-table-find-next-fs

```text
int
mnt_table_find_next_fs (struct libmnt_table *tb,
                        struct libmnt_iter *itr,
                        int (*match_func) (struct libmnt_fs *, void *),
                        void *userdata,
                        struct libmnt_fs **fs);

This function allows searching in tb .

Parameters

tb table

itr iterator

match_func function returning 1 or 0

userdata extra data for match_func

fs NULL or returns pointer to the next matching table entry

Returns

negative number in case of error, 1 at end of table or 0 o success.
```

G2 - How can I create device images that will trigger errors when running
unit-tests?

For example, files in `util-linux/tests/expected/blkid` show the expected
outputs after probing the properties of device images in
`util-linux/tests/ts/blkid/images-fs`.

Each image in the directory has a well-formed partition table, so tests will
always walk the "happy path". There is no image that could, for example,
trigger a collision error between probing results.

Rust provides its own test framework, with which it is easy to check functions
(including error cases) at a more granular level than with the test suite in
`util-linux`.

Knowing how to create an intentionally broken device image would be wonderful.
It would allow me to increase test coverage of my Rust-bindings.

## libblkid

B1 - Are there public accessor functions on the roadmap of `libblkid` for
reading the private fields `bid_pri`, `bid_devno`, and `bid_time` in
`blkid_dev_struct`?

For the moment, I can not accurately reproduce the way data about a
`blkid_struct_dev` is printed in `/run/blkid/blkid.tab` due to not being able
to access the relevant fields.

Example of a line in `/run/blkid/blkid.tab`

```text
<device DEVNO="0xfe01" TIME="1687337407.788618" PRI="45" LABEL="root" UUID="9e4adae9-4122-47fe-848f-67a9eb726207" BLOCK_SIZE="4096" TYPE="ext4">/dev/mapper/vg_nixos-root</device>
```

What I can currently output from Rust

```text
<device LABEL="root" UUID="9e4adae9-4122-47fe-848f-67a9eb726207" BLOCK_SIZE="4096" TYPE="ext4">/dev/mapper/vg_nixos-root</device>
```

https://github.com/util-linux/util-linux/blob/8aa25617467a1249669cff7240ca31973bf9a127/libblkid/src/blkidP.h#L45-L61

```C
struct blkid_struct_dev
{
struct list_head bid_devs; /* All devices in the cache */
struct list_head bid_tags; /* All tags for this device */
blkid_cache bid_cache; /* Dev belongs to this cache */
char *bid_name; /* Device real path (as used in cache) */
char *bid_xname; /* Device path as used by application (maybe symlink..) */
char *bid_type; /* Preferred device TYPE */
int bid_pri; /* Device priority */
dev_t bid_devno; /* Device major/minor number */
time_t bid_time; /* Last update time of device */
suseconds_t bid_utime; /* Last update time (microseconds) */
unsigned int bid_flags; /* Device status bitflags */
char *bid_label; /* Shortcut to device LABEL */
char *bid_uuid; /* Shortcut to binary UUID */
};
```


B2 - Does anyone know what the function `blkid_dev_set_search` is supposed to
do?

There are no docstrings for this function. Although I read its source code, I
could not figure out its purpose.  <('^-^)

https://github.com/util-linux/util-linux/blob/stable/v2.39/libblkid/src/dev.c#L150-L172

```C
int blkid_dev_set_search(blkid_dev_iterate iter,
const char *search_type, const char *search_value)
{
char *new_type, *new_value;


if (!iter || iter->magic != DEV_ITERATE_MAGIC || !search_type ||
   !search_value)
return -1;
new_type = malloc(strlen(search_type)+1);
new_value = malloc(strlen(search_value)+1);
if (!new_type || !new_value) {
free(new_type);
free(new_value);
return -1;
}
strcpy(new_type, search_type);
strcpy(new_value, search_value);
free(iter->search_type);
free(iter->search_value);
iter->search_type = new_type;
iter->search_value = new_value;
return 0;
}
```


B3 -  Do I define `size` as `uint64_t` or `int64_t`?

The `size` field in `struct blkid_struct_probe` is of type `uint64_t`. But,
according to the documentation, its accessor function `blkid_probe_get_sectors`
may return `-1` in case of error.

Reading the code of `blkid_probe_get_sectors`, I can see that it just divides
`size` by 512 which would never return a negative value (see below).

https://github.com/util-linux/util-linux/blob/stable/v2.39/libblkid/src/blkidP.h#L203-L233

```C
/*
 * Low-level probing control struct
 */
struct blkid_struct_probe
{
int fd; /* device file descriptor */
uint64_t off; /* begin of data on the device */
uint64_t size; /* end of data on the device */

dev_t devno; /* device number (st.st_rdev) */
dev_t disk_devno; /* devno of the whole-disk or 0 */
unsigned int blkssz; /* sector size (BLKSSZGET ioctl) */
mode_t mode; /* struct stat.sb_mode */
uint64_t zone_size; /* zone size (BLKGETZONESZ ioctl) */

int flags; /* private library flags */
int prob_flags; /* always zeroized by blkid_do_*() */

uint64_t wipe_off; /* begin of the wiped area */
uint64_t wipe_size; /* size of the wiped area */
struct blkid_chain *wipe_chain; /* superblock, partition, ... */

struct list_head buffers; /* list of buffers */
struct list_head hints;

struct blkid_chain chains[BLKID_NCHAINS]; /* array of chains */
struct blkid_chain *cur_chain; /* current chain */

struct list_head values; /* results */

struct blkid_struct_probe *parent; /* for clones */
struct blkid_struct_probe *disk_probe; /* whole-disk probing */
};

```

https://github.com/util-linux/util-linux/blob/stable/v2.39/libblkid/src/blkid.h.in#L85-L90

```C
/**
 * blkid_loff_t:
 *
 * 64-bit signed number for offsets and sizes
 */
typedef int64_t blkid_loff_t;
```

https://github.com/util-linux/util-linux/blob/8aa25617467a1249669cff7240ca31973bf9a127/libblkid/src/probe.c#L1971-L1983

```C
/**
 * blkid_probe_get_sectors:
 * @pr: probe
 *
 * Returns: 512-byte sector count or -1 in case of error.
 */
blkid_loff_t blkid_probe_get_sectors(blkid_probe pr)
{
return (blkid_loff_t) (pr->size >> 9);
}
```


B4 - Is the documentation out-of-date or just anticipating a future change?

The function `blkid_probe_set_sectorsize` always returns `0`, but its docstring
says otherwise.

https://github.com/util-linux/util-linux/blob/8aa25617467a1249669cff7240ca31973bf9a127/libblkid/src/probe.c#L2014-L2030

```C
/**
 * blkid_probe_set_sectorsize:
 * @pr: probe
 * @sz: new size (to overwrite system default)
 *
 * Note that blkid_probe_set_device() resets this setting. Use it after
 * blkid_probe_set_device() and before any probing call.
 *
 * Since: 2.30
 *
 * Returns: 0 or <0 in case of error
 */
int blkid_probe_set_sectorsize(blkid_probe pr, unsigned int sz)
{
pr->blkssz = sz;
return 0;
}
```


B5 - Is there a list of all file systems supported by `libblkid`?

By searching the source code, I managed to constitute a list of supported file
systems gathered in the enum
[`FileSystem`](https://docs.rs/rsblkid/latest/rsblkid/partition/enum.FileSystem.html#variants)
in `rsblkid`.

It would be nice if I could double-check its accuracy from an official
reference.


B6 - Is there a list of all tags supported by `libblkid`?

By searching the source code, I managed to constitute a list of supported tags
gathered in the enum
[`Tag`](https://docs.rs/rsblkid/latest/rsblkid/device/enum.Tag.html#variants)
in `rsblkid`.

It would be nice if I could double-check its accuracy from an official
reference.

## libfdisk

F1 - What is a `grain size`?

The documentation of `fdisk_get_grain_size` says "grain in bytes used to align
partitions (usually 1MiB)" but does not elaborate.

https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.39/libfdisk-docs/libfdisk-Context.html#fdisk-get-grain-size

I stumbled on this answer about partition alignment during my search:

"What is partition alignment and why whould I need it?"

https://superuser.com/a/393918

Is it what `fdisk_get_grain_size` is refering to?


F2 - Are `fdisk_labelitem_*` supposed to have globally unique values, or is the
overlap intentional?

The way they are currently defined `SUN_LABELITEM_LABELID`,
`BSD_LABELITEM_TYPE`,`SGI_LABELITEM_PCYLCOUNT` , and `GPT_LABELITEM_FIRSTLBA`
end up having the same numerical value i.e.  `__FDISK_NLABELITEMS = 8`.

As I understand it, these LABELITEM are fields in a partition table header for
their respective partition table types.

To represent them in Rust, I use
[HeaderEntry](https://docs.rs/rsfdisk/latest/rsfdisk/partition_table/enum.HeaderEntry.html#)
which groups the LABELITEMs in a unified enum.

This enum uses a workaround to convert a `HeaderEntry` to the native `u32`
value used by `libfdisk`
https://github.com/nickpiaddo/rsfdisk/blob/main/src/core/partition_table/header_entry_enum.rs

But converting back from `u32` to `HeaderEntry` is all but impossible if the
value of each `fdisk_labelitem_*` is not globally unique.

See their definitions below.

https://github.com/util-linux/util-linux/blob/8aa25617467a1249669cff7240ca31973bf9a127/libfdisk/src/libfdisk.h.in#L414-L425

```C
  /**
   * fdisk_labelitem_gen:
   * @FDISK_LABELITEM_ID: Unique disk identifier
   * @__FDISK_NLABELITEMS: Specifies reserved range for generic items (0..7)
   *
   * Generic disklabel items.
   */
  enum fdisk_labelitem_gen {
    FDISK_LABELITEM_ID = 0,
    __FDISK_NLABELITEMS = 8
  };
```

https://github.com/util-linux/util-linux/blob/8aa25617467a1249669cff7240ca31973bf9a127/libfdisk/src/libfdisk.h.in#L634-L655

```C
    /**
   * fdisk_labelitem_sun:
   * @SUN_LABELITEM_LABELID: Label ID
   * @SUN_LABELITEM_VTOCID: Volume ID
   * @SUN_LABELITEM_RPM: Rpm
   * @SUN_LABELITEM_ACYL: Alternate cylinders
   * @SUN_LABELITEM_PCYL: Physical cylinders
   * @SUN_LABELITEM_APC: Extra sects/cyl
   * @SUN_LABELITEM_INTRLV: Interleave
   *
   * SUN specific label items.
   */
  enum fdisk_labelitem_sun {
    SUN_LABELITEM_LABELID = __FDISK_NLABELITEMS,
    SUN_LABELITEM_VTOCID,
    SUN_LABELITEM_RPM,
    SUN_LABELITEM_ACYL,
    SUN_LABELITEM_PCYL,
    SUN_LABELITEM_APC,
    SUN_LABELITEM_INTRLV
  };

```

https://github.com/util-linux/util-linux/blob/8aa25617467a1249669cff7240ca31973bf9a127/libfdisk/src/libfdisk.h.in#L661-L697

```C
    /**
   * fdisk_labelitem_bsd:
   * @BSD_LABELITEM_TYPE: type
   * @BSD_LABELITEM_DISK: disk
   * @BSD_LABELITEM_PACKNAME: packname
   * @BSD_LABELITEM_FLAGS: flags (removable, ecc, badsect)
   * @BSD_LABELITEM_SECSIZE: Bytes/Sector
   * @BSD_LABELITEM_NTRACKS: Tracks/Cylinder
   * @BSD_LABELITEM_SECPERCYL: Sectors/Cylinder
   * @BSD_LABELITEM_CYLINDERS: Cylinders
   * @BSD_LABELITEM_RPM: rpm
   * @BSD_LABELITEM_INTERLEAVE: interleave
   * @BSD_LABELITEM_TRACKSKEW: trackskew
   * @BSD_LABELITEM_CYLINDERSKEW: cylinderskew
   * @BSD_LABELITEM_HEADSWITCH: headswitch
   * @BSD_LABELITEM_TRKSEEK: track-to-track seek
   *
   * BSD specific label items.
   */
  enum fdisk_labelitem_bsd {
    /* specific */
    BSD_LABELITEM_TYPE = __FDISK_NLABELITEMS,
    BSD_LABELITEM_DISK,
    BSD_LABELITEM_PACKNAME,
    BSD_LABELITEM_FLAGS,
    BSD_LABELITEM_SECSIZE,
    BSD_LABELITEM_NTRACKS,
    BSD_LABELITEM_SECPERCYL,
    BSD_LABELITEM_CYLINDERS,
    BSD_LABELITEM_RPM,
    BSD_LABELITEM_INTERLEAVE,
    BSD_LABELITEM_TRACKSKEW,
    BSD_LABELITEM_CYLINDERSKEW,
    BSD_LABELITEM_HEADSWITCH,
    BSD_LABELITEM_TRKSEEK
  };

```

https://github.com/util-linux/util-linux/blob/8aa25617467a1249669cff7240ca31973bf9a127/libfdisk/src/libfdisk.h.in#L704-L719

```C
    /**
   * fdisk_labelitem_sgi:
   * @SGI_LABELITEM_PCYLCOUNT: Physical cylinders
   * @SGI_LABELITEM_SPARECYL: Extra sects/cyl
   * @SGI_LABELITEM_ILFACT: nterleave
   * @SGI_LABELITEM_BOOTFILE: Bootfile
   *
   * SGI specific label items.
   */
  enum fdisk_labelitem_sgi {
    SGI_LABELITEM_PCYLCOUNT = __FDISK_NLABELITEMS,
    SGI_LABELITEM_SPARECYL,
    SGI_LABELITEM_ILFACT,
    SGI_LABELITEM_BOOTFILE
  };

```

https://github.com/util-linux/util-linux/blob/8aa25617467a1249669cff7240ca31973bf9a127/libfdisk/src/libfdisk.h.in#L775-L798

```C
    /**
   * fdisk_labelitem_gpt:
   * @GPT_LABELITEM_ID: GPT disklabel UUID (!= partition UUID)
   * @GPT_LABELITEM_FIRSTLBA: First Usable LBA
   * @GPT_LABELITEM_LASTLBA: Last Usable LBA
   * @GPT_LABELITEM_ALTLBA: Alternative LBA (backup header LBA)
   * @GPT_LABELITEM_ENTRIESLBA: Partitions entries array LBA
   * @GPT_LABELITEM_ENTRIESALLOC: Number of allocated entries in entries array
   * @GPT_LABELITEM_ENTRIESLASTLBA: Last LBA where is entries array
   *
   * GPT specific label items.
   */
  enum fdisk_labelitem_gpt {
    /* generic */
    GPT_LABELITEM_ID = FDISK_LABELITEM_ID,
    /* specific */
    GPT_LABELITEM_FIRSTLBA = __FDISK_NLABELITEMS,
    GPT_LABELITEM_LASTLBA,
    GPT_LABELITEM_ALTLBA,
    GPT_LABELITEM_ENTRIESLBA,
    GPT_LABELITEM_ENTRIESALLOC,
    GPT_LABELITEM_ENTRIESLASTLBA
  };

```


F3 - In the function `fdisk_locate_disklabel`, in what unit are `offset`, and
`size` expressed? bytes? sectors?

https://mirrors.edge.kernel.org/pub/linux/utils/util-linux/v2.39/libfdisk-docs/libfdisk-Label.html#fdisk-locate-disklabel

```text
  int
  fdisk_locate_disklabel (struct fdisk_context *cxt,
                          int n,
                          const char **name,
                          uint64_t *offset,
                          size_t *size);

  Locate disklabel and returns info about n item of the label.

  For example GPT is composed from three items, PMBR and GPT, n=0 return offset
  to PMBR and n=1 return offset to GPT Header and n=2 returns offset to GPT array
  of partitions, n=3 and n=4 returns location of the backup GPT label at the end
  of the disk.

  The function returns the current in-memory situation. It's possible that a
  header location is modified by write operation, for example when enabled
  minimization (see fdisk_gpt_enable_minimize()). In this case it's better to
  call this function after fdisk_write_disklabel().

  For more details see 'D' expert fdisk command.

  Parameters

    cxt context

    n N item

    name return item name

    offset return offset where is item

    size of the item

  Returns

    0 on success, <0 on error, 1 no more items.

```

## libmount

M1 - Does `libmount` plan to provide public functions to access/set the
private `fmt` field in `struct libmnt_table`?


[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux