+/*
+ * Concatenate context of the temporary mount point iff selinux is enabled
+ */
+#ifdef HAVE_SELINUX
+static void append_context_for_mount(char *mntpt, struct mkfs_opts *mop)
+{
+ security_context_t fcontext;
+
+ if (getfilecon(mntpt, &fcontext) < 0) {
+ /* Continuing with default behaviour */
+ fprintf(stderr, "%s: Get file context failed : %s\n",
+ progname, strerror(errno));
+ return;
+ }
+
+ if (fcontext != NULL) {
+ strcat(mop->mo_ldd.ldd_mount_opts, ",context=");
+ strcat(mop->mo_ldd.ldd_mount_opts, fcontext);
+ freecon(fcontext);
+ }
+}
+#endif
+
+/* return canonicalized absolute pathname, even if the target file does not
+ * exist, unlike realpath */
+static char *absolute_path(char *devname)
+{
+ char buf[PATH_MAX + 1] = "";
+ char *path;
+ char *ptr;
+ int len;
+
+ path = malloc(sizeof(buf));
+ if (path == NULL)
+ return NULL;
+
+ if (devname[0] != '/') {
+ if (getcwd(buf, sizeof(buf) - 1) == NULL) {
+ free(path);
+ return NULL;
+ }
+ len = snprintf(path, sizeof(buf), "%s/%s", buf, devname);
+ if (len >= sizeof(buf)) {
+ free(path);
+ return NULL;
+ }
+ } else {
+ len = snprintf(path, sizeof(buf), "%s", devname);
+ if (len >= sizeof(buf)) {
+ free(path);
+ return NULL;
+ }
+ }
+
+ /* truncate filename before calling realpath */
+ ptr = strrchr(path, '/');
+ if (ptr == NULL) {
+ free(path);
+ return NULL;
+ }
+ *ptr = '\0';
+ if (buf != realpath(path, buf)) {
+ free(path);
+ return NULL;
+ }
+ /* add the filename back */
+ len = snprintf(path, PATH_MAX, "%s/%s", buf, ptr+1);
+ if (len >= PATH_MAX) {
+ free(path);
+ return NULL;
+ }
+ return path;
+}
+
+/* Determine if a device is a block device (as opposed to a file) */
+static int is_block(char *devname)
+{
+ struct stat st;
+ int ret = 0;
+ char *devpath;
+
+ devpath = absolute_path(devname);
+ if (devpath == NULL) {
+ fprintf(stderr, "%s: failed to resolve path to %s\n",
+ progname, devname);
+ return -1;
+ }
+
+ ret = access(devname, F_OK);
+ if (ret != 0) {
+ if (strncmp(devpath, "/dev/", 5) == 0) {
+ /* nobody sane wants to create a loopback file under
+ * /dev. Let's just report the device doesn't exist */
+ fprintf(stderr, "%s: %s apparently does not exist\n",
+ progname, devpath);
+ ret = -1;
+ goto out;
+ }
+ ret = 0;
+ goto out;
+ }
+ ret = stat(devpath, &st);
+ if (ret != 0) {
+ fprintf(stderr, "%s: cannot stat %s\n", progname, devpath);
+ goto out;
+ }
+ ret = S_ISBLK(st.st_mode);
+out:
+ free(devpath);
+ return ret;
+}
+
+static int is_feature_enabled(const char *feature, const char *devpath)
+{
+ char cmd[PATH_MAX];
+ FILE *fp;
+ char enabled_features[4096] = "";
+ int ret = 1;
+
+ snprintf(cmd, sizeof(cmd), "%s -R features %s 2>&1",
+ DEBUGFS, devpath);
+
+ /* Using popen() instead of run_command() since debugfs does
+ * not return proper error code if command is not supported */
+ fp = popen(cmd, "r");
+ if (!fp) {
+ fprintf(stderr, "%s: %s\n", progname, strerror(errno));
+ return 0;
+ }
+
+ ret = fread(enabled_features, 1, sizeof(enabled_features) - 1, fp);
+ enabled_features[ret] = '\0';
+ pclose(fp);
+
+ if (strstr(enabled_features, feature))
+ return 1;
+ return 0;
+}
+