OSDN Git Service

gpet 0.2 pre
[gpet/origin.git] / src / usr_sbin / editpolicy.c
index cb555cd..d264562 100644 (file)
@@ -3,9 +3,9 @@
  *
  * TOMOYO Linux's utilities.
  *
- * Copyright (C) 2005-2010  NTT DATA CORPORATION
+ * Copyright (C) 2005-2011  NTT DATA CORPORATION
  *
- * Version: 1.8.0   2010/11/11
+ * Version: 1.8.1   2011/04/01
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License v2 as published by the
        static char *gpet_line = NULL;
 #endif /* __GPET */
 
-/* Variables */
+/* Domain policy. */
+struct ccs_domain_policy ccs_dp = { };
 
-extern int ccs_persistent_fd;
+/* Readline history. */
+static struct ccs_readline_data ccs_rl = { };
 
+/* File descriptor for offline mode. */
+int ccs_persistent_fd = EOF;
+
+/* Array of "path_group" entries. */
 struct ccs_path_group_entry *ccs_path_group_list = NULL;
+/* Length of ccs_path_group_list array. */
 int ccs_path_group_list_len = 0;
-struct ccs_generic_acl *ccs_generic_acl_list = NULL;
-int ccs_generic_acl_list_count = 0;
+/* Array of string ACL entries. */
+struct ccs_generic_acl *ccs_gacl_list = NULL;
+/* Length of ccs_generic_list array. */
+int ccs_gacl_list_count = 0;
 
+/* Policy directory. */
 static const char *ccs_policy_dir = NULL;
+/* Use ccs-editpolicy-agent program? */
 static _Bool ccs_offline_mode = false;
+/* Use readonly mode? */
 static _Bool ccs_readonly_mode = false;
+/* Refresh interval in second. 0 means no auto refresh. */
 static unsigned int ccs_refresh_interval = 0;
+/* Need to reload the screen due to auto refresh? */
 static _Bool ccs_need_reload = false;
+/* Policy file's name. */
 static const char *ccs_policy_file = NULL;
+/* Caption of the current screen. */
 static const char *ccs_list_caption = NULL;
+/* Currently selected domain. */
 static char *ccs_current_domain = NULL;
+/* Currently selected PID. */
 static unsigned int ccs_current_pid = 0;
-static int ccs_current_screen = CCS_SCREEN_DOMAIN_LIST;
+/* Currently active screen's index. */
+enum ccs_screen_type ccs_current_screen = CCS_SCREEN_DOMAIN_LIST;
+/*
+ * Array of "initialize_domain"/"no_initialize_domain"/"keep_domain"/
+ * "no_keep_domain" entries.
+ */
 static struct ccs_transition_control_entry *ccs_transition_control_list = NULL;
+/* Length of ccs_transition_control_list array. */
 static int ccs_transition_control_list_len = 0;
-static int ccs_profile_sort_type = 0;
+/* Sort profiles by value? */
+static _Bool ccs_profile_sort_type = false;
+/* Number of domain initializer source domains. */
 static int ccs_unnumbered_domain_count = 0;
+/* Width of CUI screen. */
 static int ccs_window_width = 0;
+/* Height of CUI screen. */
 static int ccs_window_height = 0;
-static int ccs_current_item_index[CCS_MAXSCREEN];
-int ccs_current_y[CCS_MAXSCREEN];
-int ccs_list_item_count[CCS_MAXSCREEN];
+/* Cursor info for CUI screen. */
+struct ccs_screen ccs_screen[CCS_MAXSCREEN] = { };
+/* Number of entries available on current screen. */
+int ccs_list_item_count = 0;
+/* Lines available for displaying ACL entries.  */
 static int ccs_body_lines = 0;
-static int ccs_max_eat_col[CCS_MAXSCREEN];
+/* Columns to shift. */
 static int ccs_eat_col = 0;
+/* Max columns. */
 static int ccs_max_col = 0;
-static int ccs_list_indent = 0;
-static int ccs_acl_sort_type = 0;
+/* Sort ACL by operand first? */
+static _Bool ccs_acl_sort_type = false;
+/* Last error message. */
 static char *ccs_last_error = NULL;
+/* Domain screen is dealing with process list rather than domain list? */
+static _Bool ccs_domain_sort_type = false;
+/* Start from the first line when showing ACL screen? */
+static _Bool ccs_no_restore_cursor = false;
 
-/* Prototypes */
+/* Domain transition coltrol keywords. */
+static const char *ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = {
+       [CCS_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ",
+       [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
+       [CCS_TRANSITION_CONTROL_KEEP] = "keep_domain ",
+       [CCS_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ",
+};
 
-static void ccs_sigalrm_handler(int sig);
-static const char *ccs_get_last_name(const struct ccs_domain_policy *dp, const int index);
-static _Bool ccs_keeper_domain(struct ccs_domain_policy *dp, const int index);
-static _Bool ccs_initializer_source(struct ccs_domain_policy *dp, const int index);
-static _Bool ccs_initializer_target(struct ccs_domain_policy *dp, const int index);
-static _Bool ccs_domain_unreachable(struct ccs_domain_policy *dp, const int index);
-static _Bool ccs_deleted_domain(struct ccs_domain_policy *dp, const int index);
-static const struct ccs_transition_control_entry *ccs_transition_control(const struct ccs_path_info *domainname, const char *program);
-static int ccs_generic_acl_compare(const void *a, const void *b);
-static int ccs_generic_acl_compare0(const void *a, const void *b);
-static int ccs_string_acl_compare(const void *a, const void *b);
-static int ccs_profile_entry_compare(const void *a, const void *b);
-static void ccs_read_generic_policy(void);
-static int ccs_add_transition_control_entry(const char *domainname, const char *program, const u8 type);
-static int ccs_add_transition_control_policy(char *data, const u8 type);
-static int ccs_add_path_group_entry(const char *group_name, const char *member_name, const _Bool is_delete);
+static FILE *ccs_editpolicy_open_write(const char *filename);
+static _Bool ccs_deleted_domain(const int index);
+static _Bool ccs_domain_unreachable(const int index);
+static _Bool ccs_initializer_source(const int index);
+static _Bool ccs_initializer_target(const int index);
+static _Bool ccs_keeper_domain(const int index);
+static _Bool ccs_select_item(const int index);
+static _Bool ccs_show_command_key(const enum ccs_screen_type screen,
+                                 const _Bool readonly);
+static const char *ccs_eat(const char *str);
+static const char *ccs_get_last_name(const int index);
+static const struct ccs_transition_control_entry *ccs_transition_control
+(const struct ccs_path_info *domainname, const char *program);
+static enum ccs_screen_type ccs_generic_list_loop(void);
+static enum ccs_screen_type ccs_select_window(const int current);
+static int ccs_add_path_group_entry(const char *group_name,
+                                   const char *member_name,
+                                   const _Bool is_delete);
 static int ccs_add_path_group_policy(char *data, const _Bool is_delete);
-static void ccs_assign_dis(struct ccs_domain_policy *dp, const struct ccs_path_info *domainname, const char *program);
+static int ccs_add_transition_control_entry(const char *domainname,
+                                           const char *program, const enum
+                                           ccs_transition_type type);
+static int ccs_add_transition_control_policy(char *data, const enum
+                                            ccs_transition_type type);
+static int ccs_count(const unsigned char *array, const int len);
+static int ccs_count2(const struct ccs_generic_acl *array, int len);
 static int ccs_domainname_attribute_compare(const void *a, const void *b);
-static void ccs_read_domain_and_exception_policy(struct ccs_domain_policy *dp);
-static void ccs_show_current(struct ccs_domain_policy *dp);
-static const char *ccs_eat(const char *str);
-static int ccs_show_domain_line(struct ccs_domain_policy *dp, const int index);
+static int ccs_gacl_compare(const void *a, const void *b);
+static int ccs_gacl_compare0(const void *a, const void *b);
+static int ccs_profile_entry_compare(const void *a, const void *b);
 static int ccs_show_acl_line(const int index, const int list_indent);
-static int ccs_show_profile_line(const int index);
+static int ccs_show_domain_line(const int index);
 static int ccs_show_literal_line(const int index);
-static int ccs_show_meminfo_line(const int index);
-static void ccs_show_list(struct ccs_domain_policy *dp);
-static void ccs_resize_window(void);
-static void ccs_up_arrow_key(struct ccs_domain_policy *dp);
-static void ccs_down_arrow_key(struct ccs_domain_policy *dp);
-static void ccs_page_up_key(struct ccs_domain_policy *dp);
-static void ccs_page_down_key(struct ccs_domain_policy *dp);
+static int ccs_show_profile_line(const int index);
+static int ccs_show_stat_line(const int index);
+static int ccs_string_acl_compare(const void *a, const void *b);
+static void ccs_add_entry(void);
 static void ccs_adjust_cursor_pos(const int item_count);
-static void ccs_set_cursor_pos(const int index);
-static int ccs_count(const unsigned char *array, const int len);
-static int ccs_count2(const struct ccs_generic_acl *array, int len);
-static _Bool ccs_select_item(struct ccs_domain_policy *dp, const int index);
-static int ccs_generic_acl_compare(const void *a, const void *b);
-static void ccs_delete_entry(struct ccs_domain_policy *dp, const int index);
-static void ccs_add_entry(struct ccs_readline_data *rl);
-static void ccs_find_entry(struct ccs_domain_policy *dp, _Bool input, _Bool forward, const int current, struct ccs_readline_data *rl);
-static void ccs_set_profile(struct ccs_domain_policy *dp, const int current);
-static void ccs_set_level(struct ccs_domain_policy *dp, const int current);
-static void ccs_set_quota(struct ccs_domain_policy *dp, const int current);
-static int ccs_select_window(struct ccs_domain_policy *dp, const int current);
-static _Bool ccs_show_command_key(const int screen, const _Bool readonly);
-static int ccs_generic_list_loop(struct ccs_domain_policy *dp);
+static void ccs_assign_dis(const struct ccs_path_info *domainname,
+                          const char *program);
 static void ccs_copy_file(const char *source, const char *dest);
-static FILE *ccs_editpolicy_open_write(const char *filename);
-
-/* Utility Functions */
+static void ccs_delete_entry(const int index);
+static void ccs_down_arrow_key(void);
+static void ccs_find_entry(const _Bool input, const _Bool forward,
+                          const int current);
+static void ccs_page_down_key(void);
+static void ccs_page_up_key(void);
+static void ccs_read_domain_and_exception_policy(void);
+static void ccs_read_generic_policy(void);
+static void ccs_resize_window(void);
+static void ccs_set_cursor_pos(const int index);
+static void ccs_set_level(const int current);
+static void ccs_set_profile(const int current);
+static void ccs_set_quota(const int current);
+static void ccs_show_current(void);
+static void ccs_show_list(void);
+static void ccs_sigalrm_handler(int sig);
+static void ccs_up_arrow_key(void);
 
+/**
+ * ccs_copy_file - Copy local file to local or remote file.
+ *
+ * @source: Local file.
+ * @dest:   Local or remote file name.
+ *
+ * Returns nothing.
+ */
 static void ccs_copy_file(const char *source, const char *dest)
 {
        FILE *fp_in = fopen(source, "r");
@@ -135,16 +191,30 @@ static void ccs_copy_file(const char *source, const char *dest)
                fclose(fp_in);
 }
 
-static const char *ccs_get_last_name(const struct ccs_domain_policy *dp,
-                                    const int index)
+/**
+ * ccs_get_last_name - Get last component of a domainname.
+ *
+ * @index: Index in the domain policy.
+ *
+ * Returns the last componet of the domainname.
+ */
+static const char *ccs_get_last_name(const int index)
 {
-       const char *cp0 = ccs_domain_name(dp, index);
+       const char *cp0 = ccs_domain_name(&ccs_dp, index);
        const char *cp1 = strrchr(cp0, ' ');
        if (cp1)
                return cp1 + 1;
        return cp0;
 }
 
+/**
+ * ccs_count - Count non-zero elements in an array.
+ *
+ * @array: Pointer to "const unsigned char".
+ * @len:   Length of @array array.
+ *
+ * Returns number of non-zero elements.
+ */
 static int ccs_count(const unsigned char *array, const int len)
 {
        int i;
@@ -155,6 +225,14 @@ static int ccs_count(const unsigned char *array, const int len)
        return c;
 }
 
+/**
+ * ccs_count2 - Count non-zero elements in a "struct ccs_generic_acl" array.
+ *
+ * @array: Pointer to "const struct ccs_generic_acl".
+ * @len:   Length of @array array.
+ *
+ * Returns number of non-zero elements.
+ */
 static int ccs_count2(const struct ccs_generic_acl *array, int len)
 {
        int i;
@@ -165,6 +243,14 @@ static int ccs_count2(const struct ccs_generic_acl *array, int len)
        return c;
 }
 
+/**
+ * ccs_count3 - Count non-zero elements in a "struct ccs_task_entry" array.
+ *
+ * @array: Pointer to "const struct ccs_task_entry".
+ * @len:   Length of @array array.
+ *
+ * Returns number of non-zero elements.
+ */
 static int ccs_count3(const struct ccs_task_entry *array, int len)
 {
        int i;
@@ -175,32 +261,82 @@ static int ccs_count3(const struct ccs_task_entry *array, int len)
        return c;
 }
 
-static _Bool ccs_keeper_domain(struct ccs_domain_policy *dp, const int index)
+/**
+ * ccs_keeper_domain - Check whether the given domain is marked as "keep_domain".
+ *
+ * @index: Index in the domain policy.
+ *
+ * Returns true if the given domain is marked as "keep_domain",
+ * false otherwise.
+ */
+static _Bool ccs_keeper_domain(const int index)
 {
-       return dp->list[index].is_dk;
+       return ccs_dp.list[index].is_dk;
 }
 
-static _Bool ccs_initializer_source(struct ccs_domain_policy *dp, const int index)
+/**
+ * ccs_initializer_source - Check whether the given domain is marked as "initialize_domain".
+ *
+ * @index: Index in the domain policy.
+ *
+ * Returns true if the given domain is marked as "initialize_domain",
+ * false otherwise.
+ */
+static _Bool ccs_initializer_source(const int index)
 {
-       return dp->list[index].is_dis;
+       return ccs_dp.list[index].is_dis;
 }
 
-static _Bool ccs_initializer_target(struct ccs_domain_policy *dp, const int index)
+/**
+ * ccs_initializer_target - Check whether the given domain is a target of "initialize_domain".
+ *
+ * @index: Index in the domain policy.
+ *
+ * Returns true if the given domain is a target of "initialize_domain",
+ * false otherwise.
+ */
+static _Bool ccs_initializer_target(const int index)
 {
-       return dp->list[index].is_dit;
+       return ccs_dp.list[index].is_dit;
 }
 
-static _Bool ccs_domain_unreachable(struct ccs_domain_policy *dp, const int index)
+/**
+ * ccs_domain_unreachable - Check whether the given domain is unreachable or not.
+ *
+ * @index: Index in the domain policy.
+ *
+ * Returns true if the given domain is unreachable, false otherwise.
+ *
+ * TODO: Check "task auto_domain_transition" and
+ * "task manual_domain_transition" which allow other domains to reach
+ * the given domain.
+ */
+static _Bool ccs_domain_unreachable(const int index)
 {
-       return dp->list[index].is_du;
+       return ccs_dp.list[index].is_du;
 }
 
-static _Bool ccs_deleted_domain(struct ccs_domain_policy *dp, const int index)
+/**
+ * ccs_deleted_domain - Check whether the given domain is marked as deleted or not.
+ *
+ * @index: Index in the domain policy.
+ *
+ * Returns true if the given domain is marked as deleted, false otherwise.
+ */
+static _Bool ccs_deleted_domain(const int index)
 {
-       return dp->list[index].is_dd;
+       return ccs_dp.list[index].is_dd;
 }
 
-static int ccs_generic_acl_compare0(const void *a, const void *b)
+/**
+ * ccs_gacl_compare0 - strcmp() for qsort() callback.
+ *
+ * @a: Pointer to "void".
+ * @b: Pointer to "void".
+ *
+ * Returns return value of strcmp().
+ */
+static int ccs_gacl_compare0(const void *a, const void *b)
 {
        const struct ccs_generic_acl *a0 = (struct ccs_generic_acl *) a;
        const struct ccs_generic_acl *b0 = (struct ccs_generic_acl *) b;
@@ -214,6 +350,14 @@ static int ccs_generic_acl_compare0(const void *a, const void *b)
        return strcmp(a2, b2);
 }
 
+/**
+ * ccs_string_acl_compare - strcmp() for qsort() callback.
+ *
+ * @a: Pointer to "void".
+ * @b: Pointer to "void".
+ *
+ * Returns return value of strcmp().
+ */
 static int ccs_string_acl_compare(const void *a, const void *b)
 {
        const struct ccs_generic_acl *a0 = (struct ccs_generic_acl *) a;
@@ -223,7 +367,16 @@ static int ccs_string_acl_compare(const void *a, const void *b)
        return strcmp(a1, b1);
 }
 
-static int ccs_add_transition_control_policy(char *data, const u8 type)
+/**
+ * ccs_add_transition_control_policy - Add "initialize_domain"/"no_initialize_domain"/"keep_domain"/ "no_keep_domain" entries.
+ *
+ * @data: Line to parse.
+ * @type: One of values in "enum ccs_transition_type".
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int ccs_add_transition_control_policy
+(char *data, const enum ccs_transition_type type)
 {
        char *domainname = strstr(data, " from ");
        if (domainname) {
@@ -237,6 +390,14 @@ static int ccs_add_transition_control_policy(char *data, const u8 type)
        return ccs_add_transition_control_entry(domainname, data, type);
 }
 
+/**
+ * ccs_add_path_group_policy - Add "path_group" entry.
+ *
+ * @data:      Line to parse.
+ * @is_delete: True if it is delete request, false otherwise.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
 static int ccs_add_path_group_policy(char *data, const _Bool is_delete)
 {
        char *cp = strchr(data, ' ');
@@ -246,8 +407,13 @@ static int ccs_add_path_group_policy(char *data, const _Bool is_delete)
        return ccs_add_path_group_entry(data, cp, is_delete);
 }
 
-static void ccs_assign_dis(struct ccs_domain_policy *dp,
-                          const struct ccs_path_info *domainname,
+/**
+ * ccs_assign_dis - Assign domain initializer source domain.
+ *
+ * @domainname: Pointer to "const struct ccs_path_info".
+ * @program:    Program name.
+ */
+static void ccs_assign_dis(const struct ccs_path_info *domainname,
                           const char *program)
 {
        const struct ccs_transition_control_entry *d_t =
@@ -258,17 +424,25 @@ static void ccs_assign_dis(struct ccs_domain_policy *dp,
                ccs_get();
                line = ccs_shprintf("%s %s", domainname->name, program);
                ccs_normalize_line(line);
-               source = ccs_assign_domain(dp, line, true, false);
+               source = ccs_assign_domain(&ccs_dp, line, true, false);
                if (source == EOF)
                        ccs_out_of_memory();
                line = ccs_shprintf(CCS_ROOT_NAME " %s", program);
-               dp->list[source].target_domainname = strdup(line);
-               if (!dp->list[source].target_domainname)
+               ccs_dp.list[source].target_domainname = strdup(line);
+               if (!ccs_dp.list[source].target_domainname)
                        ccs_out_of_memory();
                ccs_put();
        }
 }
 
+/**
+ * ccs_domainname_attribute_compare - strcmp() for qsort() callback.
+ *
+ * @a: Pointer to "void".
+ * @b: Pointer to "void".
+ *
+ * Returns return value of strcmp().
+ */
 static int ccs_domainname_attribute_compare(const void *a, const void *b)
 {
        const struct ccs_domain_info *a0 = a;
@@ -279,41 +453,50 @@ static int ccs_domainname_attribute_compare(const void *a, const void *b)
        return k;
 }
 
-static const char *ccs_transition_type[CCS_MAX_TRANSITION_TYPE] = {
-       [CCS_TRANSITION_CONTROL_INITIALIZE] = "initialize_domain ",
-       [CCS_TRANSITION_CONTROL_NO_INITIALIZE] = "no_initialize_domain ",
-       [CCS_TRANSITION_CONTROL_KEEP] = "keep_domain ",
-       [CCS_TRANSITION_CONTROL_NO_KEEP] = "no_keep_domain ",
-};
-
-static int ccs_find_target_domain(struct ccs_domain_policy *dp, const int index)
+/**
+ * ccs_find_target_domain - Find the initialize_domain target domain.
+ *
+ * @index: Index in the domain policy.
+ *
+ * Returns index in the domain policy if found, EOF otherwise.
+ */
+static int ccs_find_target_domain(const int index)
 {
-       return ccs_find_domain(dp, dp->list[index].target_domainname, false, false);
+       return ccs_find_domain(&ccs_dp, ccs_dp.list[index].target_domainname,
+                              false, false);
 }
 
-static int ccs_show_domain_line(struct ccs_domain_policy *dp, const int index)
+/**
+ * ccs_show_domain_line - Show a line of the domain transition tree.
+ *
+ * @index: Index in the domain policy.
+ *
+ * Returns length of the printed line.
+ */
+static int ccs_show_domain_line(const int index)
 {
        int tmp_col = 0;
        const struct ccs_transition_control_entry *transition_control;
        char *line;
        const char *sp;
-       const int number = dp->list[index].number;
+       const int number = ccs_dp.list[index].number;
        int redirect_index;
-       const bool is_dis = ccs_initializer_source(dp, index);
-       const bool is_deleted = ccs_deleted_domain(dp, index);
+       const bool is_dis = ccs_initializer_source(index);
+       const bool is_deleted = ccs_deleted_domain(index);
        if (number >= 0) {
-               printw("%c%4d:", dp->list_selected[index] ? '&' : ' ', number);
-               if (dp->list[index].profile_assigned)
-                       printw("%3u", dp->list[index].profile);
+               printw("%c%4d:", ccs_dp.list_selected[index] ? '&' : ' ',
+                      number);
+               if (ccs_dp.list[index].profile_assigned)
+                       printw("%3u", ccs_dp.list[index].profile);
                else
                        printw("???");
-               printw(" %c%c%c ", ccs_keeper_domain(dp, index) ? '#' : ' ',
-                      ccs_initializer_target(dp, index) ? '*' : ' ',
-                      ccs_domain_unreachable(dp, index) ? '!' : ' ');
+               printw(" %c%c%c ", ccs_keeper_domain(index) ? '#' : ' ',
+                      ccs_initializer_target(index) ? '*' : ' ',
+                      ccs_domain_unreachable(index) ? '!' : ' ');
        } else
                printw("              ");
        tmp_col += 14;
-       sp = ccs_domain_name(dp, index);
+       sp = ccs_domain_name(&ccs_dp, index);
        while (true) {
                const char *cp = strchr(sp, ' ');
                if (!cp)
@@ -332,7 +515,7 @@ static int ccs_show_domain_line(struct ccs_domain_policy *dp, const int index)
                printw("%s", ccs_eat(" )"));
                tmp_col += 2;
        }
-       transition_control = dp->list[index].d_t;
+       transition_control = ccs_dp.list[index].d_t;
        if (!transition_control || is_dis)
                goto no_transition_control;
        ccs_get();
@@ -350,9 +533,10 @@ no_transition_control:
        if (!is_dis)
                goto done;
        ccs_get();
-       redirect_index = ccs_find_target_domain(dp, index);
+       redirect_index = ccs_find_target_domain(index);
        if (redirect_index >= 0)
-               line = ccs_shprintf(" ( -> %d )", dp->list[redirect_index].number);
+               line = ccs_shprintf(" ( -> %d )",
+                                   ccs_dp.list[redirect_index].number);
        else
                line = ccs_shprintf(" ( -> Not Found )");
        printw("%s", ccs_eat(line));
@@ -362,14 +546,23 @@ done:
        return tmp_col;
 }
 
+/**
+ * ccs_show_acl_line - Print an ACL line.
+ *
+ * @index:       Index in the generic list.
+ * @list_indent: Indent size.
+ *
+ * Returns length of the printed line.
+ */
 static int ccs_show_acl_line(const int index, const int list_indent)
 {
-       u16 directive = ccs_generic_acl_list[index].directive;
+       const enum ccs_editpolicy_directives directive =
+               ccs_gacl_list[index].directive;
        const char *cp1 = ccs_directives[directive].alias;
-       const char *cp2 = ccs_generic_acl_list[index].operand;
+       const char *cp2 = ccs_gacl_list[index].operand;
        int len = list_indent - ccs_directives[directive].alias_len;
        printw("%c%4d: %s ",
-              ccs_generic_acl_list[index].selected ? '&' : ' ',
+              ccs_gacl_list[index].selected ? '&' : ' ',
               index, ccs_eat(cp1));
        while (len-- > 0)
                printw("%s", ccs_eat(" "));
@@ -377,58 +570,55 @@ static int ccs_show_acl_line(const int index, const int list_indent)
        return strlen(cp1) + strlen(cp2) + 8 + list_indent;
 }
 
+/**
+ * ccs_show_profile_line - Print a profile line.
+ *
+ * @index: Index in the generic list.
+ *
+ * Returns length of the printed line.
+ */
 static int ccs_show_profile_line(const int index)
 {
-       const char *cp = ccs_generic_acl_list[index].operand;
-       const u16 profile = ccs_generic_acl_list[index].directive;
+       const char *cp = ccs_gacl_list[index].operand;
+       const u16 profile = ccs_gacl_list[index].directive;
        char number[8] = "";
        if (profile <= 256)
                snprintf(number, sizeof(number) - 1, "%3u-", profile);
-       printw("%c%4d: %s", ccs_generic_acl_list[index].selected ? '&' : ' ',
+       printw("%c%4d: %s", ccs_gacl_list[index].selected ? '&' : ' ',
               index, ccs_eat(number));
        printw("%s ", ccs_eat(cp));
        return strlen(number) + strlen(cp) + 8;
 }
 
+/**
+ * ccs_show_literal_line - Print a literal line.
+ *
+ * @index: Index in the generic list.
+ *
+ * Returns length of the printed line.
+ */
 static int ccs_show_literal_line(const int index)
 {
-       const char *cp = ccs_generic_acl_list[index].operand;
+       const char *cp = ccs_gacl_list[index].operand;
        printw("%c%4d: %s ",
-              ccs_generic_acl_list[index].selected ? '&' : ' ',
+              ccs_gacl_list[index].selected ? '&' : ' ',
               index, ccs_eat(cp));
        return strlen(cp) + 8;
 }
 
-static int ccs_show_meminfo_line(const int index)
+/**
+ * ccs_show_stat_line - Print a statistics line.
+ *
+ * @index: Index in the generic list.
+ *
+ * Returns length of the printed line.
+ */
+static int ccs_show_stat_line(const int index)
 {
        char *line;
-       unsigned int now = 0;
-       unsigned int quota = -1;
-       const char *data = ccs_generic_acl_list[index].operand;
+       unsigned int now;
        ccs_get();
-       if (sscanf(data, "Policy: %u (Quota: %u)", &now, &quota) >= 1)
-               line = ccs_shprintf("Memory used for policy      = %10u bytes   "
-                                   "(Quota: %10u bytes)", now, quota);
-       else if (sscanf(data, "Audit logs: %u (Quota: %u)", &now, &quota) >= 1)
-               line = ccs_shprintf("Memory used for audit logs  = %10u bytes   "
-                                   "(Quota: %10u bytes)", now, quota);
-       else if (sscanf(data, "Query lists: %u (Quota: %u)", &now, &quota) >= 1)
-               line = ccs_shprintf("Memory used for query lists = %10u bytes   "
-                                   "(Quota: %10u bytes)", now, quota);
-       else if (sscanf(data, "Total: %u", &now) == 1)
-               line = ccs_shprintf("Total memory in use         = %10u bytes",
-                                   now);
-       else if (sscanf(data, "Shared: %u (Quota: %u)", &now, &quota) >= 1)
-               line = ccs_shprintf("Memory for string data      = %10u bytes    "
-                                   "Quota = %10u bytes", now, quota);
-       else if (sscanf(data, "Private: %u (Quota: %u)", &now, &quota) >= 1)
-               line = ccs_shprintf("Memory for numeric data     = %10u bytes    "
-                                   "Quota = %10u bytes", now, quota);
-       else if (sscanf(data, "Dynamic: %u (Quota: %u)", &now, &quota) >= 1)
-               line = ccs_shprintf("Memory for temporary data   = %10u bytes    "
-                                   "Quota = %10u bytes", now, quota);
-       else
-               line = ccs_shprintf("%s", data);
+       line = ccs_shprintf("%s", ccs_gacl_list[index].operand);
        if (line[0])
                printw("%s", ccs_eat(line));
        now = strlen(line);
@@ -436,9 +626,16 @@ static int ccs_show_meminfo_line(const int index)
        return now;
 }
 
-static int ccs_domain_sort_type = 0;
-
-static _Bool ccs_show_command_key(const int screen, const _Bool readonly)
+/**
+ * ccs_show_command_key - Print help screen.
+ *
+ * @screen:   Currently selected screen.
+ * @readonly: True if readonly_mopde, false otherwise.
+ *
+ * Returns true to continue, false to quit.
+ */
+static _Bool ccs_show_command_key(const enum ccs_screen_type screen,
+                                 const _Bool readonly)
 {
        int c;
        clear();
@@ -446,7 +643,7 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly)
        printw("Q/q        Quit this editor.\n");
        printw("R/r        Refresh to the latest information.\n");
        switch (screen) {
-       case CCS_SCREEN_MEMINFO_LIST:
+       case CCS_SCREEN_STAT_LIST:
                break;
        default:
                printw("F/f        Find first.\n");
@@ -456,7 +653,7 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly)
        printw("W/w        Switch to selected screen.\n");
        /* printw("Tab        Switch to next screen.\n"); */
        switch (screen) {
-       case CCS_SCREEN_MEMINFO_LIST:
+       case CCS_SCREEN_STAT_LIST:
                break;
        default:
                printw("Insert     Copy an entry at the cursor position to "
@@ -485,7 +682,7 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly)
                               "cursor position.\n");
                }
                break;
-       case CCS_SCREEN_MEMINFO_LIST:
+       case CCS_SCREEN_STAT_LIST:
                if (!readonly)
                        printw("S/s        Set memory quota of selected "
                               "items.\n");
@@ -494,6 +691,8 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly)
                if (!readonly)
                        printw("S/s        Set mode of selected items.\n");
                break;
+       default:
+               break;
        }
        switch (screen) {
        case CCS_SCREEN_EXCEPTION_LIST:
@@ -503,11 +702,15 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly)
                        printw("A/a        Add a new entry.\n");
                        printw("D/d        Delete selected entries.\n");
                }
+       default:
+               break;
        }
        switch (screen) {
        case CCS_SCREEN_PROFILE_LIST:
                if (!readonly)
                        printw("A/a        Define a new profile.\n");
+       default:
+               break;
        }
        switch (screen) {
        case CCS_SCREEN_ACL_LIST:
@@ -520,6 +723,8 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly)
        case CCS_SCREEN_DOMAIN_LIST:
                if (!ccs_offline_mode)
                        printw("@          Switch domain/process list.\n");
+       default:
+               break;
        }
        printw("Arrow-keys and PageUp/PageDown/Home/End keys "
               "for scroll.\n\n");
@@ -535,18 +740,13 @@ static _Bool ccs_show_command_key(const int screen, const _Bool readonly)
        return true;
 }
 
-/* Main Functions */
-
-static void ccs_close_write(FILE *fp)
-{
-       if (ccs_network_mode) {
-               fputc(0, fp);
-               fflush(fp);
-               fgetc(fp);
-       }
-       fclose(fp);
-}
-
+/**
+ * ccs_set_error - Set error line's caption.
+ *
+ * @filename: Filename to print. Maybe NULL.
+ *
+ * Returns nothing.
+ */
 static void ccs_set_error(const char *filename)
 {
        if (filename) {
@@ -562,6 +762,45 @@ static void ccs_set_error(const char *filename)
        }
 }
 
+/**
+ * ccs_send_fd - Send file descriptor.
+ *
+ * @data: String data to send with file descriptor.
+ * @fd:   Pointer to file desciptor.
+ *
+ * Returns nothing.
+ */
+static void ccs_send_fd(char *data, int *fd)
+{
+       struct msghdr msg;
+       struct iovec iov = { data, strlen(data) };
+       char cmsg_buf[CMSG_SPACE(sizeof(int))];
+       struct cmsghdr *cmsg = (struct cmsghdr *) cmsg_buf;
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_control = cmsg_buf;
+       msg.msg_controllen = sizeof(cmsg_buf);
+       cmsg->cmsg_level = SOL_SOCKET;
+       cmsg->cmsg_type = SCM_RIGHTS;
+       cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+       msg.msg_controllen = cmsg->cmsg_len;
+       memmove(CMSG_DATA(cmsg), fd, sizeof(int));
+       sendmsg(ccs_persistent_fd, &msg, 0);
+       close(*fd);
+}
+
+/**
+ * ccs_editpolicy_open_write - Wrapper for ccs_open_write().
+ *
+ * @filename: File to open for writing.
+ *
+ * Returns pointer to "FILE" on success, NULL otherwise.
+ *
+ * Since CUI policy editor screen provides a line for printing error message,
+ * this function sets error line if failed. Also, this function returns NULL if
+ * readonly mode.
+ */
 static FILE *ccs_editpolicy_open_write(const char *filename)
 {
        if (ccs_network_mode) {
@@ -597,6 +836,16 @@ out:
        }
 }
 
+/**
+ * ccs_editpolicy_open_read - Wrapper for ccs_open_read().
+ *
+ * @filename: File to open for reading.
+ *
+ * Returns pointer to "FILE" on success, NULL otherwise.
+ *
+ * Since CUI policy editor screen provides a line for printing error message,
+ * this function sets error line if failed.
+ */
 static FILE *ccs_editpolicy_open_read(const char *filename)
 {
        if (ccs_network_mode) {
@@ -627,6 +876,17 @@ out:
        }
 }
 
+/**
+ * ccs_open2 - Wrapper for open().
+ *
+ * @filename: File to open.
+ * @mode:     Flags to passed to open().
+ *
+ * Returns file descriptor on success, EOF otherwise.
+ *
+ * Since CUI policy editor screen provides a line for printing error message,
+ * this function sets error line if failed.
+ */
 static int ccs_open2(const char *filename, int mode)
 {
        const int fd = open(filename, mode);
@@ -635,12 +895,29 @@ static int ccs_open2(const char *filename, int mode)
        return fd;
 }
 
+/**
+ * ccs_sigalrm_handler - Callback routine for timer interrupt.
+ *
+ * @sig: Signal number. Not used.
+ *
+ * Returns nothing.
+ *
+ * This function is called when ccs_refresh_interval is non-zero. This function
+ * marks current screen to reload. Also, this function reenables timer event.
+ */
 static void ccs_sigalrm_handler(int sig)
 {
        ccs_need_reload = true;
        alarm(ccs_refresh_interval);
 }
 
+/**
+ * ccs_eat - Shift string data before displaying.
+ *
+ * @str: String to be displayed.
+ *
+ * Returns shifted string.
+ */
 static const char *ccs_eat(const char *str)
 {
        while (*str && ccs_eat_col) {
@@ -650,6 +927,15 @@ static const char *ccs_eat(const char *str)
        return str;
 }
 
+/**
+ * ccs_transition_control - Find domain transition control.
+ *
+ * @domainname: Pointer to "const struct ccs_path_info".
+ * @program:    Program name.
+ *
+ * Returns pointer to "const struct ccs_transition_control_entry" if found one,
+ * NULL otherwise.
+ */
 static const struct ccs_transition_control_entry *ccs_transition_control
 (const struct ccs_path_info *domainname, const char *program)
 {
@@ -663,12 +949,12 @@ static const struct ccs_transition_control_entry *ccs_transition_control
                last_name.name = domainname->name;
        ccs_fill_path_info(&last_name);
        for (type = 0; type < CCS_MAX_TRANSITION_TYPE; type++) {
- next:
+next:
                for (i = 0; i < ccs_transition_control_list_len; i++) {
                        struct ccs_transition_control_entry *ptr
                                = &ccs_transition_control_list[i];
                        if (ptr->type != type)
-                                continue;
+                               continue;
                        if (ptr->domainname) {
                                if (!ptr->is_last_name) {
                                        if (ccs_pathcmp(ptr->domainname,
@@ -680,7 +966,8 @@ static const struct ccs_transition_control_entry *ccs_transition_control
                                                continue;
                                }
                        }
-                       if (ptr->program && strcmp(ptr->program->name, program))
+                       if (ptr->program &&
+                           strcmp(ptr->program->name, program))
                                continue;
                        if (type == CCS_TRANSITION_CONTROL_NO_INITIALIZE) {
                                /*
@@ -700,6 +987,14 @@ static const struct ccs_transition_control_entry *ccs_transition_control
        return NULL;
 }
 
+/**
+ * ccs_profile_entry_compare -  strcmp() for qsort() callback.
+ *
+ * @a: Pointer to "void".
+ * @b: Pointer to "void".
+ *
+ * Returns return value of strcmp().
+ */
 static int ccs_profile_entry_compare(const void *a, const void *b)
 {
        const struct ccs_generic_acl *a0 = (struct ccs_generic_acl *) a;
@@ -724,7 +1019,7 @@ static int ccs_profile_entry_compare(const void *a, const void *b)
                                return 1;
                }
        }
-       if (ccs_profile_sort_type == 0) {
+       if (!ccs_profile_sort_type) {
                if (a2 == b2)
                        return strcmp(a1, b1);
                else
@@ -742,13 +1037,19 @@ static int ccs_profile_entry_compare(const void *a, const void *b)
        }
 }
 
+/**
+ * ccs_read_generic_policy - Read policy data other than domain policy.
+ *
+ * Returns nothing.
+ */
 static void ccs_read_generic_policy(void)
 {
        FILE *fp = NULL;
        _Bool flag = false;
-       while (ccs_generic_acl_list_count)
+       while (ccs_gacl_list_count)
                free((void *)
-                    ccs_generic_acl_list[--ccs_generic_acl_list_count].operand);
+                    ccs_gacl_list[--ccs_gacl_list_count].
+                    operand);
        if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
                if (ccs_network_mode)
                        /* We can read after write. */
@@ -758,7 +1059,8 @@ static void ccs_read_generic_policy(void)
                        fp = fopen(ccs_policy_file, "r+");
                if (fp) {
                        if (ccs_domain_sort_type)
-                               fprintf(fp, "select pid=%u\n", ccs_current_pid);
+                               fprintf(fp, "select pid=%u\n",
+                                       ccs_current_pid);
                        else
                                fprintf(fp, "select domain=%s\n",
                                        ccs_current_domain);
@@ -773,10 +1075,11 @@ static void ccs_read_generic_policy(void)
                ccs_set_error(ccs_policy_file);
                return;
        }
+       ccs_freadline_raw = ccs_current_screen == CCS_SCREEN_STAT_LIST;
        ccs_get();
        while (true) {
-               char *line = ccs_freadline(fp);
-               u16 directive;
+               char *line = ccs_freadline_unpack(fp);
+               enum ccs_editpolicy_directives directive;
                char *cp;
                if (!line)
                        break;
@@ -812,42 +1115,59 @@ static void ccs_read_generic_policy(void)
                        directive = CCS_DIRECTIVE_NONE;
                        break;
                }
-               ccs_generic_acl_list = realloc(ccs_generic_acl_list,
-                                              (ccs_generic_acl_list_count + 1) *
-                                              sizeof(struct ccs_generic_acl));
-               if (!ccs_generic_acl_list)
+               ccs_gacl_list =
+                       realloc(ccs_gacl_list,
+                               (ccs_gacl_list_count + 1) *
+                               sizeof(struct ccs_generic_acl));
+               if (!ccs_gacl_list)
                        ccs_out_of_memory();
                cp = strdup(line);
                if (!cp)
                        ccs_out_of_memory();
-               ccs_generic_acl_list[ccs_generic_acl_list_count].directive = directive;
-               ccs_generic_acl_list[ccs_generic_acl_list_count].selected = 0;
-               ccs_generic_acl_list[ccs_generic_acl_list_count++].operand = cp;
+               ccs_gacl_list[ccs_gacl_list_count].directive =
+                       directive;
+               ccs_gacl_list[ccs_gacl_list_count].selected = 0;
+               ccs_gacl_list[ccs_gacl_list_count++].operand =
+                       cp;
        }
        ccs_put();
+       ccs_freadline_raw = false;
        fclose(fp);
        switch (ccs_current_screen) {
        case CCS_SCREEN_ACL_LIST:
-               qsort(ccs_generic_acl_list, ccs_generic_acl_list_count,
-                     sizeof(struct ccs_generic_acl), ccs_generic_acl_compare);
+               qsort(ccs_gacl_list, ccs_gacl_list_count,
+                     sizeof(struct ccs_generic_acl), ccs_gacl_compare);
                break;
        case CCS_SCREEN_EXCEPTION_LIST:
-               qsort(ccs_generic_acl_list, ccs_generic_acl_list_count,
-                     sizeof(struct ccs_generic_acl), ccs_generic_acl_compare0);
+               qsort(ccs_gacl_list, ccs_gacl_list_count,
+                     sizeof(struct ccs_generic_acl),
+                     ccs_gacl_compare0);
                break;
        case CCS_SCREEN_PROFILE_LIST:
-               qsort(ccs_generic_acl_list, ccs_generic_acl_list_count,
-                     sizeof(struct ccs_generic_acl), ccs_profile_entry_compare);
+               qsort(ccs_gacl_list, ccs_gacl_list_count,
+                     sizeof(struct ccs_generic_acl),
+                     ccs_profile_entry_compare);
+               break;
+       case CCS_SCREEN_STAT_LIST:
                break;
        default:
-               qsort(ccs_generic_acl_list, ccs_generic_acl_list_count,
+               qsort(ccs_gacl_list, ccs_gacl_list_count,
                      sizeof(struct ccs_generic_acl), ccs_string_acl_compare);
        }
 }
 
-static int ccs_add_transition_control_entry(const char *domainname,
-                                           const char *program,
-                                           const u8 type)
+/**
+ * ccs_add_transition_control_entry - Add "initialize_domain"/"no_initialize_domain"/"keep_domain"/ "no_keep_domain" entries.
+ *
+ * @domainname: Domainname.
+ * @program:    Program name.
+ * @type: One of values in "enum ccs_transition_type".
+ *
+ * Returns 0 on success, -EINVAL otherwise.
+ */
+static int ccs_add_transition_control_entry
+(const char *domainname, const char *program,
+ const enum ccs_transition_type type)
 {
        void *vp;
        struct ccs_transition_control_entry *ptr;
@@ -886,8 +1206,18 @@ static int ccs_add_transition_control_entry(const char *domainname,
        return 0;
 }
 
-static int ccs_add_path_group_entry(const char *group_name, const char *member_name,
-                               const _Bool is_delete)
+/**
+ * ccs_add_path_group_entry - Add "path_group" entry.
+ *
+ * @group_name:  Name of address group.
+ * @member_name: Address string.
+ * @is_delete:   True if it is delete request, false otherwise.
+ *
+ * Returns 0 on success, negative value otherwise.
+ */
+static int ccs_add_path_group_entry(const char *group_name,
+                                   const char *member_name,
+                                   const _Bool is_delete)
 {
        const struct ccs_path_info *saved_group_name;
        const struct ccs_path_info *saved_member_name;
@@ -938,180 +1268,288 @@ static int ccs_add_path_group_entry(const char *group_name, const char *member_n
        return 0;
 }
 
-static void ccs_read_domain_and_exception_policy(struct ccs_domain_policy *dp)
+/*
+ * List of "task auto_domain_transition" "task manual_domain_transition"
+ * "auto_domain_transition=" part.
+ */
+static char **ccs_jump_list = NULL;
+static int ccs_jump_list_len = 0;
+
+/**
+ * ccs_add_condition_domain_transition - Add auto_domain_transition= part.
+ *
+ * @line:  Line to parse.
+ * @index: Current domain's index.
+ *
+ * Returns nothing.
+ */
+static void ccs_add_condition_domain_transition(char *line, const int index)
+{
+       static char domainname[4096];
+       int source;
+       char *cp = strrchr(line, ' ');
+       if (!cp || strncmp(cp, " auto_domain_transition=\"", 25))
+               return;
+       *cp = '\0';
+       cp += 25;
+       source = strlen(cp);
+       if (!source)
+               return;
+       cp[source - 1] = '\0';
+       snprintf(domainname, sizeof(domainname) - 1, "%s %s",
+                ccs_domain_name(&ccs_dp, index), cp);
+       domainname[sizeof(domainname) - 1] = '\0';
+       ccs_normalize_line(domainname);
+       cp = strdup(domainname);
+       ccs_jump_list = realloc(ccs_jump_list,
+                               (ccs_jump_list_len + 1) * sizeof(char *));
+       if (!cp || !ccs_jump_list)
+               ccs_out_of_memory();
+       ccs_jump_list[ccs_jump_list_len++] = cp;
+       source = ccs_assign_domain(&ccs_dp, domainname, true, false);
+       if (source == EOF)
+               ccs_out_of_memory();
+       cp = strdup(domainname);
+       if (!cp)
+               ccs_out_of_memory();
+       ccs_dp.list[source].target_domainname = cp;
+}
+
+/**
+ * ccs_add_acl_domain_transition - Add task acl.
+ *
+ * @line:  Line to parse.
+ * @index: Current domain's index.
+ *
+ * Returns nothing.
+ */
+static void ccs_add_acl_domain_transition(char *line, const int index)
+{
+       static char domainname[4096];
+       int source;
+       char *cp;
+       for (source = 0; line[source]; source++)
+               if (line[source] == ' ' && line[source + 1] != '/') {
+                       line[source] = '\0';
+                       break;
+               }
+       if (!ccs_correct_domain(line))
+               return;
+       cp = strdup(line);
+       ccs_jump_list = realloc(ccs_jump_list,
+                               (ccs_jump_list_len + 1) * sizeof(char *));
+       if (!cp || !ccs_jump_list)
+               ccs_out_of_memory();
+       ccs_jump_list[ccs_jump_list_len++] = cp;
+       cp = strrchr(line, ' ');
+       if (cp)
+               cp++;
+       else
+               cp = line;
+       snprintf(domainname, sizeof(domainname) - 1, "%s %s",
+                ccs_domain_name(&ccs_dp, index), cp);
+       domainname[sizeof(domainname) - 1] = '\0';
+       ccs_normalize_line(domainname);
+       source = ccs_assign_domain(&ccs_dp, domainname, true, false);
+       if (source == EOF)
+               ccs_out_of_memory();
+       cp = strdup(line);
+       if (!cp)
+               ccs_out_of_memory();
+       ccs_dp.list[source].target_domainname = cp;
+}
+
+/**
+ * ccs_parse_domain_line - Parse an ACL entry in domain policy.
+ *
+ * @line:        Line to parse.
+ * @index:       Current domain's index.
+ * @parse_flags: True if parse use_profile and use_group lines, false otherwise.
+ *
+ * Returns nothing.
+ */
+static void ccs_parse_domain_line(char *line, const int index,
+                                 const bool parse_flags)
+{
+       ccs_add_condition_domain_transition(line, index);
+       if (ccs_str_starts(line, "task auto_execute_handler ") ||
+           ccs_str_starts(line, "task denied_execute_handler ") ||
+           ccs_str_starts(line, "file execute ")) {
+               char *cp = strchr(line, ' ');
+               if (cp)
+                       *cp = '\0';
+               if (*line == '@' || ccs_correct_path(line))
+                       ccs_add_string_entry(&ccs_dp, line, index);
+       } else if (ccs_str_starts(line,
+                                 "task auto_domain_transition ") ||
+                  ccs_str_starts(line,
+                                 "task manual_domain_transition ")) {
+               ccs_add_acl_domain_transition(line, index);
+       } else if (parse_flags) {
+               unsigned int profile;
+               if (sscanf(line, "use_profile %u", &profile) == 1) {
+                       ccs_dp.list[index].profile = (u8) profile;
+                       ccs_dp.list[index].profile_assigned = 1;
+               } else if (sscanf(line, "use_group %u", &profile) == 1) {
+                       ccs_dp.list[index].group = (u8) profile;
+               }
+       }
+}
+
+/**
+ * ccs_parse_exception_line - Parse an ACL entry in exception policy.
+ *
+ * @line:      Line to parse.
+ * @max_index: Number of domains currently defined.
+ *
+ * Returns nothing.
+ */
+static void ccs_parse_exception_line(char *line, const int max_index)
+{
+       unsigned int group;
+       if (ccs_str_starts(line, "initialize_domain "))
+               ccs_add_transition_control_policy
+                       (line, CCS_TRANSITION_CONTROL_INITIALIZE);
+       else if (ccs_str_starts(line, "no_initialize_domain "))
+               ccs_add_transition_control_policy
+                       (line, CCS_TRANSITION_CONTROL_NO_INITIALIZE);
+       else if (ccs_str_starts(line, "keep_domain "))
+               ccs_add_transition_control_policy
+                       (line, CCS_TRANSITION_CONTROL_KEEP);
+       else if (ccs_str_starts(line, "no_keep_domain "))
+               ccs_add_transition_control_policy
+                       (line, CCS_TRANSITION_CONTROL_NO_KEEP);
+       else if (ccs_str_starts(line, "path_group "))
+               ccs_add_path_group_policy(line, false);
+       else if (ccs_str_starts(line, "address_group "))
+               ccs_add_address_group_policy(line, false);
+       else if (ccs_str_starts(line, "number_group "))
+               ccs_add_number_group_policy(line, false);
+       else if (sscanf(line, "acl_group %u", &group) == 1 && group < 256) {
+               int index;
+               char *cp = strchr(line + 10, ' ');
+               if (cp)
+                       line = cp + 1;
+               for (index = 0; index < max_index; index++) {
+                       if (ccs_dp.list[index].group != group)
+                               continue;
+                       cp = strdup(line);
+                       if (!cp)
+                               ccs_out_of_memory();
+                       ccs_parse_domain_line(cp, index, false);
+                       free(cp);
+               }
+       }
+}
+
+/**
+ * ccs_read_domain_and_exception_policy - Read domain policy and exception policy.
+ *
+ * Returns nothing.
+ *
+ * Since CUI policy editor screen shows domain initializer source domains and
+ * unreachable domains, we need to read not only the domain policy but also
+ * the exception policy for printing the domain transition tree.
+ */
+static void ccs_read_domain_and_exception_policy(void)
 {
        FILE *fp;
        int i;
        int j;
        int index;
        int max_index;
-       static char **ccs_jump_list = NULL;
-       static int ccs_jump_list_len = 0;
        while (ccs_jump_list_len)
                free(ccs_jump_list[--ccs_jump_list_len]);
-       ccs_clear_domain_policy(dp);
+       ccs_clear_domain_policy(&ccs_dp);
        ccs_transition_control_list_len = 0;
-       while (ccs_path_group_list_len)
-               free(ccs_path_group_list[--ccs_path_group_list_len].member_name);
-       /*
-       while (ccs_address_group_list_len)
-               free(ccs_address_group_list[--ccs_address_group_list_len].member_name);
-       */
-       ccs_address_group_list_len = 0;
-       ccs_number_group_list_len = 0;
-       ccs_assign_domain(dp, CCS_ROOT_NAME, false, false);
-
-       /* Load all domain list. */
+       ccs_editpolicy_clear_groups();
+       ccs_assign_domain(&ccs_dp, CCS_ROOT_NAME, false, false);
+
+       /* Load all domain transition related entries. */
        fp = NULL;
        if (ccs_network_mode)
                /* We can read after write. */
-               fp = ccs_editpolicy_open_write(ccs_policy_file);
+               fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_DOMAIN_POLICY);
        else if (!ccs_offline_mode)
                /* Don't set error message if failed. */
-               fp = fopen(ccs_policy_file, "r+");
+               fp = fopen(CCS_PROC_POLICY_DOMAIN_POLICY, "r+");
        if (fp) {
-               fprintf(fp, "select execute\n");
+               fprintf(fp, "select transition_only\n");
                if (ccs_network_mode)
                        fputc(0, fp);
                fflush(fp);
-       }
-       if (!fp)
+       } else {
                fp = ccs_editpolicy_open_read(CCS_PROC_POLICY_DOMAIN_POLICY);
-       if (!fp) {
-               ccs_set_error(CCS_PROC_POLICY_DOMAIN_POLICY);
-               goto no_domain;
        }
-       index = EOF;
-       ccs_get();
-       while (true) {
-               char *line = ccs_freadline(fp);
-               unsigned int profile;
-               if (!line)
-                       break;
-               if (ccs_domain_def(line)) {
-                       index = ccs_assign_domain(dp, line, false, false);
-                       continue;
-               } else if (index == EOF) {
-                       continue;
-               }
-               if (ccs_str_starts(line, "task auto_execute_handler ") ||
-                   ccs_str_starts(line, "task denied_execute_handler ") ||
-                   ccs_str_starts(line, "file execute ")) {
-                       char *cp = strchr(line, ' ');
-                       if (cp)
-                               *cp = '\0';
-                       if (*line == '@' || ccs_correct_path(line))
-                               ccs_add_string_entry(dp, line, index);
-               } else if (ccs_str_starts(line,
-                                         "task auto_domain_transition ") ||
-                          ccs_str_starts(line,
-                                         "task manual_domain_transition ")) {
-                       static char domainname[4096];
-                       int source;
-                       char *m;
-                       int i;
-                       for (i = 0; line[i]; i++)
-                               if (line[i] == ' ' && line[i + 1] != '/') {
-                                       line[i] = '\0';
-                                       break;
-                               }
-                       if (!ccs_correct_domain(line))
+       if (fp) {
+               index = EOF;
+               ccs_get();
+               while (true) {
+                       char *line = ccs_freadline_unpack(fp);
+                       if (!line)
+                               break;
+                       if (ccs_domain_def(line)) {
+                               index = ccs_assign_domain(&ccs_dp, line, false,
+                                                         false);
                                continue;
-                       ccs_jump_list = realloc(ccs_jump_list,
-                                               (ccs_jump_list_len + 1)
-                                               * sizeof(char *));
-                       if (!ccs_jump_list)
-                               ccs_out_of_memory();
-                       ccs_jump_list[ccs_jump_list_len] = strdup(line);
-                       if (!ccs_jump_list[ccs_jump_list_len])
-                               ccs_out_of_memory();
-                       ccs_jump_list_len++;
-                       m = strrchr(line, ' ');
-                       if (m)
-                               m++;
-                       else
-                               m = line;
-                       snprintf(domainname, sizeof(domainname) - 1, "%s %s",
-                                ccs_domain_name(dp, index), m);
-                       domainname[sizeof(domainname) - 1] = '\0';
-                       ccs_normalize_line(domainname);
-                       source = ccs_assign_domain(dp, domainname, true, false);
-                       if (source == EOF)
-                               ccs_out_of_memory();
-                       dp->list[source].target_domainname = strdup(line);
-                       if (!dp->list[source].target_domainname)
-                               ccs_out_of_memory();
-               } else if (sscanf(line, "use_profile %u", &profile) == 1) {
-                       dp->list[index].profile = (u8) profile;
-                       dp->list[index].profile_assigned = 1;
-               } else if (sscanf(line, "use_group %u", &profile) == 1) {
-                       dp->list[index].group = (u8) profile;
+                       } else if (index == EOF) {
+                               continue;
+                       }
+                       ccs_parse_domain_line(line, index, true);
                }
+               ccs_put();
+               fclose(fp);
+       } else {
+               ccs_set_error(CCS_PROC_POLICY_DOMAIN_POLICY);
        }
-       ccs_put();
-       fclose(fp);
-no_domain:
 
-       max_index = dp->list_len;
+       max_index = ccs_dp.list_len;
 
-       /* Load domain_initializer list, domain_keeper list. */
-       fp = ccs_editpolicy_open_read(CCS_PROC_POLICY_EXCEPTION_POLICY);
-       if (!fp) {
-               ccs_set_error(CCS_PROC_POLICY_EXCEPTION_POLICY);
-               goto no_exception;
+       /* Load domain transition related entries and group entries. */
+       fp = NULL;
+       if (ccs_network_mode)
+               /* We can read after write. */
+               fp = ccs_editpolicy_open_write
+                       (CCS_PROC_POLICY_EXCEPTION_POLICY);
+       else if (!ccs_offline_mode)
+               /* Don't set error message if failed. */
+               fp = fopen(CCS_PROC_POLICY_EXCEPTION_POLICY, "r+");
+       if (fp) {
+               fprintf(fp, "select transition_only\n");
+               if (ccs_network_mode)
+                       fputc(0, fp);
+               fflush(fp);
+       } else {
+               fp = ccs_editpolicy_open_read
+                       (CCS_PROC_POLICY_EXCEPTION_POLICY);
        }
-       ccs_get();
-       while (true) {
-               unsigned int group;
-               char *line = ccs_freadline(fp);
-               if (!line)
-                       break;
-               if (ccs_str_starts(line, "initialize_domain "))
-                       ccs_add_transition_control_policy(line, CCS_TRANSITION_CONTROL_INITIALIZE);
-               else if (ccs_str_starts(line, "no_initialize_domain "))
-                       ccs_add_transition_control_policy(line, CCS_TRANSITION_CONTROL_NO_INITIALIZE);
-               else if (ccs_str_starts(line, "keep_domain "))
-                       ccs_add_transition_control_policy(line, CCS_TRANSITION_CONTROL_KEEP);
-               else if (ccs_str_starts(line, "no_keep_domain "))
-                       ccs_add_transition_control_policy(line, CCS_TRANSITION_CONTROL_NO_KEEP);
-               else if (ccs_str_starts(line, "path_group "))
-                       ccs_add_path_group_policy(line, false);
-               else if (ccs_str_starts(line, "address_group "))
-                       ccs_add_address_group_policy(line, false);
-               else if (ccs_str_starts(line, "number_group "))
-                       ccs_add_number_group_policy(line, false);
-               else if (sscanf(line, "acl_group %u", &group) == 1
-                        && group < 256) {
-                       char *cp = strchr(line + 10, ' ');
-                       if (cp)
-                               line = cp + 1;
-                       if (ccs_str_starts(line,
-                                          "task auto_execute_handler ") ||
-                           ccs_str_starts(line,
-                                          "task denied_execute_handler ") ||
-                           ccs_str_starts(line, "file execute ")) {
-                               cp = strchr(line, ' ');
-                               if (cp)
-                                       *cp = '\0';
-                               if (*line == '@' || ccs_correct_path(line)) {
-                                       for (index = 0; index < max_index;
-                                            index++)
-                                               if (dp->list[index].group
-                                                   == group)
-                                                       ccs_add_string_entry(dp, line, index);
-                               }
-                       }
+       if (fp) {
+               ccs_get();
+               while (true) {
+                       char *line = ccs_freadline_unpack(fp);
+                       if (!line)
+                               break;
+                       ccs_parse_exception_line(line, max_index);
                }
+               ccs_put();
+               fclose(fp);
+       } else {
+               ccs_set_error(CCS_PROC_POLICY_EXCEPTION_POLICY);
        }
-       ccs_put();
-       fclose(fp);
-no_exception:
 
-       /* Find unreachable domains. */
+       /*
+        * Find unreachable domains.
+        *
+        * This is calculated based on "initialize_domain" and "keep_domain"
+        * keywords. However, since "task auto_domain_transition" and "task
+        * manual_domain_transition" keywords and "auto_domain_transition="
+        * condition are not subjected to "initialize_domain" and "keep_domain"
+        * keywords, we need to adjust later.
+        */
        for (index = 0; index < max_index; index++) {
                char *line;
                ccs_get();
-               line = ccs_shprintf("%s", ccs_domain_name(dp, index));
+               line = ccs_shprintf("%s", ccs_domain_name(&ccs_dp, index));
                while (true) {
                        const struct ccs_transition_control_entry *d_t;
                        struct ccs_path_info parent;
@@ -1128,17 +1566,17 @@ no_exception:
                        if (d_t->type == CCS_TRANSITION_CONTROL_INITIALIZE &&
                            parent.total_len == CCS_ROOT_NAME_LEN)
                                break;
-                       dp->list[index].d_t = d_t;
+                       ccs_dp.list[index].d_t = d_t;
                        continue;
                }
                ccs_put();
-               if (dp->list[index].d_t)
-                       dp->list[index].is_du = true;
+               if (ccs_dp.list[index].d_t)
+                       ccs_dp.list[index].is_du = true;
        }
 
        /* Find domain initializer target domains. */
        for (index = 0; index < max_index; index++) {
-               char *cp = strchr(ccs_domain_name(dp, index), ' ');
+               char *cp = strchr(ccs_domain_name(&ccs_dp, index), ' ');
                if (!cp || strchr(cp + 1, ' '))
                        continue;
                for (i = 0; i < ccs_transition_control_list_len; i++) {
@@ -1148,7 +1586,7 @@ no_exception:
                                continue;
                        if (ptr->program && strcmp(ptr->program->name, cp + 1))
                                continue;
-                       dp->list[index].is_dit = true;
+                       ccs_dp.list[index].is_dit = true;
                }
        }
 
@@ -1163,36 +1601,38 @@ no_exception:
                        if (!ptr->is_last_name) {
                                if (ptr->domainname &&
                                    ccs_pathcmp(ptr->domainname,
-                                               dp->list[index].domainname))
+                                               ccs_dp.list[index].domainname))
                                        continue;
-                               dp->list[index].is_dk = true;
+                               ccs_dp.list[index].is_dk = true;
                                continue;
                        }
-                       cp = strrchr(dp->list[index].domainname->name,
+                       cp = strrchr(ccs_dp.list[index].domainname->name,
                                     ' ');
                        if (!cp || (ptr->domainname->name &&
                                    strcmp(ptr->domainname->name, cp + 1)))
                                continue;
-                       dp->list[index].is_dk = true;
+                       ccs_dp.list[index].is_dk = true;
                }
        }
 
        /* Create domain initializer source domains. */
        for (index = 0; index < max_index; index++) {
                const struct ccs_path_info *domainname
-                       = dp->list[index].domainname;
+                       = ccs_dp.list[index].domainname;
                const struct ccs_path_info **string_ptr
-                       = dp->list[index].string_ptr;
-               const int max_count = dp->list[index].string_count;
-               /* Don't create source domain under <kernel> because
-                  they will become ccs_target domains. */
+                       = ccs_dp.list[index].string_ptr;
+               const int max_count = ccs_dp.list[index].string_count;
+               /*
+                * Don't create source domain under <kernel> because
+                * they will become target domains.
+                */
                if (domainname->total_len == CCS_ROOT_NAME_LEN)
                        continue;
                for (i = 0; i < max_count; i++) {
                        const struct ccs_path_info *cp = string_ptr[i];
                        struct ccs_path_group_entry *group;
                        if (cp->name[0] != '@') {
-                               ccs_assign_dis(dp, domainname, cp->name);
+                               ccs_assign_dis(domainname, cp->name);
                                continue;
                        }
                        group = ccs_find_path_group(cp->name + 1);
@@ -1200,40 +1640,47 @@ no_exception:
                                continue;
                        for (j = 0; j < group->member_name_len; j++) {
                                cp = group->member_name[j];
-                               ccs_assign_dis(dp, domainname, cp->name);
+                               ccs_assign_dis(domainname, cp->name);
                        }
                }
        }
 
-       /* Create domain jump target domains. */
+       /*
+        * Create domain jump target domains.
+        * This may reset unreachable domains.
+        */
        for (i = 0; i < ccs_jump_list_len; i++) {
-               int index = ccs_find_domain(dp, ccs_jump_list[i], false, false);
-               if (index != EOF)
-                       dp->list[index].is_dit = true;
+               const int index = ccs_find_domain(&ccs_dp, ccs_jump_list[i],
+                                                 false, false);
+               if (index == EOF)
+                       continue;
+               ccs_dp.list[index].is_dit = true;
+               ccs_dp.list[index].d_t = NULL;
+               ccs_dp.list[index].is_du = false;
        }
 
-       //max_index = dp->list_len;
-
        /* Create missing parent domains. */
        for (index = 0; index < max_index; index++) {
                char *line;
                ccs_get();
-               line = ccs_shprintf("%s", ccs_domain_name(dp, index));
+               line = ccs_shprintf("%s", ccs_domain_name(&ccs_dp, index));
                while (true) {
                        char *cp = strrchr(line, ' ');
                        if (!cp)
                                break;
                        *cp = '\0';
-                       if (ccs_find_domain(dp, line, false, false) != EOF)
+                       if (ccs_find_domain(&ccs_dp, line, false, false)
+                           != EOF)
                                continue;
-                       if (ccs_assign_domain(dp, line, false, true) == EOF)
+                       if (ccs_assign_domain(&ccs_dp, line, false, true)
+                           == EOF)
                                ccs_out_of_memory();
                }
                ccs_put();
        }
 
        /* Sort by domain name. */
-       qsort(dp->list, dp->list_len, sizeof(struct ccs_domain_info),
+       qsort(ccs_dp.list, ccs_dp.list_len, sizeof(struct ccs_domain_info),
              ccs_domainname_attribute_compare);
 
        /* Assign domain numbers. */
@@ -1241,23 +1688,30 @@ no_exception:
                int number = 0;
                int index;
                ccs_unnumbered_domain_count = 0;
-               for (index = 0; index < dp->list_len; index++) {
-                       if (ccs_deleted_domain(dp, index) ||
-                           ccs_initializer_source(dp, index)) {
-                               dp->list[index].number = -1;
+               for (index = 0; index < ccs_dp.list_len; index++) {
+                       if (ccs_deleted_domain(index) ||
+                           ccs_initializer_source(index)) {
+                               ccs_dp.list[index].number = -1;
                                ccs_unnumbered_domain_count++;
                        } else {
-                               dp->list[index].number = number++;
+                               ccs_dp.list[index].number = number++;
                        }
                }
        }
 
-       dp->list_selected = realloc(dp->list_selected, dp->list_len);
-       if (dp->list_len && !dp->list_selected)
+       ccs_dp.list_selected = realloc(ccs_dp.list_selected, ccs_dp.list_len);
+       if (ccs_dp.list_len && !ccs_dp.list_selected)
                ccs_out_of_memory();
-       memset(dp->list_selected, 0, dp->list_len);
+       memset(ccs_dp.list_selected, 0, ccs_dp.list_len);
 }
 
+/**
+ * ccs_show_process_line - Print a process line.
+ *
+ * @index: Index in the ccs_task_list array.
+ *
+ * Returns length of the printed line.
+ */
 static int ccs_show_process_line(const int index)
 {
        char *line;
@@ -1273,23 +1727,31 @@ static int ccs_show_process_line(const int index)
        ccs_get();
        line = ccs_shprintf("%s%s (%u) %s", ccs_task_list[index].depth ?
                            " +- " : "", ccs_task_list[index].name,
-                           ccs_task_list[index].pid, ccs_task_list[index].domain);
+                           ccs_task_list[index].pid,
+                           ccs_task_list[index].domain);
        printw("%s", ccs_eat(line));
        tmp_col += strlen(line);
        ccs_put();
        return tmp_col;
 }
 
-static void ccs_show_list(struct ccs_domain_policy *dp)
+/**
+ * ccs_show_list - Print list on the screen.
+ *
+ * Returns nothing.
+ */
+static void ccs_show_list(void)
 {
-       const int offset = ccs_current_item_index[ccs_current_screen];
+       struct ccs_screen *ptr = &ccs_screen[ccs_current_screen];
+       int ccs_list_indent;
+       const int offset = ptr->current;
        int i;
        int tmp_col;
        if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST)
-               ccs_list_item_count[CCS_SCREEN_DOMAIN_LIST] = ccs_domain_sort_type ?
-                       ccs_task_list_len : dp->list_len;
+               ccs_list_item_count = ccs_domain_sort_type ?
+                       ccs_task_list_len : ccs_dp.list_len;
        else
-               ccs_list_item_count[ccs_current_screen] = ccs_generic_acl_list_count;
+               ccs_list_item_count = ccs_gacl_list_count;
        clear();
        move(0, 0);
        if (ccs_window_height < CCS_HEADER_LINES + 1) {
@@ -1299,28 +1761,29 @@ static void ccs_show_list(struct ccs_domain_policy *dp)
                return;
        }
        /* add color */
-       ccs_editpolicy_color_change(ccs_editpolicy_color_head(ccs_current_screen), true);
+       ccs_editpolicy_color_change(ccs_editpolicy_color_head(), true);
        if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
                if (ccs_domain_sort_type) {
                        printw("<<< Process State Viewer >>>"
                               "      %d process%s    '?' for help",
-                              ccs_task_list_len, ccs_task_list_len > 1 ? "es" : "");
+                              ccs_task_list_len,
+                              ccs_task_list_len > 1 ? "es" : "");
                } else {
-                       int i = ccs_list_item_count[CCS_SCREEN_DOMAIN_LIST]
+                       int i = ccs_list_item_count
                                - ccs_unnumbered_domain_count;
                        printw("<<< Domain Transition Editor >>>"
                               "      %d domain%c    '?' for help",
                               i, i > 1 ? 's' : ' ');
                }
        } else {
-               int i = ccs_list_item_count[ccs_current_screen];
+               int i = ccs_list_item_count;
                printw("<<< %s >>>"
                       "      %d entr%s    '?' for help", ccs_list_caption,
                       i, i > 1 ? "ies" : "y");
        }
        /* add color */
-       ccs_editpolicy_color_change(ccs_editpolicy_color_head(ccs_current_screen), false);
-       ccs_eat_col = ccs_max_eat_col[ccs_current_screen];
+       ccs_editpolicy_color_change(ccs_editpolicy_color_head(), false);
+       ccs_eat_col = ptr->x;
        ccs_max_col = 0;
        if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
                char *line;
@@ -1336,24 +1799,27 @@ static void ccs_show_list(struct ccs_domain_policy *dp)
        switch (ccs_current_screen) {
        case CCS_SCREEN_EXCEPTION_LIST:
        case CCS_SCREEN_ACL_LIST:
-               for (i = 0; i < ccs_list_item_count[ccs_current_screen]; i++) {
-                       const u16 directive = ccs_generic_acl_list[i].directive;
+               for (i = 0; i < ccs_list_item_count; i++) {
+                       const enum ccs_editpolicy_directives directive =
+                               ccs_gacl_list[i].directive;
                        const int len = ccs_directives[directive].alias_len;
                        if (len > ccs_list_indent)
                                ccs_list_indent = len;
                }
                break;
+       default:
+               break;
        }
        for (i = 0; i < ccs_body_lines; i++) {
                const int index = offset + i;
-               ccs_eat_col = ccs_max_eat_col[ccs_current_screen];
-               if (index >= ccs_list_item_count[ccs_current_screen])
+               ccs_eat_col = ptr->x;
+               if (index >= ccs_list_item_count)
                        break;
                move(CCS_HEADER_LINES + i, 0);
                switch (ccs_current_screen) {
                case CCS_SCREEN_DOMAIN_LIST:
                        if (!ccs_domain_sort_type)
-                               tmp_col = ccs_show_domain_line(dp, index);
+                               tmp_col = ccs_show_domain_line(index);
                        else
                                tmp_col = ccs_show_process_line(index);
                        break;
@@ -1364,8 +1830,8 @@ static void ccs_show_list(struct ccs_domain_policy *dp)
                case CCS_SCREEN_PROFILE_LIST:
                        tmp_col = ccs_show_profile_line(index);
                        break;
-               case CCS_SCREEN_MEMINFO_LIST:
-                       tmp_col = ccs_show_meminfo_line(index);
+               case CCS_SCREEN_STAT_LIST:
+                       tmp_col = ccs_show_stat_line(index);
                        break;
                default:
                        tmp_col = ccs_show_literal_line(index);
@@ -1376,51 +1842,71 @@ static void ccs_show_list(struct ccs_domain_policy *dp)
                if (tmp_col > ccs_max_col)
                        ccs_max_col = tmp_col;
        }
-       ccs_show_current(dp);
+       ccs_show_current();
 }
 
+/**
+ * ccs_resize_window - Callback for resize event.
+ *
+ * Returns nothing.
+ */
 static void ccs_resize_window(void)
 {
+       struct ccs_screen *ptr = &ccs_screen[ccs_current_screen];
        getmaxyx(stdscr, ccs_window_height, ccs_window_width);
        ccs_body_lines = ccs_window_height - CCS_HEADER_LINES;
-       if (ccs_body_lines <= ccs_current_y[ccs_current_screen])
-               ccs_current_y[ccs_current_screen] = ccs_body_lines - 1;
-       if (ccs_current_y[ccs_current_screen] < 0)
-               ccs_current_y[ccs_current_screen] = 0;
+       if (ccs_body_lines <= ptr->y)
+               ptr->y = ccs_body_lines - 1;
+       if (ptr->y < 0)
+               ptr->y = 0;
 }
 
-static void ccs_up_arrow_key(struct ccs_domain_policy *dp)
+/**
+ * ccs_up_arrow_key - Callback event for pressing up-arrow key.
+ *
+ * Returns nothing.
+ */
+static void ccs_up_arrow_key(void)
 {
-       if (ccs_current_y[ccs_current_screen] > 0) {
-               ccs_current_y[ccs_current_screen]--;
-               ccs_show_current(dp);
-       } else if (ccs_current_item_index[ccs_current_screen] > 0) {
-               ccs_current_item_index[ccs_current_screen]--;
-               ccs_show_list(dp);
+       struct ccs_screen *ptr = &ccs_screen[ccs_current_screen];
+       if (ptr->y > 0) {
+               ptr->y--;
+               ccs_show_current();
+       } else if (ptr->current > 0) {
+               ptr->current--;
+               ccs_show_list();
        }
 }
 
-static void ccs_down_arrow_key(struct ccs_domain_policy *dp)
+/**
+ * ccs_down_arrow_key - Callback event for pressing down-arrow key.
+ *
+ * Returns nothing.
+ */
+static void ccs_down_arrow_key(void)
 {
-       if (ccs_current_y[ccs_current_screen] < ccs_body_lines - 1) {
-               if (ccs_current_item_index[ccs_current_screen]
-                   + ccs_current_y[ccs_current_screen]
-                   < ccs_list_item_count[ccs_current_screen] - 1) {
-                       ccs_current_y[ccs_current_screen]++;
-                       ccs_show_current(dp);
+       struct ccs_screen *ptr = &ccs_screen[ccs_current_screen];
+       if (ptr->y < ccs_body_lines - 1) {
+               if (ptr->current + ptr->y < ccs_list_item_count - 1) {
+                       ptr->y++;
+                       ccs_show_current();
                }
-       } else if (ccs_current_item_index[ccs_current_screen]
-                  + ccs_current_y[ccs_current_screen]
-                  < ccs_list_item_count[ccs_current_screen] - 1) {
-               ccs_current_item_index[ccs_current_screen]++;
-               ccs_show_list(dp);
+       } else if (ptr->current + ptr->y < ccs_list_item_count - 1) {
+               ptr->current++;
+               ccs_show_list();
        }
 }
 
-static void ccs_page_up_key(struct ccs_domain_policy *dp)
+/**
+ * ccs_page_up_key - Callback event for pressing page-up key.
+ *
+ * Returns nothing.
+ */
+static void ccs_page_up_key(void)
 {
-       int p0 = ccs_current_item_index[ccs_current_screen];
-       int p1 = ccs_current_y[ccs_current_screen];
+       struct ccs_screen *ptr = &ccs_screen[ccs_current_screen];
+       int p0 = ptr->current;
+       int p1 = ptr->y;
        _Bool refresh;
        if (p0 + p1 > ccs_body_lines) {
                p0 -= ccs_body_lines;
@@ -1432,20 +1918,26 @@ static void ccs_page_up_key(struct ccs_domain_policy *dp)
        } else {
                return;
        }
-       refresh = (ccs_current_item_index[ccs_current_screen] != p0);
-       ccs_current_item_index[ccs_current_screen] = p0;
-       ccs_current_y[ccs_current_screen] = p1;
+       refresh = (ptr->current != p0);
+       ptr->current = p0;
+       ptr->y = p1;
        if (refresh)
-               ccs_show_list(dp);
+               ccs_show_list();
        else
-               ccs_show_current(dp);
+               ccs_show_current();
 }
 
-static void ccs_page_down_key(struct ccs_domain_policy *dp)
+/**
+ * ccs_page_down_key - Callback event for pressing page-down key.
+ *
+ * Returns nothing.
+ */
+static void ccs_page_down_key(void)
 {
-       int ccs_count = ccs_list_item_count[ccs_current_screen] - 1;
-       int p0 = ccs_current_item_index[ccs_current_screen];
-       int p1 = ccs_current_y[ccs_current_screen];
+       struct ccs_screen *ptr = &ccs_screen[ccs_current_screen];
+       int ccs_count = ccs_list_item_count - 1;
+       int p0 = ptr->current;
+       int p1 = ptr->y;
        _Bool refresh;
        if (p0 + p1 + ccs_body_lines < ccs_count) {
                p0 += ccs_body_lines;
@@ -1459,38 +1951,55 @@ static void ccs_page_down_key(struct ccs_domain_policy *dp)
        } else {
                return;
        }
-       refresh = (ccs_current_item_index[ccs_current_screen] != p0);
-       ccs_current_item_index[ccs_current_screen] = p0;
-       ccs_current_y[ccs_current_screen] = p1;
+       refresh = (ptr->current != p0);
+       ptr->current = p0;
+       ptr->y = p1;
        if (refresh)
-               ccs_show_list(dp);
+               ccs_show_list();
        else
-               ccs_show_current(dp);
+               ccs_show_current();
 }
 
+/**
+ * ccs_editpolicy_get_current - Get currently selected line's index.
+ *
+ * Returns index for currently selected line on success, EOF otherwise.
+ *
+ * If current screen has no entry, this function returns EOF.
+ */
 int ccs_editpolicy_get_current(void)
 {
-       int ccs_count = ccs_list_item_count[ccs_current_screen];
-       const int p0 = ccs_current_item_index[ccs_current_screen];
-       const int p1 = ccs_current_y[ccs_current_screen];
+       struct ccs_screen *ptr = &ccs_screen[ccs_current_screen];
+       int ccs_count = ccs_list_item_count;
+       const int p0 = ptr->current;
+       const int p1 = ptr->y;
        if (!ccs_count)
                return EOF;
        if (p0 + p1 < 0 || p0 + p1 >= ccs_count) {
-               fprintf(stderr, "ERROR: ccs_current_item_index=%d ccs_current_y=%d\n",
+               fprintf(stderr,
+                       "ERROR: ccs_current_item_index=%d ccs_current_y=%d\n",
                        p0, p1);
                exit(127);
        }
        return p0 + p1;
 }
 
-static void ccs_show_current(struct ccs_domain_policy *dp)
+/**
+ * ccs_show_current - Show current cursor line.
+ *
+ * Returns nothing.
+ */
+static void ccs_show_current(void)
 {
-       if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST && !ccs_domain_sort_type) {
+       struct ccs_screen *ptr = &ccs_screen[ccs_current_screen];
+       if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST &&
+           !ccs_domain_sort_type) {
                char *line;
                const int index = ccs_editpolicy_get_current();
                ccs_get();
-               ccs_eat_col = ccs_max_eat_col[ccs_current_screen];
-               line = ccs_shprintf("%s", ccs_eat(ccs_domain_name(dp, index)));
+               ccs_eat_col = ptr->x;
+               line = ccs_shprintf("%s",
+                                   ccs_eat(ccs_domain_name(&ccs_dp, index)));
                if (ccs_window_width < strlen(line))
                        line[ccs_window_width] = '\0';
                move(2, 0);
@@ -1500,46 +2009,70 @@ static void ccs_show_current(struct ccs_domain_policy *dp)
                ccs_editpolicy_attr_change(A_REVERSE, false); /* add color */
                ccs_put();
        }
-       move(CCS_HEADER_LINES + ccs_current_y[ccs_current_screen], 0);
-       ccs_editpolicy_line_draw(ccs_current_screen);     /* add color */
+       move(CCS_HEADER_LINES + ptr->y, 0);
+       ccs_editpolicy_line_draw();     /* add color */
        refresh();
 }
 
+/**
+ * ccs_adjust_cursor_pos - Adjust cursor position if needed.
+ *
+ * @item_count: Available item count in this screen.
+ *
+ * Returns nothing.
+ */
 static void ccs_adjust_cursor_pos(const int item_count)
 {
+       struct ccs_screen *ptr = &ccs_screen[ccs_current_screen];
        if (item_count == 0) {
-               ccs_current_item_index[ccs_current_screen] = 0;
-               ccs_current_y[ccs_current_screen] = 0;
+               ptr->current = 0;
+               ptr->y = 0;
        } else {
-               while (ccs_current_item_index[ccs_current_screen]
-                      + ccs_current_y[ccs_current_screen] >= item_count) {
-                       if (ccs_current_y[ccs_current_screen] > 0)
-                               ccs_current_y[ccs_current_screen]--;
-                       else if (ccs_current_item_index[ccs_current_screen] > 0)
-                               ccs_current_item_index[ccs_current_screen]--;
+               while (ptr->current + ptr->y >= item_count) {
+                       if (ptr->y > 0)
+                               ptr->y--;
+                       else if (ptr->current > 0)
+                               ptr->current--;
                }
        }
 }
 
+/**
+ * ccs_set_cursor_pos - Move cursor position if needed.
+ *
+ * @index: Index in the domain policy or currently selected line in the generic
+ *         list.
+ *
+ * Returns nothing.
+ */
 static void ccs_set_cursor_pos(const int index)
 {
-       while (index < ccs_current_y[ccs_current_screen]
-              + ccs_current_item_index[ccs_current_screen]) {
-               if (ccs_current_y[ccs_current_screen] > 0)
-                       ccs_current_y[ccs_current_screen]--;
+       struct ccs_screen *ptr = &ccs_screen[ccs_current_screen];
+       while (index < ptr->y + ptr->current) {
+               if (ptr->y > 0)
+                       ptr->y--;
                else
-                       ccs_current_item_index[ccs_current_screen]--;
+                       ptr->current--;
        }
-       while (index > ccs_current_y[ccs_current_screen]
-              + ccs_current_item_index[ccs_current_screen]) {
-               if (ccs_current_y[ccs_current_screen] < ccs_body_lines - 1)
-                       ccs_current_y[ccs_current_screen]++;
+       while (index > ptr->y + ptr->current) {
+               if (ptr->y < ccs_body_lines - 1)
+                       ptr->y++;
                else
-                       ccs_current_item_index[ccs_current_screen]++;
+                       ptr->current++;
        }
 }
 
-static _Bool ccs_select_item(struct ccs_domain_policy *dp, const int index)
+/**
+ * ccs_select_item - Select an item.
+ *
+ * @index: Index in the domain policy or currently selected line in the generic
+ *         list.
+ *
+ * Returns true if selected, false otherwise.
+ *
+ * Domain transition source and deleted domains are not selectable.
+ */
+static _Bool ccs_select_item(const int index)
 {
        int x;
        int y;
@@ -1547,25 +2080,33 @@ static _Bool ccs_select_item(struct ccs_domain_policy *dp, const int index)
                return false;
        if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
                if (!ccs_domain_sort_type) {
-                       if (ccs_deleted_domain(dp, index) ||
-                           ccs_initializer_source(dp, index))
+                       if (ccs_deleted_domain(index) ||
+                           ccs_initializer_source(index))
                                return false;
-                       dp->list_selected[index] ^= 1;
+                       ccs_dp.list_selected[index] ^= 1;
                } else {
                        ccs_task_list[index].selected ^= 1;
                }
        } else {
-               ccs_generic_acl_list[index].selected ^= 1;
+               ccs_gacl_list[index].selected ^= 1;
        }
        getyx(stdscr, y, x);
        ccs_editpolicy_sttr_save();    /* add color */
-       ccs_show_list(dp);
+       ccs_show_list();
        ccs_editpolicy_sttr_restore(); /* add color */
        move(y, x);
        return true;
 }
 
-static int ccs_generic_acl_compare(const void *a, const void *b)
+/**
+ * ccs_gacl_compare - strcmp() for qsort() callback.
+ *
+ * @a: Pointer to "void".
+ * @b: Pointer to "void".
+ *
+ * Returns return value of strcmp().
+ */
+static int ccs_gacl_compare(const void *a, const void *b)
 {
        const struct ccs_generic_acl *a0 = (struct ccs_generic_acl *) a;
        const struct ccs_generic_acl *b0 = (struct ccs_generic_acl *) b;
@@ -1573,11 +2114,23 @@ static int ccs_generic_acl_compare(const void *a, const void *b)
        const char *b1 = ccs_directives[b0->directive].alias;
        const char *a2 = a0->operand;
        const char *b2 = b0->operand;
-       if (ccs_acl_sort_type == 0) {
+       if (!ccs_acl_sort_type) {
                const int ret = strcmp(a1, b1);
                if (ret)
                        return ret;
                return strcmp(a2, b2);
+       } else if (a0->directive == CCS_DIRECTIVE_USE_GROUP) {
+               return 1;
+       } else if (b0->directive == CCS_DIRECTIVE_USE_GROUP) {
+               return -1;
+       } else if (a0->directive == CCS_DIRECTIVE_TRANSITION_FAILED) {
+               return 2;
+       } else if (b0->directive == CCS_DIRECTIVE_TRANSITION_FAILED) {
+               return -2;
+       } else if (a0->directive == CCS_DIRECTIVE_QUOTA_EXCEEDED) {
+               return 3;
+       } else if (b0->directive == CCS_DIRECTIVE_QUOTA_EXCEEDED) {
+               return -3;
        } else {
                const int ret = strcmp(a2, b2);
                if (ret)
@@ -1586,25 +2139,33 @@ static int ccs_generic_acl_compare(const void *a, const void *b)
        }
 }
 
-static void ccs_delete_entry(struct ccs_domain_policy *dp, const int index)
+/**
+ * ccs_delete_entry - Delete an entry.
+ *
+ * @index: Index in the domain policy.
+ *
+ * Returns nothing.
+ */
+static void ccs_delete_entry(const int index)
 {
 #ifndef __GPET
        int c;
        move(1, 0);
        ccs_editpolicy_color_change(CCS_DISP_ERR, true);        /* add color */
        if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
-               c = ccs_count(dp->list_selected, dp->list_len);
-               if (!c && index < dp->list_len)
-                       c = ccs_select_item(dp, index);
+               c = ccs_count(ccs_dp.list_selected, ccs_dp.list_len);
+               if (!c && index < ccs_dp.list_len)
+                       c = ccs_select_item(index);
                if (!c)
                        printw("Select domain using Space key first.");
                else
                        printw("Delete selected domain%s? ('Y'es/'N'o)",
                               c > 1 ? "s" : "");
        } else {
-               c = ccs_count2(ccs_generic_acl_list, ccs_generic_acl_list_count);
+               c = ccs_count2(ccs_gacl_list,
+                              ccs_gacl_list_count);
                if (!c)
-                       c = ccs_select_item(dp, index);
+                       c = ccs_select_item(index);
                if (!c)
                        printw("Select entry using Space key first.");
                else
@@ -1621,19 +2182,21 @@ static void ccs_delete_entry(struct ccs_domain_policy *dp, const int index)
        } while (!(c == 'Y' || c == 'y' || c == 'N' || c == 'n' || c == EOF));
        ccs_resize_window();
        if (c != 'Y' && c != 'y') {
-               ccs_show_list(dp);
+               ccs_show_list();
                return;
        }
 #endif /* __GPET */
        if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
                int i;
-               FILE *fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_DOMAIN_POLICY);
+               FILE *fp = ccs_editpolicy_open_write
+                       (CCS_PROC_POLICY_DOMAIN_POLICY);
                if (!fp)
                        return;
-               for (i = 1; i < dp->list_len; i++) {
-                       if (!dp->list_selected[i])
+               for (i = 1; i < ccs_dp.list_len; i++) {
+                       if (!ccs_dp.list_selected[i])
                                continue;
-                       fprintf(fp, "delete %s\n", ccs_domain_name(dp, i));
+                       fprintf(fp, "delete %s\n",
+                               ccs_domain_name(&ccs_dp, i));
                }
                ccs_close_write(fp);
        } else {
@@ -1643,36 +2206,43 @@ static void ccs_delete_entry(struct ccs_domain_policy *dp, const int index)
                        return;
                if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
                        if (ccs_domain_sort_type)
-                               fprintf(fp, "select pid=%u\n", ccs_current_pid);
+                               fprintf(fp, "select pid=%u\n",
+                                       ccs_current_pid);
                        else
                                fprintf(fp, "select domain=%s\n",
                                        ccs_current_domain);
                }
-               for (i = 0; i < ccs_generic_acl_list_count; i++) {
-                       u16 directive;
-                       if (!ccs_generic_acl_list[i].selected)
+               for (i = 0; i < ccs_gacl_list_count; i++) {
+                       enum ccs_editpolicy_directives directive;
+                       if (!ccs_gacl_list[i].selected)
                                continue;
-                       directive = ccs_generic_acl_list[i].directive;
+                       directive = ccs_gacl_list[i].directive;
                        fprintf(fp, "delete %s %s\n",
                                ccs_directives[directive].original,
-                               ccs_generic_acl_list[i].operand);
+                               ccs_gacl_list[i].operand);
                }
                ccs_close_write(fp);
        }
 }
 
-static void ccs_add_entry(struct ccs_readline_data *rl)
+/**
+ * ccs_add_entry - Add an entry.
+ *
+ * Returns nothing.
+ */
+static void ccs_add_entry(void)
 {
        FILE *fp;
        char *line;
 #ifndef __GPET
        ccs_editpolicy_attr_change(A_BOLD, true);  /* add color */
        line = ccs_readline(ccs_window_height - 1, 0, "Enter new entry> ",
-                           rl->history, rl->count, 128000, 8);
+                           ccs_rl.history, ccs_rl.count, 128000, 8);
        ccs_editpolicy_attr_change(A_BOLD, false); /* add color */
        if (!line || !*line)
                goto out;
-       rl->count = ccs_add_history(line, rl->history, rl->count, rl->max);
+       ccs_rl.count = ccs_add_history(line, ccs_rl.history, ccs_rl.count,
+                                      ccs_rl.max);
 #else
        line = gpet_line;
 #endif
@@ -1680,7 +2250,7 @@ static void ccs_add_entry(struct ccs_readline_data *rl)
        if (!fp)
                goto out;
        switch (ccs_current_screen) {
-               u16 directive;
+               enum ccs_editpolicy_directives directive;
        case CCS_SCREEN_DOMAIN_LIST:
                if (!ccs_correct_domain(line)) {
                        const int len = strlen(line) + 128;
@@ -1709,6 +2279,8 @@ static void ccs_add_entry(struct ccs_readline_data *rl)
                if (!strchr(line, '='))
                        fprintf(fp, "%s-COMMENT=\n", line);
                break;
+       default:
+               break;
        }
        fprintf(fp, "%s\n", line);
        ccs_close_write(fp);
@@ -1716,8 +2288,17 @@ out:
        free(line);
 }
 
-static void ccs_find_entry(struct ccs_domain_policy *dp, _Bool input, _Bool forward,
-                          const int current, struct ccs_readline_data *rl)
+/**
+ * ccs_find_entry - Find an entry by user's key input.
+ *
+ * @input:   True if find next/previous, false if find first.
+ * @forward: True if find next, false if find previous.
+ * @current: Current position.
+ *
+ * Returns nothing.
+ */
+static void ccs_find_entry(const _Bool input, const _Bool forward,
+                          const int current)
 {
        int index = current;
        char *line = NULL;
@@ -1727,13 +2308,14 @@ static void ccs_find_entry(struct ccs_domain_policy *dp, _Bool input, _Bool forw
                goto start_search;
        ccs_editpolicy_attr_change(A_BOLD, true);  /* add color */
        line = ccs_readline(ccs_window_height - 1, 0, "Search> ",
-                           rl->history, rl->count, 128000, 8);
+                           ccs_rl.history, ccs_rl.count, 128000, 8);
        ccs_editpolicy_attr_change(A_BOLD, false); /* add color */
        if (!line || !*line)
                goto out;
-       rl->count = ccs_add_history(line, rl->history, rl->count, rl->max);
-       free(rl->search_buffer[ccs_current_screen]);
-       rl->search_buffer[ccs_current_screen] = line;
+       ccs_rl.count = ccs_add_history(line, ccs_rl.history, ccs_rl.count,
+                                      ccs_rl.max);
+       free(ccs_rl.search_buffer[ccs_current_screen]);
+       ccs_rl.search_buffer[ccs_current_screen] = line;
        line = NULL;
        index = -1;
 start_search:
@@ -1741,7 +2323,7 @@ start_search:
        while (true) {
                const char *cp;
                if (forward) {
-                       if (++index >= ccs_list_item_count[ccs_current_screen])
+                       if (++index >= ccs_list_item_count)
                                break;
                } else {
                        if (--index < 0)
@@ -1751,17 +2333,19 @@ start_search:
                        if (ccs_domain_sort_type)
                                cp = ccs_task_list[index].name;
                        else
-                               cp = ccs_get_last_name(dp, index);
+                               cp = ccs_get_last_name(index);
                } else if (ccs_current_screen == CCS_SCREEN_PROFILE_LIST) {
                        cp = ccs_shprintf("%u-%s",
-                                         ccs_generic_acl_list[index].directive,
-                                         ccs_generic_acl_list[index].operand);
+                                         ccs_gacl_list[index].directive,
+                                         ccs_gacl_list[index].operand);
                } else {
-                       const u16 directive = ccs_generic_acl_list[index].directive;
-                       cp = ccs_shprintf("%s %s", ccs_directives[directive].alias,
-                                         ccs_generic_acl_list[index].operand);
+                       const enum ccs_editpolicy_directives directive =
+                               ccs_gacl_list[index].directive;
+                       cp = ccs_shprintf("%s %s",
+                                         ccs_directives[directive].alias,
+                                         ccs_gacl_list[index].operand);
                }
-               if (!strstr(cp, rl->search_buffer[ccs_current_screen]))
+               if (!strstr(cp, ccs_rl.search_buffer[ccs_current_screen]))
                        continue;
                ccs_set_cursor_pos(index);
                break;
@@ -1769,18 +2353,25 @@ start_search:
        ccs_put();
 out:
        free(line);
-       ccs_show_list(dp);
+       ccs_show_list();
 }
 
-static void ccs_set_profile(struct ccs_domain_policy *dp, const int current)
+/**
+ * ccs_set_profile - Change profile number.
+ *
+ * @current: Currently selected line in the generic list.
+ *
+ * Returns nothing.
+ */
+static void ccs_set_profile(const int current)
 {
        int index;
        FILE *fp;
        char *line;
 #ifndef __GPET
        if (!ccs_domain_sort_type) {
-               if (!ccs_count(dp->list_selected, dp->list_len) &&
-                   !ccs_select_item(dp, current)) {
+               if (!ccs_count(ccs_dp.list_selected, ccs_dp.list_len) &&
+                   !ccs_select_item(current)) {
                        move(1, 0);
                        printw("Select domain using Space key first.");
                        clrtoeol();
@@ -1789,7 +2380,7 @@ static void ccs_set_profile(struct ccs_domain_policy *dp, const int current)
                }
        } else {
                if (!ccs_count3(ccs_task_list, ccs_task_list_len) &&
-                   !ccs_select_item(dp, current)) {
+                   !ccs_select_item(current)) {
                        move(1, 0);
                        printw("Select processes using Space key first.");
                        clrtoeol();
@@ -1810,11 +2401,11 @@ static void ccs_set_profile(struct ccs_domain_policy *dp, const int current)
        if (!fp)
                goto out;
        if (!ccs_domain_sort_type) {
-               for (index = 0; index < dp->list_len; index++) {
-                       if (!dp->list_selected[index])
+               for (index = 0; index < ccs_dp.list_len; index++) {
+                       if (!ccs_dp.list_selected[index])
                                continue;
                        fprintf(fp, "select domain=%s\n" "use_profile %s\n",
-                               ccs_domain_name(dp, index), line);
+                               ccs_domain_name(&ccs_dp, index), line);
                }
        } else {
                for (index = 0; index < ccs_task_list_len; index++) {
@@ -1829,21 +2420,28 @@ out:
        free(line);
 }
 
-static void ccs_set_level(struct ccs_domain_policy *dp, const int current)
+/**
+ * ccs_set_level - Change profiles.
+ *
+ * @current: Currently selected line in the generic list.
+ *
+ * Returns nothing.
+ */
+static void ccs_set_level(const int current)
 {
        int index;
        FILE *fp;
        char *line;
 #ifndef __GPET
-       if (!ccs_count2(ccs_generic_acl_list, ccs_generic_acl_list_count))
-               ccs_select_item(dp, current);
+       if (!ccs_count2(ccs_gacl_list, ccs_gacl_list_count))
+               ccs_select_item(current);
        ccs_editpolicy_attr_change(A_BOLD, true);  /* add color */
        ccs_initial_readline_data = NULL;
-       for (index = 0; index < ccs_generic_acl_list_count; index++) {
+       for (index = 0; index < ccs_gacl_list_count; index++) {
                char *cp;
-               if (!ccs_generic_acl_list[index].selected)
+               if (!ccs_gacl_list[index].selected)
                        continue;
-               cp = strchr(ccs_generic_acl_list[index].operand, '=');
+               cp = strchr(ccs_gacl_list[index].operand, '=');
                if (!cp)
                        continue;
                ccs_initial_readline_data = cp + 1;
@@ -1861,18 +2459,18 @@ static void ccs_set_level(struct ccs_domain_policy *dp, const int current)
        fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_PROFILE);
        if (!fp)
                goto out;
-       for (index = 0; index < ccs_generic_acl_list_count; index++) {
+       for (index = 0; index < ccs_gacl_list_count; index++) {
                char *buf;
                char *cp;
-               u16 directive;
-               if (!ccs_generic_acl_list[index].selected)
+               enum ccs_editpolicy_directives directive;
+               if (!ccs_gacl_list[index].selected)
                        continue;
                ccs_get();
-               buf = ccs_shprintf("%s", ccs_generic_acl_list[index].operand);
+               buf = ccs_shprintf("%s", ccs_gacl_list[index].operand);
                cp = strchr(buf, '=');
                if (cp)
                        *cp = '\0';
-               directive = ccs_generic_acl_list[index].directive;
+               directive = ccs_gacl_list[index].directive;
                if (directive < 256)
                        fprintf(fp, "%u-", directive);
                fprintf(fp, "%s=%s\n", buf, line);
@@ -1883,14 +2481,21 @@ out:
        free(line);
 }
 
-static void ccs_set_quota(struct ccs_domain_policy *dp, const int current)
+/**
+ * ccs_set_quota - Set memory quota.
+ *
+ * @current: Currently selected line in the generic list.
+ *
+ * Returns nothing.
+ */
+static void ccs_set_quota(const int current)
 {
        int index;
        FILE *fp;
        char *line;
 #ifndef __GPET
-       if (!ccs_count2(ccs_generic_acl_list, ccs_generic_acl_list_count))
-               ccs_select_item(dp, current);
+       if (!ccs_count2(ccs_gacl_list, ccs_gacl_list_count))
+               ccs_select_item(current);
        ccs_editpolicy_attr_change(A_BOLD, true);  /* add color */
        line = ccs_readline(ccs_window_height - 1, 0, "Enter new value> ",
                            NULL, 0, 20, 1);
@@ -1900,16 +2505,16 @@ static void ccs_set_quota(struct ccs_domain_policy *dp, const int current)
 #endif
        if (!line || !*line)
                goto out;
-       fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_MEMINFO);
+       fp = ccs_editpolicy_open_write(CCS_PROC_POLICY_STAT);
        if (!fp)
                goto out;
-       for (index = 0; index < ccs_generic_acl_list_count; index++) {
+       for (index = 0; index < ccs_gacl_list_count; index++) {
                char *buf;
                char *cp;
-               if (!ccs_generic_acl_list[index].selected)
+               if (!ccs_gacl_list[index].selected)
                        continue;
                ccs_get();
-               buf = ccs_shprintf("%s", ccs_generic_acl_list[index].operand);
+               buf = ccs_shprintf("%s", ccs_gacl_list[index].operand);
                cp = strchr(buf, ':');
                if (cp)
                        *cp = '\0';
@@ -1921,57 +2526,70 @@ out:
        free(line);
 }
 
-static _Bool ccs_select_acl_window(struct ccs_domain_policy *dp, const int current,
-                                  const _Bool may_refresh)
+/**
+ * ccs_select_acl_window - Check whether to switch to ACL list or not.
+ *
+ * @current: Index in the domain policy.
+ *
+ * Returns true if next window is ACL list, false otherwise.
+ */
+static _Bool ccs_select_acl_window(const int current)
 {
+       char *old_domain;
        if (ccs_current_screen != CCS_SCREEN_DOMAIN_LIST || current == EOF)
                return false;
        ccs_current_pid = 0;
        if (ccs_domain_sort_type) {
                ccs_current_pid = ccs_task_list[current].pid;
-       } else if (ccs_initializer_source(dp, current)) {
-               int redirect_index;
-               if (!may_refresh)
-                       return false;
-               redirect_index = ccs_find_target_domain(dp, current);
+       } else if (ccs_initializer_source(current)) {
+               struct ccs_screen *ptr = &ccs_screen[ccs_current_screen];
+               const int redirect_index = ccs_find_target_domain(current);
                if (redirect_index == EOF)
                        return false;
-               ccs_current_item_index[ccs_current_screen]
-                       = redirect_index - ccs_current_y[ccs_current_screen];
-               while (ccs_current_item_index[ccs_current_screen] < 0) {
-                       ccs_current_item_index[ccs_current_screen]++;
-                       ccs_current_y[ccs_current_screen]--;
+               ptr->current = redirect_index - ptr->y;
+               while (ptr->current < 0) {
+                       ptr->current++;
+                       ptr->y--;
                }
-               ccs_show_list(dp);
+               ccs_show_list();
                return false;
-       } else if (ccs_deleted_domain(dp, current)) {
+       } else if (ccs_deleted_domain(current)) {
                return false;
        }
-       free(ccs_current_domain);
+       old_domain = ccs_current_domain;
        if (ccs_domain_sort_type)
                ccs_current_domain = strdup(ccs_task_list[current].domain);
        else
-               ccs_current_domain = strdup(ccs_domain_name(dp, current));
+               ccs_current_domain = strdup(ccs_domain_name(&ccs_dp, current));
        if (!ccs_current_domain)
                ccs_out_of_memory();
+       ccs_no_restore_cursor = old_domain &&
+               strcmp(old_domain, ccs_current_domain);
+       free(old_domain);
        return true;
 }
 
-static int ccs_select_window(struct ccs_domain_policy *dp, const int current)
+/**
+ * ccs_select_window - Switch window.
+ *
+ * @current: Index in the domain policy.
+ *
+ * Returns next window to display.
+ */
+static enum ccs_screen_type ccs_select_window(const int current)
 {
        move(0, 0);
        printw("Press one of below keys to switch window.\n\n");
        printw("e     <<< Exception Policy Editor >>>\n");
        printw("d     <<< Domain Transition Editor >>>\n");
        if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST && current != EOF &&
-           !ccs_initializer_source(dp, current) &&
-           !ccs_deleted_domain(dp, current))
+           !ccs_initializer_source(current) && !ccs_deleted_domain(current))
                printw("a     <<< Domain Policy Editor >>>\n");
        printw("p     <<< Profile Editor >>>\n");
        printw("m     <<< Manager Policy Editor >>>\n");
        if (!ccs_offline_mode) {
                /* printw("i     <<< Interactive Enforcing Mode >>>\n"); */
-               printw("u     <<< Memory Usage >>>\n");
+               printw("s     <<< Statistics >>>\n");
        }
        printw("q     Quit this editor.\n");
        clrtobot();
@@ -1983,7 +2601,7 @@ static int ccs_select_window(struct ccs_domain_policy *dp, const int current)
                if (c == 'D' || c == 'd')
                        return CCS_SCREEN_DOMAIN_LIST;
                if (c == 'A' || c == 'a')
-                       if (ccs_select_acl_window(dp, current, false))
+                       if (ccs_select_acl_window(current))
                                return CCS_SCREEN_ACL_LIST;
                if (c == 'P' || c == 'p')
                        return CCS_SCREEN_PROFILE_LIST;
@@ -1994,8 +2612,8 @@ static int ccs_select_window(struct ccs_domain_policy *dp, const int current)
                        if (c == 'I' || c == 'i')
                                return CCS_SCREEN_QUERY_LIST;
                        */
-                       if (c == 'U' || c == 'u')
-                               return CCS_SCREEN_MEMINFO_LIST;
+                       if (c == 'S' || c == 's')
+                               return CCS_SCREEN_STAT_LIST;
                }
                if (c == 'Q' || c == 'q')
                        return CCS_MAXSCREEN;
@@ -2004,78 +2622,92 @@ static int ccs_select_window(struct ccs_domain_policy *dp, const int current)
        }
 }
 
-static void ccs_copy_mark_state(struct ccs_domain_policy *dp, const int current)
+/**
+ * ccs_copy_mark_state - Copy selected state to lines under the current line.
+ *
+ * @current: Index in the domain policy.
+ *
+ * Returns nothing.
+ */
+static void ccs_copy_mark_state(const int current)
 {
        int index;
        if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
                if (ccs_domain_sort_type) {
                        const u8 selected = ccs_task_list[current].selected;
-                       for (index = current; index < ccs_task_list_len; index++)
+                       for (index = current; index < ccs_task_list_len;
+                            index++)
                                ccs_task_list[index].selected = selected;
                } else {
-                       const u8 selected = dp->list_selected[current];
-                       if (ccs_deleted_domain(dp, current) ||
-                           ccs_initializer_source(dp, current))
+                       const u8 selected = ccs_dp.list_selected[current];
+                       if (ccs_deleted_domain(current) ||
+                           ccs_initializer_source(current))
                                return;
-                       for (index = current;
-                            index < dp->list_len; index++) {
-                               if (ccs_deleted_domain(dp, index) ||
-                                   ccs_initializer_source(dp, index))
+                       for (index = current; index < ccs_dp.list_len;
+                            index++) {
+                               if (ccs_deleted_domain(index) ||
+                                   ccs_initializer_source(index))
                                        continue;
-                               dp->list_selected[index] = selected;
+                               ccs_dp.list_selected[index] = selected;
                        }
                }
        } else {
-               const u8 selected = ccs_generic_acl_list[current].selected;
-               for (index = current; index < ccs_generic_acl_list_count; index++)
-                       ccs_generic_acl_list[index].selected = selected;
+               const u8 selected = ccs_gacl_list[current].selected;
+               for (index = current; index < ccs_gacl_list_count;
+                    index++)
+                       ccs_gacl_list[index].selected = selected;
        }
-       ccs_show_list(dp);
+       ccs_show_list();
 }
 
-static void ccs_copy_to_history(struct ccs_domain_policy *dp, const int current,
-                               struct ccs_readline_data *rl)
+/**
+ * ccs_copy_to_history - Copy line to histoy buffer.
+ *
+ * @current: Index in the domain policy.
+ *
+ * Returns nothing.
+ */
+static void ccs_copy_to_history(const int current)
 {
        const char *line;
        if (current == EOF)
                return;
        ccs_get();
        switch (ccs_current_screen) {
-               u16 directive;
+               enum ccs_editpolicy_directives directive;
        case CCS_SCREEN_DOMAIN_LIST:
-               line = ccs_domain_name(dp, current);
+               line = ccs_domain_name(&ccs_dp, current);
                break;
        case CCS_SCREEN_EXCEPTION_LIST:
        case CCS_SCREEN_ACL_LIST:
-               directive = ccs_generic_acl_list[current].directive;
+               directive = ccs_gacl_list[current].directive;
                line = ccs_shprintf("%s %s", ccs_directives[directive].alias,
-                               ccs_generic_acl_list[current].operand);
+                               ccs_gacl_list[current].operand);
                break;
-       case CCS_SCREEN_MEMINFO_LIST:
+       case CCS_SCREEN_STAT_LIST:
                line = NULL;
                break;
        default:
-               line = ccs_shprintf("%s", ccs_generic_acl_list[current].operand);
+               line = ccs_shprintf("%s",
+                                   ccs_gacl_list[current].operand);
        }
-       rl->count = ccs_add_history(line, rl->history, rl->count, rl->max);
+       ccs_rl.count = ccs_add_history(line, ccs_rl.history, ccs_rl.count,
+                                      ccs_rl.max);
        ccs_put();
 }
 
-static int ccs_generic_list_loop(struct ccs_domain_policy *dp)
+/**
+ * ccs_generic_list_loop - Main loop.
+ *
+ * Returns next screen to display.
+ */
+static enum ccs_screen_type ccs_generic_list_loop(void)
 {
-       static struct ccs_readline_data rl;
-       static int saved_current_y[CCS_MAXSCREEN];
-       static int saved_current_item_index[CCS_MAXSCREEN];
-       static _Bool first = true;
-       if (first) {
-               memset(&rl, 0, sizeof(rl));
-               rl.max = 20;
-               rl.history = malloc(rl.max * sizeof(const char *));
-               memset(saved_current_y, 0, sizeof(saved_current_y));
-               memset(saved_current_item_index, 0,
-                      sizeof(saved_current_item_index));
-               first = false;
-       }
+       struct ccs_screen *ptr;
+       static struct {
+               int y;
+               int current;
+       } saved_cursor[CCS_MAXSCREEN] = { };
        if (ccs_current_screen == CCS_SCREEN_EXCEPTION_LIST) {
                ccs_policy_file = CCS_PROC_POLICY_EXCEPTION_POLICY;
                ccs_list_caption = "Exception Policy Editor";
@@ -2091,34 +2723,40 @@ static int ccs_generic_list_loop(struct ccs_domain_policy *dp)
        } else if (ccs_current_screen == CCS_SCREEN_MANAGER_LIST) {
                ccs_policy_file = CCS_PROC_POLICY_MANAGER;
                ccs_list_caption = "Manager Policy Editor";
-       } else if (ccs_current_screen == CCS_SCREEN_MEMINFO_LIST) {
-               ccs_policy_file = CCS_PROC_POLICY_MEMINFO;
-               ccs_list_caption = "Memory Usage";
+       } else if (ccs_current_screen == CCS_SCREEN_STAT_LIST) {
+               ccs_policy_file = CCS_PROC_POLICY_STAT;
+               ccs_list_caption = "Statistics";
        } else {
                ccs_policy_file = CCS_PROC_POLICY_DOMAIN_POLICY;
                /* ccs_list_caption = "Domain Transition Editor"; */
        }
-       ccs_current_item_index[ccs_current_screen]
-               = saved_current_item_index[ccs_current_screen];
-       ccs_current_y[ccs_current_screen] = saved_current_y[ccs_current_screen];
+       ptr = &ccs_screen[ccs_current_screen];
+       if (ccs_no_restore_cursor) {
+               ptr->current = 0;
+               ptr->y = 0;
+               ccs_no_restore_cursor = false;
+       } else {
+               ptr->current = saved_cursor[ccs_current_screen].current;
+               ptr->y = saved_cursor[ccs_current_screen].y;
+       }
 start:
        if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST) {
-               if (ccs_domain_sort_type == 0) {
-                       ccs_read_domain_and_exception_policy(dp);
-                       ccs_adjust_cursor_pos(dp->list_len);
+               if (!ccs_domain_sort_type) {
+                       ccs_read_domain_and_exception_policy();
+                       ccs_adjust_cursor_pos(ccs_dp.list_len);
                } else {
                        ccs_read_process_list(true);
                        ccs_adjust_cursor_pos(ccs_task_list_len);
                }
        } else {
                ccs_read_generic_policy();
-               ccs_adjust_cursor_pos(ccs_generic_acl_list_count);
+               ccs_adjust_cursor_pos(ccs_gacl_list_count);
        }
 #ifdef __GPET
        return 0;
 #else
 start2:
-       ccs_show_list(dp);
+       ccs_show_list();
        if (ccs_last_error) {
                move(1, 0);
                printw("ERROR: %s", ccs_last_error);
@@ -2130,9 +2768,8 @@ start2:
        while (true) {
                const int current = ccs_editpolicy_get_current();
                const int c = ccs_getch2();
-               saved_current_item_index[ccs_current_screen]
-                       = ccs_current_item_index[ccs_current_screen];
-               saved_current_y[ccs_current_screen] = ccs_current_y[ccs_current_screen];
+               saved_cursor[ccs_current_screen].current = ptr->current;
+               saved_cursor[ccs_current_screen].y = ptr->y;
                if (c == 'q' || c == 'Q')
                        return CCS_MAXSCREEN;
                if ((c == '\r' || c == '\n') &&
@@ -2153,52 +2790,52 @@ start2:
                switch (c) {
                case KEY_RESIZE:
                        ccs_resize_window();
-                       ccs_show_list(dp);
+                       ccs_show_list();
                        break;
                case KEY_UP:
-                       ccs_up_arrow_key(dp);
+                       ccs_up_arrow_key();
                        break;
                case KEY_DOWN:
-                       ccs_down_arrow_key(dp);
+                       ccs_down_arrow_key();
                        break;
                case KEY_PPAGE:
-                       ccs_page_up_key(dp);
+                       ccs_page_up_key();
                        break;
                case KEY_NPAGE:
-                       ccs_page_down_key(dp);
+                       ccs_page_down_key();
                        break;
                case ' ':
-                       ccs_select_item(dp, current);
+                       ccs_select_item(current);
                        break;
                case 'c':
                case 'C':
                        if (current == EOF)
                                break;
-                       ccs_copy_mark_state(dp, current);
-                       ccs_show_list(dp);
+                       ccs_copy_mark_state(current);
+                       ccs_show_list();
                        break;
                case 'f':
                case 'F':
-                       if (ccs_current_screen != CCS_SCREEN_MEMINFO_LIST)
-                               ccs_find_entry(dp, true, true, current, &rl);
+                       if (ccs_current_screen != CCS_SCREEN_STAT_LIST)
+                               ccs_find_entry(true, true, current);
                        break;
                case 'p':
                case 'P':
-                       if (ccs_current_screen == CCS_SCREEN_MEMINFO_LIST)
+                       if (ccs_current_screen == CCS_SCREEN_STAT_LIST)
                                break;
-                       if (!rl.search_buffer[ccs_current_screen])
-                               ccs_find_entry(dp, true, false, current, &rl);
+                       if (!ccs_rl.search_buffer[ccs_current_screen])
+                               ccs_find_entry(true, false, current);
                        else
-                               ccs_find_entry(dp, false, false, current, &rl);
+                               ccs_find_entry(false, false, current);
                        break;
                case 'n':
                case 'N':
-                       if (ccs_current_screen == CCS_SCREEN_MEMINFO_LIST)
+                       if (ccs_current_screen == CCS_SCREEN_STAT_LIST)
                                break;
-                       if (!rl.search_buffer[ccs_current_screen])
-                               ccs_find_entry(dp, true, true, current, &rl);
+                       if (!ccs_rl.search_buffer[ccs_current_screen])
+                               ccs_find_entry(true, true, current);
                        else
-                               ccs_find_entry(dp, false, true, current, &rl);
+                               ccs_find_entry(false, true, current);
                        break;
                case 'd':
                case 'D':
@@ -2211,8 +2848,10 @@ start2:
                        case CCS_SCREEN_EXCEPTION_LIST:
                        case CCS_SCREEN_ACL_LIST:
                        case CCS_SCREEN_MANAGER_LIST:
-                               ccs_delete_entry(dp, current);
+                               ccs_delete_entry(current);
                                goto start;
+                       default:
+                               break;
                        }
                        break;
                case 'a':
@@ -2227,13 +2866,15 @@ start2:
                        case CCS_SCREEN_ACL_LIST:
                        case CCS_SCREEN_PROFILE_LIST:
                        case CCS_SCREEN_MANAGER_LIST:
-                               ccs_add_entry(&rl);
+                               ccs_add_entry();
                                goto start;
+                       default:
+                               break;
                        }
                        break;
                case '\r':
                case '\n':
-                       if (ccs_select_acl_window(dp, current, true))
+                       if (ccs_select_acl_window(current))
                                return CCS_SCREEN_ACL_LIST;
                        break;
                case 's':
@@ -2242,62 +2883,68 @@ start2:
                                break;
                        switch (ccs_current_screen) {
                        case CCS_SCREEN_DOMAIN_LIST:
-                               ccs_set_profile(dp, current);
+                               ccs_set_profile(current);
                                goto start;
                        case CCS_SCREEN_PROFILE_LIST:
-                               ccs_set_level(dp, current);
+                               ccs_set_level(current);
                                goto start;
-                       case CCS_SCREEN_MEMINFO_LIST:
-                               ccs_set_quota(dp, current);
+                       case CCS_SCREEN_STAT_LIST:
+                               ccs_set_quota(current);
                                goto start;
+                       default:
+                               break;
                        }
                        break;
                case 'r':
                case 'R':
                        goto start;
                case KEY_LEFT:
-                       if (!ccs_max_eat_col[ccs_current_screen])
+                       if (!ptr->x)
                                break;
-                       ccs_max_eat_col[ccs_current_screen]--;
+                       ptr->x--;
                        goto start2;
                case KEY_RIGHT:
-                       ccs_max_eat_col[ccs_current_screen]++;
+                       ptr->x++;
                        goto start2;
                case KEY_HOME:
-                       ccs_max_eat_col[ccs_current_screen] = 0;
+                       ptr->x = 0;
                        goto start2;
                case KEY_END:
-                       ccs_max_eat_col[ccs_current_screen] = ccs_max_col;
+                       ptr->x = ccs_max_col;
                        goto start2;
                case KEY_IC:
-                       ccs_copy_to_history(dp, current, &rl);
+                       ccs_copy_to_history(current);
                        break;
                case 'o':
                case 'O':
                        if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
-                               ccs_editpolicy_try_optimize(dp, current,
-                                                           ccs_current_screen);
-                               ccs_show_list(dp);
+                               ccs_editpolicy_optimize(current);
+                               ccs_show_list();
                        }
                        break;
                case '@':
-                       if (ccs_current_screen == CCS_SCREEN_ACL_LIST) {
-                               ccs_acl_sort_type = (ccs_acl_sort_type + 1) % 2;
+                       switch (ccs_current_screen) {
+                       case CCS_SCREEN_ACL_LIST:
+                               ccs_acl_sort_type = !ccs_acl_sort_type;
                                goto start;
-                       } else if (ccs_current_screen == CCS_SCREEN_PROFILE_LIST) {
-                               ccs_profile_sort_type = (ccs_profile_sort_type + 1) % 2;
+                       case CCS_SCREEN_PROFILE_LIST:
+                               ccs_profile_sort_type = !ccs_profile_sort_type;
                                goto start;
-                       } else if (ccs_current_screen == CCS_SCREEN_DOMAIN_LIST &&
-                                  !ccs_offline_mode) {
-                               ccs_domain_sort_type = (ccs_domain_sort_type + 1) % 2;
+                       case CCS_SCREEN_DOMAIN_LIST:
+                               if (ccs_offline_mode)
+                                       break;
+                               ccs_domain_sort_type = !ccs_domain_sort_type;
                                goto start;
+                       default:
+                               break;
                        }
                        break;
                case 'w':
                case 'W':
-                       return ccs_select_window(dp, current);
+                       return ccs_select_window(current);
                case '?':
-                       if (ccs_show_command_key(ccs_current_screen, ccs_readonly_mode))
+                       if (ccs_show_command_key(ccs_current_screen,
+                                                ccs_readonly_mode))
                                goto start;
                        return CCS_MAXSCREEN;
                }
@@ -2305,6 +2952,14 @@ start2:
 #endif /* __GPET */
 }
 
+/**
+ * ccs_save_to_file - Save policy to file.
+ *
+ * @src: Filename to read from.
+ * @dest: Filename to write to.
+ *
+ * Returns true on success, false otherwise.
+ */
 static _Bool ccs_save_to_file(const char *src, const char *dest)
 {
        FILE *proc_fp = ccs_editpolicy_open_read(src);
@@ -2325,6 +2980,167 @@ static _Bool ccs_save_to_file(const char *src, const char *dest)
        return true;
 }
 
+/**
+ * ccs_parse_args - Parse command line arguments.
+ *
+ * @argc: argc passed to main().
+ * @argv: argv passed to main().
+ *
+ * Returns nothing.
+ */
+static void ccs_parse_args(int argc, char *argv[])
+{
+       int i;
+       for (i = 1; i < argc; i++) {
+               char *ptr = argv[i];
+               char *cp = strchr(ptr, ':');
+               if (*ptr == '/') {
+                       if (ccs_network_mode || ccs_offline_mode)
+                               goto usage;
+                       ccs_policy_dir = ptr;
+                       ccs_offline_mode = true;
+               } else if (cp) {
+                       *cp++ = '\0';
+                       if (ccs_network_mode || ccs_offline_mode)
+                               goto usage;
+                       ccs_network_ip = inet_addr(ptr);
+                       ccs_network_port = htons(atoi(cp));
+                       ccs_network_mode = true;
+                       if (!ccs_check_remote_host())
+                               exit(1);
+               } else if (!strcmp(ptr, "e"))
+                       ccs_current_screen = CCS_SCREEN_EXCEPTION_LIST;
+               else if (!strcmp(ptr, "d"))
+                       ccs_current_screen = CCS_SCREEN_DOMAIN_LIST;
+               else if (!strcmp(ptr, "p"))
+                       ccs_current_screen = CCS_SCREEN_PROFILE_LIST;
+               else if (!strcmp(ptr, "m"))
+                       ccs_current_screen = CCS_SCREEN_MANAGER_LIST;
+               else if (!strcmp(ptr, "s"))
+                       ccs_current_screen = CCS_SCREEN_STAT_LIST;
+               else if (!strcmp(ptr, "readonly"))
+                       ccs_readonly_mode = true;
+               else if (sscanf(ptr, "refresh=%u", &ccs_refresh_interval)
+                        != 1) {
+usage:
+                       printf("Usage: %s [e|d|p|m|s] [readonly] "
+                              "[refresh=interval] "
+                              "[{policy_dir|remote_ip:remote_port}]\n",
+                              argv[0]);
+                       exit(1);
+               }
+       }
+}
+
+/**
+ * ccs_load_offline - Load policy for offline mode.
+ *
+ * Returns nothing.
+ */
+static void ccs_load_offline(void)
+{
+       int fd[2] = { EOF, EOF };
+       if (chdir(ccs_policy_dir) || chdir("policy/current/")) {
+               fprintf(stderr, "Directory %s/policy/current/ doesn't "
+                       "exist.\n", ccs_policy_dir);
+               exit(1);
+       }
+       if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) {
+               fprintf(stderr, "socketpair()\n");
+               exit(1);
+       }
+       switch (fork()) {
+       case 0:
+               close(fd[0]);
+               ccs_persistent_fd = fd[1];
+               ccs_editpolicy_offline_daemon();
+               _exit(0);
+       case -1:
+               fprintf(stderr, "fork()\n");
+               exit(1);
+       }
+       close(fd[1]);
+       ccs_persistent_fd = fd[0];
+       ccs_copy_file("exception_policy.conf",
+                     CCS_PROC_POLICY_EXCEPTION_POLICY);
+       ccs_copy_file("domain_policy.conf", CCS_PROC_POLICY_DOMAIN_POLICY);
+       ccs_copy_file("profile.conf", CCS_PROC_POLICY_PROFILE);
+       ccs_copy_file("manager.conf", CCS_PROC_POLICY_MANAGER);
+       if (chdir("..")) {
+               fprintf(stderr, "Directory %s/policy/ doesn't exist.\n",
+                       ccs_policy_dir);
+               exit(1);
+       }
+}
+
+/**
+ * ccs_load_readwrite - Check that this program can write to /proc/ccs/ interface.
+ *
+ * Returns nothing.
+ */
+static void ccs_load_readwrite(void)
+{
+       const int fd1 = ccs_open2(CCS_PROC_POLICY_EXCEPTION_POLICY, O_RDWR);
+       const int fd2 = ccs_open2(CCS_PROC_POLICY_DOMAIN_POLICY, O_RDWR);
+       if ((fd1 != EOF && write(fd1, "", 0) != 0) ||
+           (fd2 != EOF && write(fd2, "", 0) != 0)) {
+               fprintf(stderr, "In order to run this program, it must be "
+                       "registered to %s . "
+                       "Please reboot.\n", CCS_PROC_POLICY_MANAGER);
+               exit(1);
+       }
+       close(fd1);
+       close(fd2);
+}
+
+/**
+ * ccs_save_offline - Save policy for offline mode.
+ *
+ * Returns nothing.
+ */
+static void ccs_save_offline(void)
+{
+       time_t now = time(NULL);
+       static char stamp[32] = { };
+       while (1) {
+               struct tm *tm = localtime(&now);
+               snprintf(stamp, sizeof(stamp) - 1,
+                        "%02d-%02d-%02d.%02d:%02d:%02d/",
+                        tm->tm_year % 100, tm->tm_mon + 1, tm->tm_mday,
+                        tm->tm_hour, tm->tm_min, tm->tm_sec);
+               if (!mkdir(stamp, 0700))
+                       break;
+               else if (errno == EEXIST)
+                       now++;
+               else {
+                       fprintf(stderr, "Can't create %s/%s .\n",
+                               ccs_policy_dir, stamp);
+                       exit(1);
+               }
+       }
+       if ((symlink("policy/current/profile.conf", "../profile.conf") &&
+            errno != EEXIST) ||
+           (symlink("policy/current/manager.conf", "../manager.conf") &&
+            errno != EEXIST) ||
+           (symlink("policy/current/exception_policy.conf",
+                    "../exception_policy.conf") && errno != EEXIST) ||
+           (symlink("policy/current/domain_policy.conf",
+                    "../domain_policy.conf") && errno != EEXIST) ||
+           chdir(stamp) ||
+           !ccs_save_to_file(CCS_PROC_POLICY_PROFILE, "profile.conf") ||
+           !ccs_save_to_file(CCS_PROC_POLICY_MANAGER, "manager.conf") ||
+           !ccs_save_to_file(CCS_PROC_POLICY_EXCEPTION_POLICY,
+                             "exception_policy.conf") ||
+           !ccs_save_to_file(CCS_PROC_POLICY_DOMAIN_POLICY,
+                             "domain_policy.conf") ||
+           chdir("..") ||
+           (rename("current", "previous") && errno != ENOENT) ||
+           symlink(stamp, "current")) {
+               fprintf(stderr, "Failed to save policy.\n");
+               exit(1);
+       }
+}
+
 #ifdef __GPET  /* gpet */
 int gpet_main(void);
 int ccs_main(int argc, char *argv[])
@@ -2332,106 +3148,22 @@ int ccs_main(int argc, char *argv[])
 int main(int argc, char *argv[])
 #endif /* gpet */
 {
-       struct ccs_domain_policy dp = { NULL, 0, NULL };
-       struct ccs_domain_policy bp = { NULL, 0, NULL };
-       memset(ccs_current_y, 0, sizeof(ccs_current_y));
-       memset(ccs_current_item_index, 0, sizeof(ccs_current_item_index));
-       memset(ccs_list_item_count, 0, sizeof(ccs_list_item_count));
-       memset(ccs_max_eat_col, 0, sizeof(ccs_max_eat_col));
-       if (argc > 1) {
-               int i;
-               for (i = 1; i < argc; i++) {
-                       char *ptr = argv[i];
-                       char *cp = strchr(ptr, ':');
-                       if (*ptr == '/') {
-                               if (ccs_network_mode || ccs_offline_mode)
-                                       goto usage;
-                               ccs_policy_dir = ptr;
-                               ccs_offline_mode = true;
-                       } else if (cp) {
-                               *cp++ = '\0';
-                               if (ccs_network_mode || ccs_offline_mode)
-                                       goto usage;
-                               ccs_network_ip = inet_addr(ptr);
-                               ccs_network_port = htons(atoi(cp));
-                               ccs_network_mode = true;
-                               if (!ccs_check_remote_host())
-                                       return 1;
-                       } else if (!strcmp(ptr, "e"))
-                               ccs_current_screen = CCS_SCREEN_EXCEPTION_LIST;
-                       else if (!strcmp(ptr, "d"))
-                               ccs_current_screen = CCS_SCREEN_DOMAIN_LIST;
-                       else if (!strcmp(ptr, "p"))
-                               ccs_current_screen = CCS_SCREEN_PROFILE_LIST;
-                       else if (!strcmp(ptr, "m"))
-                               ccs_current_screen = CCS_SCREEN_MANAGER_LIST;
-                       else if (!strcmp(ptr, "u"))
-                               ccs_current_screen = CCS_SCREEN_MEMINFO_LIST;
-                       else if (!strcmp(ptr, "readonly"))
-                               ccs_readonly_mode = true;
-                       else if (sscanf(ptr, "refresh=%u", &ccs_refresh_interval)
-                                != 1) {
-usage:
-                               printf("Usage: %s [e|d|p|m|u] [readonly] "
-                                      "[refresh=interval] "
-                                      "[{policy_dir|remote_ip:remote_port}]\n",
-                                      argv[0]);
-                               return 1;
-                       }
-               }
-       }
+       ccs_parse_args(argc, argv);
        ccs_editpolicy_init_keyword_map();
        if (ccs_offline_mode) {
-               int fd[2] = { EOF, EOF };
-               if (chdir(ccs_policy_dir)) {
-                       printf("Directory %s doesn't exist.\n",
-                              ccs_policy_dir);
-                       return 1;
-               }
-               if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) {
-                       fprintf(stderr, "socketpair()\n");
-                       exit(1);
-               }
-               switch (fork()) {
-               case 0:
-                       close(fd[0]);
-                       ccs_persistent_fd = fd[1];
-                       ccs_editpolicy_offline_daemon();
-                       _exit(0);
-               case -1:
-                       fprintf(stderr, "fork()\n");
-                       exit(1);
-               }
-               close(fd[1]);
-               ccs_persistent_fd = fd[0];
-               ccs_copy_file(CCS_DISK_POLICY_EXCEPTION_POLICY,
-                             CCS_PROC_POLICY_EXCEPTION_POLICY);
-               ccs_copy_file(CCS_DISK_POLICY_DOMAIN_POLICY, CCS_PROC_POLICY_DOMAIN_POLICY);
-               ccs_copy_file(CCS_DISK_POLICY_PROFILE, CCS_PROC_POLICY_PROFILE);
-               ccs_copy_file(CCS_DISK_POLICY_MANAGER, CCS_PROC_POLICY_MANAGER);
-       } else if (!ccs_network_mode) {
-               if (chdir(CCS_PROC_POLICY_DIR)) {
-                       fprintf(stderr,
-                               "You can't use this editor for this kernel.\n");
-                       return 1;
-               }
-               if (!ccs_readonly_mode) {
-                       const int fd1 = ccs_open2(CCS_PROC_POLICY_EXCEPTION_POLICY,
-                                                 O_RDWR);
-                       const int fd2 = ccs_open2(CCS_PROC_POLICY_DOMAIN_POLICY,
-                                                 O_RDWR);
-                       if ((fd1 != EOF && write(fd1, "", 0) != 0) ||
-                           (fd2 != EOF && write(fd2, "", 0) != 0)) {
-                               fprintf(stderr,
-                                       "You need to register this program to "
-                                       "%s to run this program.\n",
-                                       CCS_PROC_POLICY_MANAGER);
-                               return 1;
-                       }
-                       close(fd1);
-                       close(fd2);
-               }
+               ccs_load_offline();
+               goto start;
+       }
+       if (ccs_network_mode)
+               goto start;
+       if (chdir(CCS_PROC_POLICY_DIR)) {
+               fprintf(stderr,
+                       "You can't use this editor for this kernel.\n");
+               return 1;
        }
+       if (!ccs_readonly_mode)
+               ccs_load_readwrite();
+start:
 #ifdef __GPET
        if (gpet_main())
                return 1;
@@ -2449,9 +3181,11 @@ usage:
                alarm(ccs_refresh_interval);
                timeout(1000);
        }
+       ccs_rl.max = 20;
+       ccs_rl.history = malloc(ccs_rl.max * sizeof(const char *));
        while (ccs_current_screen < CCS_MAXSCREEN) {
                ccs_resize_window();
-               ccs_current_screen = ccs_generic_list_loop(&dp);
+               ccs_current_screen = ccs_generic_list_loop();
        }
        alarm(0);
        clear();
@@ -2459,58 +3193,9 @@ usage:
        refresh();
        endwin();
 #endif /* __GPET */
-       if (ccs_offline_mode && !ccs_readonly_mode) {
-               int ret_ignored;
-               time_t now = time(NULL);
-               const char *filename = ccs_make_filename("exception_policy",
-                                                        now);
-               if (ccs_save_to_file(CCS_PROC_POLICY_EXCEPTION_POLICY,
-                                    filename)) {
-                       if (ccs_identical_file("exception_policy.conf",
-                                              filename)) {
-                               unlink(filename);
-                       } else {
-                               unlink("exception_policy.conf");
-                               ret_ignored = symlink(filename,
-                                                     "exception_policy.conf");
-                       }
-               }
-               ccs_clear_domain_policy(&dp);
-               filename = ccs_make_filename("domain_policy", now);
-               if (ccs_save_to_file(CCS_PROC_POLICY_DOMAIN_POLICY,
-                                    filename)) {
-                       if (ccs_identical_file("domain_policy.conf",
-                                              filename)) {
-                               unlink(filename);
-                       } else {
-                               unlink("domain_policy.conf");
-                               ret_ignored = symlink(filename,
-                                                     "domain_policy.conf");
-                       }
-               }
-               filename = ccs_make_filename("profile", now);
-               if (ccs_save_to_file(CCS_PROC_POLICY_PROFILE, filename)) {
-                       if (ccs_identical_file("profile.conf", filename)) {
-                               unlink(filename);
-                       } else {
-                               unlink("profile.conf");
-                               ret_ignored = symlink(filename,
-                                                     "profile.conf");
-                       }
-               }
-               filename = ccs_make_filename("manager", now);
-               if (ccs_save_to_file(CCS_PROC_POLICY_MANAGER, filename)) {
-                       if (ccs_identical_file("manager.conf", filename)) {
-                               unlink(filename);
-                       } else {
-                               unlink("manager.conf");
-                               ret_ignored = symlink(filename,
-                                                     "manager.conf");
-                       }
-               }
-       }
-       ccs_clear_domain_policy(&bp);
-       ccs_clear_domain_policy(&dp);
+       if (ccs_offline_mode && !ccs_readonly_mode)
+               ccs_save_offline();
+       ccs_clear_domain_policy(&ccs_dp);
        return 0;
 }