# Userland C program using zfs



## diaren (Jan 20, 2020)

Which includes and librariries are required to use zfs from a userland C program?. .e.g. create/destroy a filesystem and snapshot.
The only include I can find that uses zfs is /usr/include/libzfs_core.h, which requires nvpair, which requires a bunch of solaris typedefs to compile.
It seems that the required includes are in /usr/src but not included in world???


----------



## ralphbsz (Jan 20, 2020)

Two answers, neither actually very helpful.

First, you don't need any. Just use the system(3) function in the standard library to call the ZFS executables (like zfs or zpool) through shelling out.

Second: Download the system source code, and look at the source for the commands zfs and zpool. I'm going to bet that they ultimately use an ioctl to get into the kernel. Copy what they do there. But be aware that this is probably not an API that is supported or stable, so any version change can break your program.


----------



## yuripv (Jan 20, 2020)

Use libzfs_core.  It's still not public interface and isn't well documented (if at all), but it's going (or at least, was going) to be one.  You can look up the actual API looking at /usr/src/cddl/contrib/opensolaris/lib/libzfs_core/common/libzfs_core.c.

As for the "solaris typedefs", please provide a code snippet showing the problem.


----------



## diaren (Jan 20, 2020)

yuripv said:


> As for the "solaris typedefs", please provide a code snippet showing the problem.



So this is what I had before I asked the question... just to test if was at all possible.

```
#include <stdint.h>
#include <sys/param.h>
#include <sys/uio.h>

/* Sourced from /usr/src/sys/cddl/compat/opensolaris/sys/types.h */
typedef unsigned int uint_t;
typedef unsigned char uchar_t;
typedef unsigned short ushort_t;
typedef unsigned long ulong_t;
typedef unsigned long ulong_t;
typedef long long hrtime_t;
typedef enum {_B_FALSE, _B_TRUE} boolean_t;

enum lzc_dataset_type {
  LZC_DATSET_TYPE_ZFS = 2,
  LZC_DATSET_TYPE_ZVOL
};

#include <libnvpair.h>

int libzfs_core_init(void);
void libzfs_core_fini(void);
int lzc_snapshot(nvlist_t *, nvlist_t *, nvlist_t **);
int lzc_create(const char *, enum lzc_dataset_type, nvlist_t *);
int lzc_clone(const char *, const char *, nvlist_t *);
int lzc_destroy_snaps(nvlist_t *, boolean_t, nvlist_t **);
int lzc_rollback(const char *, char *, int);
int lzc_destroy(const char *);
```
With the above and using lzc_create, lzc_destroy it compiles and successfully creates/destroys a filesystem. But obviously this can't be right... If /usr/include/libzfs_core.h is included then sys/fs/zfs.h is required, which is only in /usr/src/sys/cddl/contrib/opensolaris... along with more undefined types.

I'd just like to know if/what is the definitive way of using libzfs_core or libzfs from base in a userland program.


----------



## yuripv (Jan 20, 2020)

I think it's a bug then, we should either ship the sys/fs/zfs.h and friends, or don't ship libzfs_core.h.  For the moment you could just pass the paths to includes using `-I/path/`, and require the source to be installed for your program to build.


----------



## diaren (Jan 21, 2020)

Hmm, ok. Using /usr/src results in the following code. I'll extract all required headers, and post a bug/fix.

```
// CFLAGS -xc -std=c11 -DNEED_SOLARIS_BOOLEAN -I/usr/src/sys/cddl/compat/opensolaris -I/usr/src/sys/cddl/contrib/opensolaris/uts/common -lnvpair -lzfs_core
// ARGS zroot/zfs-test
#include <err.h>
#include <libzfs_core.h>

int main(int argc, char const* argv[]) {
  if (libzfs_core_init() != 0) {
    err(1, "libzfs_core_init");
  }

  if (argc == 2) {
    char const *zfs_path = argv[1];

    if (lzc_create(zfs_path, LZC_DATSET_TYPE_ZFS, NULL) == 0) {
      warnx("%s: created", zfs_path);
      if (lzc_destroy(zfs_path) == 0) {
        warnx("%s: destroyed", zfs_path);
      }
      else {
        warn("%s could not be destroyed", zfs_path);
      }
    }
    else {
      warn("%s could not be created", zfs_path);
    }
  }
  else {
    warnx("%s <ZFSPATH>", argv[0]);
  }

  libzfs_core_fini();
  return 0;
}
```


----------

