2005-08-18 21:27:20 +00:00
|
|
|
########################################
|
|
|
|
#
|
|
|
|
# Rules and Targets for building monolithic policies
|
|
|
|
#
|
|
|
|
|
2006-08-31 17:28:35 +00:00
|
|
|
# determine the policy version and current kernel version if possible
|
|
|
|
pv := $(shell $(CHECKPOLICY) -V |cut -f 1 -d ' ')
|
2013-06-06 13:27:40 +00:00
|
|
|
kv := $(shell $(policyvers))
|
2006-08-31 17:28:35 +00:00
|
|
|
|
|
|
|
# dont print version warnings if we are unable to determine
|
|
|
|
# the currently running kernel's policy version
|
|
|
|
ifeq "$(kv)" ""
|
|
|
|
kv := $(pv)
|
|
|
|
endif
|
|
|
|
|
2021-01-31 20:50:29 +00:00
|
|
|
# dont print version warnings if we specified a lower version than the kernel supports
|
|
|
|
ifneq "$(OUTPUT_POLICY)" ""
|
|
|
|
kv := $(shell if test $(kv) -gt $(pv); then echo $(pv); else echo $(kv); fi)
|
|
|
|
endif
|
|
|
|
|
2020-12-21 12:22:13 +00:00
|
|
|
# load_policy(8) loads policy from /etc/selinux/<SELINUXTYPE>/policy/policy.$(pv)
|
|
|
|
# It does this by reading the /etc/selinux/config file SELINUXTYPE entry to
|
|
|
|
# form the full path. $(polbinpath) will contain this evaluated path for use as
|
|
|
|
# a validation check.
|
|
|
|
polbinpath := $(shell $(binary_policy_path))
|
|
|
|
|
2006-08-31 17:28:35 +00:00
|
|
|
policy_conf = $(builddir)policy.conf
|
2022-03-22 17:10:11 +00:00
|
|
|
policy_cil = $(builddir)policy.cil
|
2006-08-31 17:28:35 +00:00
|
|
|
fc = $(builddir)file_contexts
|
|
|
|
polver = $(builddir)policy.$(pv)
|
|
|
|
homedir_template = $(builddir)homedir_template
|
2006-02-15 17:59:58 +00:00
|
|
|
|
2006-03-20 20:54:56 +00:00
|
|
|
M4PARAM += -D self_contained_policy
|
|
|
|
|
2005-08-18 21:27:20 +00:00
|
|
|
# install paths
|
2006-08-31 17:28:35 +00:00
|
|
|
loadpath = $(policypath)/$(notdir $(polver))
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2009-10-23 15:20:07 +00:00
|
|
|
appfiles += $(installdir)/booleans $(installdir)/seusers $(userpath)/local.users
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2005-11-22 22:07:12 +00:00
|
|
|
# for monolithic policy use all base and module to create policy
|
2006-08-31 17:28:35 +00:00
|
|
|
all_modules := $(strip $(base_mods) $(mod_mods))
|
2006-03-27 15:43:20 +00:00
|
|
|
# off module interfaces included to make sure all interfaces are expanded.
|
2006-08-31 17:28:35 +00:00
|
|
|
all_interfaces := $(all_modules:.te=.if) $(off_mods:.te=.if)
|
|
|
|
all_te_files := $(all_modules)
|
|
|
|
all_fc_files := $(all_modules:.te=.fc)
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2020-03-21 13:31:23 +00:00
|
|
|
pre_te_files := $(secclass) $(isids) $(avs) $(m4support) $(ctx_defaults) $(poldir)/mls $(poldir)/mcs $(policycaps)
|
2006-08-31 17:28:35 +00:00
|
|
|
post_te_files := $(user_files) $(poldir)/constraints
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2006-08-31 17:28:35 +00:00
|
|
|
policy_sections := $(tmpdir)/pre_te_files.conf $(tmpdir)/all_attrs_types.conf $(tmpdir)/global_bools.conf $(tmpdir)/only_te_rules.conf $(tmpdir)/all_post.conf
|
2005-11-22 22:07:12 +00:00
|
|
|
|
|
|
|
# search layer dirs for source files
|
2006-08-31 17:28:35 +00:00
|
|
|
vpath %.te $(all_layers)
|
|
|
|
vpath %.if $(all_layers)
|
|
|
|
vpath %.fc $(all_layers)
|
2005-11-22 22:07:12 +00:00
|
|
|
|
2005-08-18 21:27:20 +00:00
|
|
|
########################################
|
|
|
|
#
|
|
|
|
# default action: build policy locally
|
|
|
|
#
|
|
|
|
default: policy
|
|
|
|
|
2006-08-31 17:28:35 +00:00
|
|
|
policy: $(polver)
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2007-03-21 19:40:55 +00:00
|
|
|
install: $(loadpath) $(fcpath) $(appfiles)
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2006-08-31 17:28:35 +00:00
|
|
|
load: $(tmpdir)/load
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2006-08-31 17:28:35 +00:00
|
|
|
checklabels: $(fcpath)
|
|
|
|
restorelabels: $(fcpath)
|
|
|
|
relabel: $(fcpath)
|
|
|
|
resetlabels: $(fcpath)
|
2006-02-01 13:22:14 +00:00
|
|
|
|
2005-08-18 21:27:20 +00:00
|
|
|
########################################
|
|
|
|
#
|
|
|
|
# Build a binary policy locally
|
|
|
|
#
|
2006-08-31 17:28:35 +00:00
|
|
|
$(polver): $(policy_conf)
|
|
|
|
@echo "Compiling $(NAME) $(polver)"
|
|
|
|
ifneq ($(pv),$(kv))
|
2005-08-18 21:27:20 +00:00
|
|
|
@echo
|
2021-01-31 20:50:29 +00:00
|
|
|
@echo "WARNING: Policy version mismatch (policy:$(pv) kernel:$(kv))! Is your OUTPUT_POLICY set correctly?"
|
2005-08-18 21:27:20 +00:00
|
|
|
@echo
|
|
|
|
endif
|
2021-02-01 19:07:40 +00:00
|
|
|
$(verbose) $(CHECKPOLICY) -U $(UNK_PERMS) -S -O -E $^ -o $@
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2022-03-22 17:10:11 +00:00
|
|
|
########################################
|
|
|
|
#
|
|
|
|
# Build a CIL policy locally
|
|
|
|
#
|
|
|
|
$(policy_cil): $(policy_conf)
|
|
|
|
@echo "Compiling $(NAME) $(policy_cil)"
|
|
|
|
ifneq ($(pv),$(kv))
|
|
|
|
@echo
|
|
|
|
@echo "WARNING: Policy version mismatch (policy:$(pv) kernel:$(kv))! Is your OUTPUT_POLICY set correctly?"
|
|
|
|
@echo
|
|
|
|
endif
|
|
|
|
$(verbose) $(CHECKPOLICY) -C -U $(UNK_PERMS) -S -O -E $^ -o $@
|
|
|
|
|
2005-08-18 21:27:20 +00:00
|
|
|
########################################
|
|
|
|
#
|
|
|
|
# Install a binary policy
|
|
|
|
#
|
2006-08-31 17:28:35 +00:00
|
|
|
$(loadpath): $(policy_conf)
|
|
|
|
@echo "Compiling and installing $(NAME) $(loadpath)"
|
|
|
|
ifneq ($(pv),$(kv))
|
2005-08-18 21:27:20 +00:00
|
|
|
@echo
|
2021-01-31 20:50:29 +00:00
|
|
|
@echo "WARNING: Policy version mismatch (policy:$(pv) kernel:$(kv))! Is your OUTPUT_POLICY set correctly?"
|
2005-08-18 21:27:20 +00:00
|
|
|
@echo
|
|
|
|
endif
|
2011-10-19 14:59:16 +00:00
|
|
|
@$(INSTALL) -d -m 0755 $(@D)
|
2021-02-01 19:07:40 +00:00
|
|
|
$(verbose) $(CHECKPOLICY) -U $(UNK_PERMS) -S -O -E $^ -o $@
|
2005-08-18 21:27:20 +00:00
|
|
|
|
|
|
|
########################################
|
|
|
|
#
|
|
|
|
# Load the binary policy
|
|
|
|
#
|
2007-11-19 20:02:50 +00:00
|
|
|
reload $(tmpdir)/load: $(loadpath) $(fcpath) $(appfiles)
|
2020-12-21 12:22:13 +00:00
|
|
|
ifneq ($(DESTDIR),)
|
|
|
|
$(error Cannot load policy as '$$DESTDIR' is set to $(DESTDIR), \
|
|
|
|
creating an invalid policy load path)
|
|
|
|
endif
|
|
|
|
ifneq ($(polbinpath).$(pv),$(loadpath))
|
|
|
|
$(error Cannot load policy as invalid policy path: $(polbinpath).$(pv) - \
|
|
|
|
Check $(topdir)/config file entry is: "SELINUXTYPE=$(NAME)")
|
|
|
|
endif
|
2006-08-31 17:28:35 +00:00
|
|
|
@echo "Loading $(NAME) $(loadpath)"
|
2021-02-01 19:05:19 +00:00
|
|
|
$(verbose) $(LOADPOLICY)
|
2005-08-18 21:27:20 +00:00
|
|
|
|
|
|
|
########################################
|
|
|
|
#
|
|
|
|
# Construct a monolithic policy.conf
|
|
|
|
#
|
2006-08-31 17:28:35 +00:00
|
|
|
$(policy_conf): $(policy_sections)
|
2006-02-15 17:59:58 +00:00
|
|
|
@echo "Creating $(NAME) $(@F)"
|
2006-03-20 20:54:56 +00:00
|
|
|
@test -d $(@D) || mkdir -p $(@D)
|
|
|
|
$(verbose) cat $^ > $@
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2006-08-31 17:28:35 +00:00
|
|
|
$(tmpdir)/pre_te_files.conf: $(pre_te_files)
|
|
|
|
@test -d $(tmpdir) || mkdir -p $(tmpdir)
|
2006-03-20 20:54:56 +00:00
|
|
|
$(verbose) $(M4) $(M4PARAM) $^ > $@
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2006-08-31 17:28:35 +00:00
|
|
|
$(tmpdir)/generated_definitions.conf: $(all_te_files)
|
|
|
|
@test -d $(tmpdir) || mkdir -p $(tmpdir)
|
2006-03-21 20:23:29 +00:00
|
|
|
# define all available object classes
|
2020-04-16 00:40:58 +00:00
|
|
|
@cat $(m4divert) > $@
|
|
|
|
$(verbose) $(genperm) $(avs) $(secclass) >> $@
|
2006-09-06 22:07:25 +00:00
|
|
|
$(verbose) $(call create-base-per-role-tmpl,$(basename $(notdir $(all_modules))),$@)
|
2006-08-31 17:28:35 +00:00
|
|
|
$(verbose) test -f $(booleans) && $(setbools) $(booleans) >> $@ || true
|
2020-04-16 00:40:58 +00:00
|
|
|
@cat $(m4undivert) >> $@
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2006-08-31 17:28:35 +00:00
|
|
|
$(tmpdir)/global_bools.conf: $(m4support) $(tmpdir)/generated_definitions.conf $(globalbool) $(globaltun)
|
2006-03-20 20:54:56 +00:00
|
|
|
$(verbose) $(M4) $(M4PARAM) $^ > $@
|
|
|
|
|
2008-03-06 20:17:46 +00:00
|
|
|
$(tmpdir)/all_interfaces.conf: $(m4support) $(all_interfaces) $(m4iferror)
|
2006-08-31 17:28:35 +00:00
|
|
|
@test -d $(tmpdir) || mkdir -p $(tmpdir)
|
2020-04-16 00:40:58 +00:00
|
|
|
@cat $(m4divert) > $@
|
2020-04-20 14:22:38 +00:00
|
|
|
$(verbose) $(M4) $^ > $(tmpdir)/$(@F).tmp
|
2006-08-31 17:28:35 +00:00
|
|
|
$(verbose) $(SED) -e s/dollarsstar/\$$\*/g $(tmpdir)/$(@F).tmp >> $@
|
2020-04-16 00:40:58 +00:00
|
|
|
@cat $(m4undivert) >> $@
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2017-02-18 15:20:20 +00:00
|
|
|
$(tmpdir)/all_te_files.conf: $(m4support) $(tmpdir)/generated_definitions.conf $(tmpdir)/all_interfaces.conf $(all_te_files) $(m4terminate)
|
2006-08-31 17:28:35 +00:00
|
|
|
ifeq "$(strip $(all_te_files))" ""
|
|
|
|
$(error No enabled modules! $(notdir $(mod_conf)) may need to be generated by using "make conf")
|
2005-08-18 21:27:20 +00:00
|
|
|
endif
|
2006-08-31 17:28:35 +00:00
|
|
|
@test -d $(tmpdir) || mkdir -p $(tmpdir)
|
2006-03-20 20:54:56 +00:00
|
|
|
$(verbose) $(M4) $(M4PARAM) -s $^ > $@
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2020-07-10 13:07:52 +00:00
|
|
|
$(tmpdir)/post_te_files.conf: $(m4support) $(tmpdir)/generated_definitions.conf $(post_te_files) $(tmpdir)/all_te_files.conf
|
2006-08-31 17:28:35 +00:00
|
|
|
@test -d $(tmpdir) || mkdir -p $(tmpdir)
|
2020-07-10 13:07:52 +00:00
|
|
|
$(verbose) $(GREP) '^[[:blank:]]*user ' $(tmpdir)/all_te_files.conf > $@ || true
|
|
|
|
$(verbose) $(M4) $(M4PARAM) $(m4support) $(tmpdir)/generated_definitions.conf $(post_te_files) >> $@
|
2005-08-18 21:27:20 +00:00
|
|
|
|
|
|
|
# extract attributes and put them first. extract post te stuff
|
2006-03-20 20:54:56 +00:00
|
|
|
# like genfscon and put last.
|
2014-02-18 23:26:33 +00:00
|
|
|
$(tmpdir)/all_attrs_types.conf: $(tmpdir)/all_te_files.conf
|
|
|
|
$(verbose) $(get_type_attr_decl) $^ | $(SORT) > $@
|
|
|
|
|
|
|
|
$(tmpdir)/all_post.conf: $(tmpdir)/all_te_files.conf $(tmpdir)/post_te_files.conf
|
|
|
|
$(verbose) cat $(tmpdir)/post_te_files.conf > $@
|
2006-03-20 20:54:56 +00:00
|
|
|
# these have to run individually because order matters:
|
2021-03-18 20:22:05 +00:00
|
|
|
$(verbose) $(GREP) '^[[:blank:]]*sid ' $(tmpdir)/all_te_files.conf >> $@ || true
|
|
|
|
$(verbose) $(GREP) '^[[:blank:]]*fs_use_(xattr|task|trans)' $(tmpdir)/all_te_files.conf >> $@ || true
|
|
|
|
$(verbose) $(GREP) '^[[:blank:]]*genfscon' $(tmpdir)/all_te_files.conf >> $@ || true
|
|
|
|
$(verbose) $(GREP) '^[[:blank:]]*portcon' $(tmpdir)/all_te_files.conf >> $@ || true
|
|
|
|
$(verbose) $(GREP) '^[[:blank:]]*netifcon' $(tmpdir)/all_te_files.conf >> $@ || true
|
|
|
|
$(verbose) $(GREP) '^[[:blank:]]*nodecon' $(tmpdir)/all_te_files.conf >> $@ || true
|
|
|
|
$(verbose) $(GREP) '^[[:blank:]]*ibpkeycon' $(tmpdir)/all_te_files.conf >> $@ || true
|
|
|
|
$(verbose) $(GREP) '^[[:blank:]]*ibendportcon' $(tmpdir)/all_te_files.conf >> $@ || true
|
2014-02-18 23:26:33 +00:00
|
|
|
|
|
|
|
$(tmpdir)/only_te_rules.conf: $(tmpdir)/all_te_files.conf
|
|
|
|
$(verbose) $(comment_move_decl) $^ > $@
|
2005-08-18 21:27:20 +00:00
|
|
|
|
|
|
|
########################################
|
|
|
|
#
|
|
|
|
# Remove the dontaudit rules from the policy.conf
|
|
|
|
#
|
2006-08-31 17:28:35 +00:00
|
|
|
enableaudit: $(policy_conf)
|
|
|
|
@test -d $(tmpdir) || mkdir -p $(tmpdir)
|
|
|
|
@echo "Removing dontaudit rules from $(notdir $(policy_conf))"
|
|
|
|
$(verbose) $(GREP) -v dontaudit $^ > $(tmpdir)/policy.audit
|
|
|
|
$(verbose) mv $(tmpdir)/policy.audit $(policy_conf)
|
2005-08-18 21:27:20 +00:00
|
|
|
|
|
|
|
########################################
|
|
|
|
#
|
|
|
|
# Construct file_contexts
|
|
|
|
#
|
2019-10-03 20:38:39 +00:00
|
|
|
$(fc): $(tmpdir)/$(notdir $(fc)).tmp
|
2006-08-31 17:28:35 +00:00
|
|
|
$(verbose) $(fcsort) $< $@
|
2008-11-11 14:22:57 +00:00
|
|
|
$(verbose) $(GREP) -e HOME -e ROLE -e USER $@ > $(homedir_template)
|
|
|
|
$(verbose) $(SED) -i -e /HOME/d -e /ROLE/d -e /USER/d $@
|
2005-11-22 22:07:12 +00:00
|
|
|
|
2006-08-31 17:28:35 +00:00
|
|
|
$(tmpdir)/$(notdir $(fc)).tmp: $(m4support) $(tmpdir)/generated_definitions.conf $(all_fc_files)
|
|
|
|
ifeq ($(all_fc_files),)
|
|
|
|
$(error No enabled modules! $(notdir $(mod_conf)) may need to be generated by using "make conf")
|
2005-08-18 21:27:20 +00:00
|
|
|
endif
|
|
|
|
@echo "Creating $(NAME) file_contexts."
|
2006-08-31 17:28:35 +00:00
|
|
|
@test -d $(tmpdir) || mkdir -p $(tmpdir)
|
2006-03-20 20:54:56 +00:00
|
|
|
$(verbose) $(M4) $(M4PARAM) $^ > $@
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2006-08-31 17:28:35 +00:00
|
|
|
$(homedir_template): $(fc)
|
2006-05-15 15:21:43 +00:00
|
|
|
|
2005-08-18 21:27:20 +00:00
|
|
|
########################################
|
|
|
|
#
|
|
|
|
# Install file_contexts
|
|
|
|
#
|
2006-08-31 17:28:35 +00:00
|
|
|
$(fcpath): $(fc) $(loadpath) $(userpath)/system.users
|
2005-08-18 21:27:20 +00:00
|
|
|
@echo "Validating $(NAME) file_contexts."
|
2006-08-31 17:28:35 +00:00
|
|
|
$(verbose) $(SETFILES) -q -c $(loadpath) $(fc)
|
2005-08-18 21:27:20 +00:00
|
|
|
@echo "Installing file_contexts."
|
2011-10-19 14:59:16 +00:00
|
|
|
@$(INSTALL) -d -m 0755 $(@D)
|
|
|
|
$(verbose) $(INSTALL) -m 0644 $(fc) $(fcpath)
|
|
|
|
$(verbose) $(INSTALL) -m 0644 $(homedir_template) $(homedirpath)
|
2021-02-01 19:08:54 +00:00
|
|
|
$(verbose) $(UMASK) 022 ; $(genhomedircon) -d $(topdir) -t $(NAME)
|
2024-02-22 16:32:50 +00:00
|
|
|
$(verbose) if $(SEFCONTEXT_COMPILE) -i > /dev/null 2>&1 ; then \
|
|
|
|
$(SEFCONTEXT_COMPILE) $(fcpath) ;\
|
|
|
|
$(SEFCONTEXT_COMPILE) $(fcpath).homedirs ;\
|
|
|
|
else \
|
|
|
|
echo "$@ Pre-compiled file context not generated! Please install the sefcontext_compile tool (commonly part of libselinux-utils)." ;\
|
|
|
|
fi
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2015-02-09 04:15:29 +00:00
|
|
|
########################################
|
|
|
|
#
|
|
|
|
# Validate file contexts
|
|
|
|
#
|
|
|
|
validate: $(fc) $(polver)
|
|
|
|
@echo "Validating $(NAME) file_contexts."
|
|
|
|
$(verbose) $(SETFILES) -q -c $(polver) $(fc)
|
|
|
|
@echo "Success."
|
|
|
|
|
2006-08-07 17:25:09 +00:00
|
|
|
########################################
|
2005-10-12 19:13:49 +00:00
|
|
|
#
|
|
|
|
# Run policy source checks
|
|
|
|
#
|
2006-08-31 17:28:35 +00:00
|
|
|
check: $(builddir)check.res
|
|
|
|
$(builddir)check.res: $(policy_conf) $(fc)
|
|
|
|
$(SECHECK) -s --profile=development --policy=$(policy_conf) --fcfile=$(fc) > $@
|
2005-10-12 19:13:49 +00:00
|
|
|
|
2006-08-31 17:28:35 +00:00
|
|
|
longcheck: $(builddir)longcheck.res
|
|
|
|
$(builddir)longcheck.res: $(policy_conf) $(fc)
|
|
|
|
$(SECHECK) -s --profile=all --policy=$(policy_conf) --fcfile=$(fc) > $@
|
2005-10-12 19:13:49 +00:00
|
|
|
|
2005-12-09 15:42:39 +00:00
|
|
|
########################################
|
|
|
|
#
|
|
|
|
# Appconfig files
|
|
|
|
#
|
2006-08-31 17:28:35 +00:00
|
|
|
$(appdir)/customizable_types: $(policy_conf)
|
|
|
|
$(verbose) $(GREP) '^[[:blank:]]*type .*customizable' $< | cut -d';' -f1 | cut -d',' -f1 | cut -d' ' -f2 | $(SORT) -u > $(tmpdir)/customizable_types
|
2011-10-19 14:59:16 +00:00
|
|
|
@$(INSTALL) -d -m 0755 $(@D)
|
|
|
|
$(verbose) $(INSTALL) -m 0644 $(tmpdir)/customizable_types $@
|
2005-12-09 15:42:39 +00:00
|
|
|
|
2009-10-23 15:20:07 +00:00
|
|
|
$(installdir)/seusers: $(seusers)
|
2011-08-12 12:28:37 +00:00
|
|
|
$(verbose) $(M4) $(M4PARAM) $(m4support) $^ | $(GREP) '^[a-z_]' > $(tmpdir)/seusers
|
2011-10-19 14:59:16 +00:00
|
|
|
@$(INSTALL) -d -m 0755 $(@D)
|
|
|
|
$(verbose) $(INSTALL) -m 0644 $(tmpdir)/seusers $@
|
2009-10-23 15:20:07 +00:00
|
|
|
|
2005-08-18 21:27:20 +00:00
|
|
|
########################################
|
|
|
|
#
|
|
|
|
# Clean the sources
|
|
|
|
#
|
|
|
|
clean:
|
2014-01-16 16:25:42 +00:00
|
|
|
$(verbose) rm -f $(policy_conf)
|
|
|
|
$(verbose) rm -f $(polver)
|
2022-03-22 17:10:11 +00:00
|
|
|
$(verbose) rm -f $(policy_cil)
|
2014-01-16 16:25:42 +00:00
|
|
|
$(verbose) rm -f $(fc)
|
|
|
|
$(verbose) rm -f $(homedir_template)
|
2020-04-22 16:13:02 +00:00
|
|
|
$(verbose) rm -f $(net_contexts) $(net_contexts_nft)
|
2014-01-16 16:25:42 +00:00
|
|
|
$(verbose) rm -f *.res
|
|
|
|
$(verbose) rm -fR $(tmpdir)
|
2005-08-18 21:27:20 +00:00
|
|
|
|
2021-02-01 19:09:27 +00:00
|
|
|
.PHONY: default policy install load reload enableaudit checklabels restorelabels relabel resetlabels validate check longcheck clean
|