/*!
 * (C) Copyright 2017 Awox SA.  All rights reserved.
 * This work contains confidential trade secrets of Awox.
 * Use, examination, copying, transfer and disclosure to others
 * are prohibited, except with the express written agreement of Awox.
 *
 * virtfs-xattr.c

 * \author	Awox
 * \date 	Jan 25, 2017
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <attr/xattr.h>
#include <errno.h>
#include <endian.h>
#include <fcntl.h>

static void usage(const char* progName)
{
	fprintf(stderr, "%s <file>\tdisplay attributes\n", progName);
	fprintf(stderr,
			"%s { -u <uid> | -g <gid> | -l } <file>\tset/change attribute value (uid, gid, is-symlink)\n",
			progName);
	fprintf(stderr, "%s -l <file>\ttag file as a symlink\n", progName);
	fprintf(stderr, "%s -c <file>\tclear all attributes\n", progName);
}

int main(int argc, char** argv)
{
	int rc;
	uid_t uid;
	int set_uid;
	gid_t gid;
	int set_gid;
	mode_t mode;
	int tag_symlink;
	int clear;
	int display;

	const char* filePath;

	set_uid = 0;
	set_gid = 0;
	tag_symlink = 0;
	clear = 0;
	display = 0;

	while ((rc = getopt(argc, argv, "u:g:lch")) != -1)
	{
		switch (rc)
		{
		case 'u':
			uid = (uid_t) htole32(atoi(optarg));
			set_uid = 1;
			break;
		case 'g':
			gid = (gid_t) htole32(atoi(optarg));
			set_gid = 1;
			break;
		case 'l':
			tag_symlink = 1;
			break;
		case 'c':
			clear = 1;
			break;
		case '?':
			usage(argv[0]);
			return EXIT_FAILURE;
			break;
		case 'h':
			usage(argv[0]);
			return EXIT_SUCCESS;
		}
	}

	if (optind >= argc)
	{
		usage(argv[0]);
		return EXIT_FAILURE;
	}

	filePath = argv[optind];

	if (clear && (set_uid || set_gid || tag_symlink))
	{
		usage(argv[0]);
		return EXIT_FAILURE;
	}

	if (!clear && !set_uid && !set_gid && !tag_symlink)
	{
		display = 1;
	}

	if (set_uid && lsetxattr(filePath, "user.virtfs.uid", &uid, sizeof(uid), 0))
	{
		perror("setxattr(user.virtfs.uid)");
		return EXIT_FAILURE;
	}

	if (set_gid && lsetxattr(filePath, "user.virtfs.gid", &gid, sizeof(gid), 0))
	{
		perror("setxattr(user.virtfs.gid)");
		return EXIT_FAILURE;
	}

	if (tag_symlink)
	{
		mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;

		mode = htole32(mode);

		if (lsetxattr(filePath, "user.virtfs.mode", &mode, sizeof(mode), 0))
		{
			perror("setxattr(user.virtfs.mode)");
			return EXIT_FAILURE;
		}
	}

	if (display)
	{
		if (lgetxattr(filePath, "user.virtfs.uid", &uid, sizeof(uid)) == sizeof(uid))
		{
			printf("uid: %d\n", (int) le32toh(uid));
		}
		if (lgetxattr(filePath, "user.virtfs.gid", &gid, sizeof(gid)) == sizeof(gid))
		{
			printf("gid: %d\n", (int) le32toh(gid));
		}
		if (lgetxattr(filePath, "user.virtfs.mode", &mode, sizeof(mode)) == sizeof(mode))
		{
			mode = le32toh(mode);
			if (mode & S_IFLNK)
				printf("symlink\n");
		}
	}

	if (clear)
	{
		if (lremovexattr(filePath, "user.virtfs.uid") && errno != ENOATTR)
		{
			perror("removexattr(user.virtfs.uid)");
			return EXIT_FAILURE;
		}
		if (lremovexattr(filePath, "user.virtfs.gid") && errno != ENOATTR)
		{
			perror("removexattr(user.virtfs.gid)");
			return EXIT_FAILURE;
		}
	}

	return EXIT_SUCCESS;
}
