// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (c) Linux Test Project, 2019-2022
 * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
 * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SKIP_DELIMITER ','

#define TST_NO_DEFAULT_MAIN
#include "tst_test.h"
#include "tst_fs.h"

#define err_exit(...) ({ \
	fprintf(stderr, __VA_ARGS__); \
	fprintf(stderr, "\n"); \
	usage(); \
	exit(2); \
})

#define fail_exit(...) ({ \
	fprintf(stderr, __VA_ARGS__); \
	fprintf(stderr, "\n"); \
	exit(1); \
})

#define info_exit(...) ({ \
	fprintf(stderr, __VA_ARGS__); \
	fprintf(stderr, "\n"); \
	exit(0); \
})

static void usage(void)
{
	fprintf(stderr, "Usage:\n");
	fprintf(stderr, "* all filesystems\n");
	fprintf(stderr, "tst_supported_fs [-s skip_list]\n");
	fprintf(stderr, "   print the list of supported filesystems\n");
	fprintf(stderr, "   if fs_type is supported and not in skip_list (optional),\n"
			"   print list of supported filesystems and return 0\n");
	fprintf(stderr, "   if fs_type isn't supported or in skip_list, return 1\n\n");

	fprintf(stderr, "* single filesystem\n");
	fprintf(stderr, "tst_supported_fs fs_type\n");
	fprintf(stderr, "   if fs_type is supported, return 0 otherwise return 1\n\n");

	fprintf(stderr, "tst_supported_fs -s skip_list fs_type\n");
	fprintf(stderr, "   if fs_type is in skip_list, return 1 otherwise return 0\n\n");

	fprintf(stderr, "tst_supported_fs -s skip_list -d path\n");
	fprintf(stderr, "   if filesystem mounted on path is in skip_list, return 1 otherwise return 0\n\n");

	fprintf(stderr, "fs_type - a specified filesystem type\n");
	fprintf(stderr, "skip_list - filesystems to skip, delimiter: '%c'\n",
			SKIP_DELIMITER);
	fprintf(stderr, "path - any valid file or directory\n");
}

static char **parse_skiplist(char *fs)
{
	char **skiplist;
	int i, cnt = 1;

	for (i = 0; fs[i]; i++) {
		if (optarg[i] == SKIP_DELIMITER)
			cnt++;
	}

	skiplist = malloc(++cnt * sizeof(char *));
	if (!skiplist) {
		fprintf(stderr, "malloc() failed\n");
		return NULL;
	}

	for (i = 0; i < cnt; i++)
		skiplist[i] = strtok_r(fs, TST_TO_STR(SKIP_DELIMITER), &fs);

	return skiplist;
}

int main(int argc, char *argv[])
{
	const char *const *filesystems;
	const char *fsname = NULL;
	int i, ret;
	char **skiplist = NULL;

	while ((ret = getopt(argc, argv, "d:hs:"))) {
		if (ret < 0)
			break;

		switch (ret) {
		case '?':
			usage();
			return 2;

		case 'h':
			usage();
			return 0;

		case 's':
			skiplist = parse_skiplist(optarg);
			if (!skiplist)
				return 2;
			break;

		case 'd':
			if (fsname)
				err_exit("Can't specify multiple paths");

			fsname = tst_fs_type_name(tst_fs_type(optarg));
			break;
		}
	}

	if (fsname && !skiplist)
		err_exit("Parameter -d requires skiplist");

	if (argc - optind > 1)
		err_exit("Can't specify multiple fs_type");

	/* fs_type */
	if (optind < argc) {
		if (fsname)
			err_exit("Can't specify fs_type and -d together");

		fsname = argv[optind];
	}

	if (fsname) {
		if (fsname[0] == '\0')
			err_exit("fs_type is empty");

		if (skiplist) {
			if (tst_fs_in_skiplist(fsname, (const char * const*)skiplist))
				fail_exit("%s is skipped", fsname);

			info_exit("%s is not skipped", fsname);
		}

		if (tst_fs_is_supported(fsname) == TST_FS_UNSUPPORTED)
			fail_exit("%s is not supported", fsname);

		info_exit("%s is supported", fsname);
	}

	/* all filesystems */
	filesystems = tst_get_supported_fs_types((const char * const*)skiplist);

	if (!filesystems[0])
		fail_exit("There are no supported filesystems or all skipped");

	for (i = 0; filesystems[i]; i++)
		printf("%s\n", filesystems[i]);

	return 0;
}
