static void run_cmd_and_exit(int i, int argc, char **argv) {
	EUID_ASSERT();

	//*************************************
	// basic arguments
	//*************************************
	if (strcmp(argv[i], "--help") == 0 ||
	    strcmp(argv[i], "-?") == 0) {
		usage();
		exit(0);
	}
	else if (strcmp(argv[i], "--version") == 0) {
		print_version();
		exit(0);
	}
#ifdef HAVE_OVERLAYFS
	else if (strcmp(argv[i], "--overlay-clean") == 0) {
		if (checkcfg(CFG_OVERLAYFS)) {
			if (remove_overlay_directory()) {
				fprintf(stderr, "Error: cannot remove overlay directory\n");
				exit(1);
			}
		}
		else
			exit_err_feature("overlayfs");
		exit(0);
	}
#endif
#ifdef HAVE_X11
	else if (strcmp(argv[i], "--x11") == 0) {
		if (checkcfg(CFG_X11)) {
			x11_start(argc, argv);
			exit(0);
		}
		else
			exit_err_feature("x11");
	}
	else if (strcmp(argv[i], "--x11=xpra") == 0) {
		if (checkcfg(CFG_X11)) {
			x11_start_xpra(argc, argv);
			exit(0);
		}
		else
			exit_err_feature("x11");
	}
	else if (strcmp(argv[i], "--x11=xephyr") == 0) {
		if (checkcfg(CFG_X11)) {
			x11_start_xephyr(argc, argv);
			exit(0);
		}
		else
			exit_err_feature("x11");
	}
	else if (strcmp(argv[i], "--x11=xvfb") == 0) {
		if (checkcfg(CFG_X11)) {
			x11_start_xvfb(argc, argv);
			exit(0);
		}
		else
			exit_err_feature("x11");
	}
#endif
#ifdef HAVE_NETWORK
	else if (strcmp(argv[i], "--nettrace") == 0) {
		if (checkcfg(CFG_NETWORK)) {
			if (getuid() != 0) {
				fprintf(stderr, "Error: --nettrace is only available to root user\n");
				exit(1);
			}
			netfilter_trace(0);
		}
		else
			exit_err_feature("networking");
		exit(0);
	}
	else if (strncmp(argv[i], "--nettrace=", 11) == 0) {
		if (checkcfg(CFG_NETWORK)) {
			if (getuid() != 0) {
				fprintf(stderr, "Error: --nettrace is only available to root user\n");
				exit(1);
			}
			pid_t pid = require_pid(argv[i] + 11);
			netfilter_trace(pid);
		}
		else
			exit_err_feature("networking");
		exit(0);
	}
	else if (strncmp(argv[i], "--bandwidth=", 12) == 0) {
		if (checkcfg(CFG_NETWORK)) {
			logargs(argc, argv);

			// extract the command
			if ((i + 1) == argc) {
				fprintf(stderr, "Error: command expected after --bandwidth option\n");
				exit(1);
			}
			char *cmd = argv[i + 1];
			if (strcmp(cmd, "status") && strcmp(cmd, "clear") && strcmp(cmd, "set")) {
				fprintf(stderr, "Error: invalid --bandwidth command.\nValid commands: set, clear, status.\n");
				exit(1);
			}

			// extract network name
			char *dev = NULL;
			int down = 0;
			int up = 0;
			if (strcmp(cmd, "set") == 0 || strcmp(cmd, "clear") == 0) {
				// extract device name
				if ((i + 2) == argc) {
					fprintf(stderr, "Error: network name expected after --bandwidth %s option\n", cmd);
					exit(1);
				}
				dev = argv[i + 2];

				// check device name
				if (if_nametoindex(dev) == 0) {
					fprintf(stderr, "Error: network device %s not found\n", dev);
					exit(1);
				}

				// extract bandwidth
				if (strcmp(cmd, "set") == 0) {
					if ((i + 4) >= argc) {
						fprintf(stderr, "Error: invalid --bandwidth set command\n");
						exit(1);
					}

					down = atoi(argv[i + 3]);
					if (down < 0) {
						fprintf(stderr, "Error: invalid download speed\n");
						exit(1);
					}
					up = atoi(argv[i + 4]);
					if (up < 0) {
						fprintf(stderr, "Error: invalid upload speed\n");
						exit(1);
					}
				}
			}

			// extract pid or sandbox name
			pid_t pid = require_pid(argv[i] + 12);
			bandwidth_pid(pid, cmd, dev, down, up);
		}
		else
			exit_err_feature("networking");
		exit(0);
	}
	else if (strncmp(argv[i], "--netfilter.print=", 18) == 0) {
		// extract pid or sandbox name
		pid_t pid = require_pid(argv[i] + 18);
		netfilter_print(pid, 0);
		exit(0);
	}
	else if (strncmp(argv[i], "--netfilter6.print=", 19) == 0) {
		// extract pid or sandbox name
		pid_t pid = require_pid(argv[i] + 19);
		netfilter_print(pid, 1);
		exit(0);
	}
#endif
	//*************************************
	// independent commands - the program will exit!
	//*************************************
	else if (strcmp(argv[i], "--debug-syscalls") == 0) {
		if (checkcfg(CFG_SECCOMP)) {
			int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FSECCOMP_MAIN, "debug-syscalls");
			exit(rv);
		}
		else
			exit_err_feature("seccomp");
	}
	else if (strcmp(argv[i], "--debug-syscalls32") == 0) {
		if (checkcfg(CFG_SECCOMP)) {
			int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FSECCOMP_MAIN, "debug-syscalls32");
			exit(rv);
		}
		else
			exit_err_feature("seccomp");
	}
	else if (strcmp(argv[i], "--debug-errnos") == 0) {
		if (checkcfg(CFG_SECCOMP)) {
			int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FSECCOMP_MAIN, "debug-errnos");
			exit(rv);
		}
		else
			exit_err_feature("seccomp");
		exit(0);
	}
	else if (strncmp(argv[i], "--seccomp.print=", 16) == 0) {
		if (checkcfg(CFG_SECCOMP)) {
			// print seccomp filter for a sandbox specified by pid or by name
			pid_t pid = require_pid(argv[i] + 16);
			seccomp_print_filter(pid);
		}
		else
			exit_err_feature("seccomp");
		exit(0);
	}
	else if (strcmp(argv[i], "--debug-protocols") == 0) {
		int rv = sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FSECCOMP_MAIN, "debug-protocols");
		exit(rv);
	}
	else if (strncmp(argv[i], "--protocol.print=", 17) == 0) {
		if (checkcfg(CFG_SECCOMP)) {
			// print seccomp filter for a sandbox specified by pid or by name
			pid_t pid = require_pid(argv[i] + 17);
			protocol_print_filter(pid);
		}
		else
			exit_err_feature("seccomp");
		exit(0);
	}
	else if (strncmp(argv[i], "--profile.print=", 16) == 0) {
		pid_t pid = require_pid(argv[i] + 16);

		// print /run/firejail/profile/<PID> file
		char *fname;
		if (asprintf(&fname, RUN_FIREJAIL_PROFILE_DIR "/%d", pid) == -1)
			errExit("asprintf");
		FILE *fp = fopen(fname, "re");
		if (!fp) {
			fprintf(stderr, "Error: sandbox %s not found\n", argv[i] + 16);
			exit(1);
		}
#define MAXBUF 4096
		char buf[MAXBUF];
		if (fgets(buf, MAXBUF, fp))
			printf("%s", buf);
		fclose(fp);
		exit(0);

	}
	else if (strncmp(argv[i], "--cpu.print=", 12) == 0) {
		// join sandbox by pid or by name
		pid_t pid = require_pid(argv[i] + 12);
		cpu_print_filter(pid);
		exit(0);
	}
	else if (strncmp(argv[i], "--apparmor.print=", 17) == 0) {
		// join sandbox by pid or by name
		pid_t pid = require_pid(argv[i] + 17);
		char *pidstr;
		if (asprintf(&pidstr, "%u", pid) == -1)
			errExit("asprintf");
		sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 3, PATH_FIREMON, "--apparmor", pidstr);
		free(pidstr);
		exit(0);
	}
	else if (strncmp(argv[i], "--caps.print=", 13) == 0) {
		// join sandbox by pid or by name
		pid_t pid = require_pid(argv[i] + 13);
		caps_print_filter(pid);
		exit(0);
	}
	else if (strncmp(argv[i], "--fs.print=", 11) == 0) {
		// join sandbox by pid or by name
		pid_t pid = require_pid(argv[i] + 11);
		fs_logger_print_log(pid);
		exit(0);
	}
	else if (strncmp(argv[i], "--dns.print=", 12) == 0) {
		// join sandbox by pid or by name
		pid_t pid = require_pid(argv[i] + 12);
		net_dns_print(pid);
		exit(0);
	}
	else if (strcmp(argv[i], "--debug-caps") == 0) {
		caps_print();
		exit(0);
	}
	else if (strcmp(argv[i], "--list") == 0) {
		if (pid_hidepid())
			sbox_run(SBOX_ROOT| SBOX_CAPS_HIDEPID | SBOX_SECCOMP, 2, PATH_FIREMON, "--list");
		else
			sbox_run(SBOX_USER| SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--list");
		exit(0);
	}
	else if (strcmp(argv[i], "--tree") == 0) {
		if (pid_hidepid())
			sbox_run(SBOX_ROOT | SBOX_CAPS_HIDEPID | SBOX_SECCOMP, 2, PATH_FIREMON, "--tree");
		else
			sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP, 2, PATH_FIREMON, "--tree");
		exit(0);
	}
	else if (strcmp(argv[i], "--top") == 0) {
		if (pid_hidepid())
			sbox_run(SBOX_ROOT | SBOX_CAPS_HIDEPID | SBOX_SECCOMP | SBOX_ALLOW_STDIN,
				2, PATH_FIREMON, "--top");
		else
			sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP | SBOX_ALLOW_STDIN,
				2, PATH_FIREMON, "--top");
		exit(0);
	}
#ifdef HAVE_NETWORK
	else if (strcmp(argv[i], "--netstats") == 0) {
		if (checkcfg(CFG_NETWORK)) {
			struct stat s;
			if (stat("/proc/sys/kernel/grsecurity", &s) == 0 || pid_hidepid())
				sbox_run(SBOX_ROOT | SBOX_CAPS_HIDEPID | SBOX_SECCOMP | SBOX_ALLOW_STDIN,
					2, PATH_FIREMON, "--netstats");
			else
				sbox_run(SBOX_USER | SBOX_CAPS_NONE | SBOX_SECCOMP | SBOX_ALLOW_STDIN,
					2, PATH_FIREMON, "--netstats");
			exit(0);
		}
		else
			exit_err_feature("networking");
	}
	else if (strncmp(argv[i], "--net.print=", 12) == 0) {
		if (checkcfg(CFG_NETWORK)) {
			// extract pid or sandbox name
			pid_t pid = require_pid(argv[i] + 12);
			net_print(pid);
			exit(0);
		}
		else
			exit_err_feature("networking");
	}
#endif
#ifdef HAVE_FILE_TRANSFER
	else if (strncmp(argv[i], "--get=", 6) == 0) {
		if (checkcfg(CFG_FILE_TRANSFER)) {
			logargs(argc, argv);
			if (arg_private_cwd) {
				fprintf(stderr, "Error: --get and --private-cwd options are mutually exclusive\n");
				exit(1);
			}

			// verify path
			if ((i + 2) != argc) {
				fprintf(stderr, "Error: invalid --get option, path expected\n");
				exit(1);
			}
			char *path = argv[i + 1];
			 invalid_filename(path, 0); // no globbing
			 if (strstr(path, "..")) {
			 	fprintf(stderr, "Error: invalid file name %s\n", path);
			 	exit(1);
			 }

			// get file
			pid_t pid = require_pid(argv[i] + 6);
			sandboxfs(SANDBOX_FS_GET, pid, path, NULL);
			exit(0);
		}
		else
			exit_err_feature("file transfer");
	}
	else if (strncmp(argv[i], "--put=", 6) == 0) {
		if (checkcfg(CFG_FILE_TRANSFER)) {
			logargs(argc, argv);
			if (arg_private_cwd) {
				fprintf(stderr, "Error: --put and --private-cwd options are mutually exclusive\n");
				exit(1);
			}

			// verify path
			if ((i + 3) != argc) {
				fprintf(stderr, "Error: invalid --put option, 2 paths expected\n");
				exit(1);
			}
			char *path1 = argv[i + 1];
			 invalid_filename(path1, 0); // no globbing
			 if (strstr(path1, "..")) {
			 	fprintf(stderr, "Error: invalid file name %s\n", path1);
			 	exit(1);
			 }
			char *path2 = argv[i + 2];
			 invalid_filename(path2, 0); // no globbing
			 if (strstr(path2, "..")) {
			 	fprintf(stderr, "Error: invalid file name %s\n", path2);
			 	exit(1);
			 }

			// get file
			pid_t pid = require_pid(argv[i] + 6);
			sandboxfs(SANDBOX_FS_PUT, pid, path1, path2);
			exit(0);
		}
		else
			exit_err_feature("file transfer");
	}
	else if (strncmp(argv[i], "--ls=", 5) == 0) {
		if (checkcfg(CFG_FILE_TRANSFER)) {
			logargs(argc, argv);
			if (arg_private_cwd) {
				fprintf(stderr, "Error: --ls and --private-cwd options are mutually exclusive\n");
				exit(1);
			}

			// verify path
			if ((i + 2) != argc) {
				fprintf(stderr, "Error: invalid --ls option, path expected\n");
				exit(1);
			}
			char *path = argv[i + 1];
			 invalid_filename(path, 0); // no globbing
			 if (strstr(path, "..")) {
			 	fprintf(stderr, "Error: invalid file name %s\n", path);
			 	exit(1);
			 }

			// list directory contents
			if (!arg_debug)
				 arg_quiet = 1;
			pid_t pid = require_pid(argv[i] + 5);
			sandboxfs(SANDBOX_FS_LS, pid, path, NULL);
			exit(0);
		}
		else
			exit_err_feature("file transfer");
	}
	else if (strncmp(argv[i], "--cat=", 6) == 0) {
		if (checkcfg(CFG_FILE_TRANSFER)) {
			logargs(argc, argv);
			if (arg_private_cwd) {
				fprintf(stderr, "Error: --cat and --private-cwd options are mutually exclusive\n");
				exit(1);
			}

			if ((i + 2) != argc) {
				fprintf(stderr, "Error: invalid --cat option, path expected\n");
				exit(1);
			}
			char *path = argv[i + 1];
			invalid_filename(path, 0); // no globbing
			if (strstr(path, "..")) {
				fprintf(stderr, "Error: invalid file name %s\n", path);
				exit(1);
			}

			// write file contents to stdout
			if (!arg_debug)
				 arg_quiet = 1;
			pid_t pid = require_pid(argv[i] + 6);
			sandboxfs(SANDBOX_FS_CAT, pid, path, NULL);
			exit(0);
		}
		else
			exit_err_feature("file transfer");
	}
#endif
	else if (strncmp(argv[i], "--join=", 7) == 0) {
		if (checkcfg(CFG_JOIN) || getuid() == 0) {
			logargs(argc, argv);

			if (arg_shell_none) {
				if (argc <= (i+1)) {
					fprintf(stderr, "Error: --shell=none set, but no command specified\n");
					exit(1);
				}
				cfg.original_program_index = i + 1;
			}

			if (!cfg.shell && !arg_shell_none)
				cfg.shell = guess_shell();

			// join sandbox by pid or by name
			pid_t pid = require_pid(argv[i] + 7);
			join(pid, argc, argv, i + 1);
			exit(0);
		}
		else
			exit_err_feature("join");

	}
	else if (strncmp(argv[i], "--join-or-start=", 16) == 0) {
		// NOTE: this is first part of option handler,
		// 		 sandbox name is set in other part
		if (checkcfg(CFG_JOIN) || getuid() == 0) {
			logargs(argc, argv);

			if (arg_shell_none) {
				if (argc <= (i+1)) {
					fprintf(stderr, "Error: --shell=none set, but no command specified\n");
					exit(1);
				}
				cfg.original_program_index = i + 1;
			}

			// try to join by name only
			pid_t pid;
			if (!read_pid(argv[i] + 16, &pid)) {
				if (!cfg.shell && !arg_shell_none)
					cfg.shell = guess_shell();

				join(pid, argc, argv, i + 1);
				exit(0);
			}
			// if there no such sandbox continue argument processing
		}
		else
			exit_err_feature("join");
	}
#ifdef HAVE_NETWORK
	else if (strncmp(argv[i], "--join-network=", 15) == 0) {
		if (checkcfg(CFG_NETWORK)) {
			logargs(argc, argv);
			arg_join_network = 1;
			if (getuid() != 0) {
				fprintf(stderr, "Error: --join-network is only available to root user\n");
				exit(1);
			}

			if (!cfg.shell && !arg_shell_none)
				cfg.shell = guess_shell();

			// join sandbox by pid or by name
			pid_t pid = require_pid(argv[i] + 15);
			join(pid, argc, argv, i + 1);
		}
		else
			exit_err_feature("networking");
		exit(0);
	}
#endif
	else if (strncmp(argv[i], "--join-filesystem=", 18) == 0) {
		logargs(argc, argv);
		arg_join_filesystem = 1;
		if (getuid() != 0) {
			fprintf(stderr, "Error: --join-filesystem is only available to root user\n");
			exit(1);
		}

		if (!cfg.shell && !arg_shell_none)
			cfg.shell = guess_shell();

		// join sandbox by pid or by name
		pid_t pid = require_pid(argv[i] + 18);
		join(pid, argc, argv, i + 1);
		exit(0);
	}
	else if (strncmp(argv[i], "--shutdown=", 11) == 0) {
		logargs(argc, argv);

		// shutdown sandbox by pid or by name
		pid_t pid = require_pid(argv[i] + 11);
		shut(pid);
		exit(0);
	}

}