summaryrefslogtreecommitdiffstats
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/actions.h78
-rw-r--r--src/common/force.c405
-rw-r--r--src/common/force.h85
-rw-r--r--src/common/security-mac.h30
-rw-r--r--src/common/selinux.c156
5 files changed, 754 insertions, 0 deletions
diff --git a/src/common/actions.h b/src/common/actions.h
new file mode 100644
index 0000000..a78f329
--- /dev/null
+++ b/src/common/actions.h
@@ -0,0 +1,78 @@
+/*
+ * dpkg - main program for package management
+ * actions.h - command action definition list
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006, 2008-2016 Guillem Jover <guillem@debian.org>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DPKG_ACTIONS_H
+#define DPKG_ACTIONS_H
+
+enum action {
+ act_unset,
+
+ act_unpack,
+ act_configure,
+ act_install,
+ act_triggers,
+ act_remove,
+ act_purge,
+ act_verify,
+ act_commandfd,
+
+ act_status,
+ act_listpackages,
+ act_listfiles,
+ act_searchfiles,
+ act_controlpath,
+ act_controllist,
+ act_controlshow,
+
+ act_cmpversions,
+
+ act_arch_add,
+ act_arch_remove,
+ act_printarch,
+ act_printforeignarches,
+
+ act_assert_feature,
+
+ act_validate_pkgname,
+ act_validate_trigname,
+ act_validate_archname,
+ act_validate_version,
+
+ act_audit,
+ act_unpackchk,
+ act_predeppackage,
+
+ act_getselections,
+ act_setselections,
+ act_clearselections,
+
+ act_avail,
+ act_printavail,
+ act_avclear,
+ act_avreplace,
+ act_avmerge,
+ act_forgetold,
+
+ act_help,
+ act_version,
+};
+
+#endif /* DPKG_ACTIONS_H */
diff --git a/src/common/force.c b/src/common/force.c
new file mode 100644
index 0000000..c4401f0
--- /dev/null
+++ b/src/common/force.c
@@ -0,0 +1,405 @@
+/*
+ * dpkg - main program for package management
+ * force.c - force operation support
+ *
+ * Copyright © 1994,1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006-2019 Guillem Jover <guillem@debian.org>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include <errno.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <dpkg/macros.h>
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+#include <dpkg/options.h>
+
+#include "force.h"
+
+static int force_mask;
+static int force_flags;
+
+enum forcetype {
+ FORCETYPE_DISABLED,
+ FORCETYPE_ENABLED,
+ FORCETYPE_DAMAGE,
+};
+
+static const char *
+forcetype_str(enum forcetype type)
+{
+ switch (type) {
+ case FORCETYPE_DISABLED:
+ return " ";
+ case FORCETYPE_ENABLED:
+ return "[*]";
+ case FORCETYPE_DAMAGE:
+ return "[!]";
+ default:
+ internerr("unknown force type '%d'", type);
+ }
+}
+
+static const struct forceinfo {
+ const char *name;
+ int flag;
+ char type;
+ const char *desc;
+} forceinfos[] = {
+ {
+ "all",
+ FORCE_ALL,
+ FORCETYPE_DAMAGE,
+ N_("Set all force options"),
+ }, {
+ "security-mac",
+ FORCE_SECURITY_MAC,
+ FORCETYPE_ENABLED,
+ N_("Use MAC based security if available"),
+ }, {
+ "downgrade",
+ FORCE_DOWNGRADE,
+ FORCETYPE_ENABLED,
+ N_("Replace a package with a lower version"),
+ }, {
+ "configure-any",
+ FORCE_CONFIGURE_ANY,
+ FORCETYPE_DISABLED,
+ N_("Configure any package which may help this one"),
+ }, {
+ "hold",
+ FORCE_HOLD,
+ FORCETYPE_DISABLED,
+ N_("Install or remove incidental packages even when on hold"),
+ }, {
+ "not-root",
+ FORCE_NON_ROOT,
+ FORCETYPE_DISABLED,
+ N_("Try to (de)install things even when not root"),
+ }, {
+ "bad-path",
+ FORCE_BAD_PATH,
+ FORCETYPE_DISABLED,
+ N_("PATH is missing important programs, problems likely"),
+ }, {
+ "bad-verify",
+ FORCE_BAD_VERIFY,
+ FORCETYPE_DISABLED,
+ N_("Install a package even if it fails authenticity check"),
+ }, {
+ "bad-version",
+ FORCE_BAD_VERSION,
+ FORCETYPE_DISABLED,
+ N_("Process even packages with wrong versions"),
+ }, {
+ "statoverride-add",
+ FORCE_STATOVERRIDE_ADD,
+ FORCETYPE_DISABLED,
+ N_("Overwrite an existing stat override when adding it"),
+ }, {
+ "statoverride-remove",
+ FORCE_STATOVERRIDE_DEL,
+ FORCETYPE_DISABLED,
+ N_("Ignore a missing stat override when removing it"),
+ }, {
+ "overwrite",
+ FORCE_OVERWRITE,
+ FORCETYPE_DISABLED,
+ N_("Overwrite a file from one package with another"),
+ }, {
+ "overwrite-diverted",
+ FORCE_OVERWRITE_DIVERTED,
+ FORCETYPE_DISABLED,
+ N_("Overwrite a diverted file with an undiverted version"),
+ }, {
+ "overwrite-dir",
+ FORCE_OVERWRITE_DIR,
+ FORCETYPE_DAMAGE,
+ N_("Overwrite one package's directory with another's file"),
+ }, {
+ "unsafe-io",
+ FORCE_UNSAFE_IO,
+ FORCETYPE_DAMAGE,
+ N_("Do not perform safe I/O operations when unpacking"),
+ }, {
+ "script-chrootless",
+ FORCE_SCRIPT_CHROOTLESS,
+ FORCETYPE_DAMAGE,
+ N_("Do not chroot into maintainer script environment"),
+ }, {
+ "confnew",
+ FORCE_CONFF_NEW,
+ FORCETYPE_DAMAGE,
+ N_("Always use the new config files, don't prompt"),
+ }, {
+ "confold",
+ FORCE_CONFF_OLD,
+ FORCETYPE_DAMAGE,
+ N_("Always use the old config files, don't prompt"),
+ }, {
+ "confdef",
+ FORCE_CONFF_DEF,
+ FORCETYPE_DAMAGE,
+ N_("Use the default option for new config files if one\n"
+ "is available, don't prompt. If no default can be found,\n"
+ "you will be prompted unless one of the confold or\n"
+ "confnew options is also given"),
+ }, {
+ "confmiss",
+ FORCE_CONFF_MISS,
+ FORCETYPE_DAMAGE,
+ N_("Always install missing config files"),
+ }, {
+ "confask",
+ FORCE_CONFF_ASK,
+ FORCETYPE_DAMAGE,
+ N_("Offer to replace config files with no new versions"),
+ }, {
+ "architecture",
+ FORCE_ARCHITECTURE,
+ FORCETYPE_DAMAGE,
+ N_("Process even packages with wrong or no architecture"),
+ }, {
+ "breaks",
+ FORCE_BREAKS,
+ FORCETYPE_DAMAGE,
+ N_("Install even if it would break another package"),
+ }, {
+ "conflicts",
+ FORCE_CONFLICTS,
+ FORCETYPE_DAMAGE,
+ N_("Allow installation of conflicting packages"),
+ }, {
+ "depends",
+ FORCE_DEPENDS,
+ FORCETYPE_DAMAGE,
+ N_("Turn all dependency problems into warnings"),
+ }, {
+ "depends-version",
+ FORCE_DEPENDS_VERSION,
+ FORCETYPE_DAMAGE,
+ N_("Turn dependency version problems into warnings"),
+ }, {
+ "remove-reinstreq",
+ FORCE_REMOVE_REINSTREQ,
+ FORCETYPE_DAMAGE,
+ N_("Remove packages which require installation"),
+ }, {
+ "remove-protected",
+ FORCE_REMOVE_PROTECTED,
+ FORCETYPE_DAMAGE,
+ N_("Remove a protected package"),
+ }, {
+ "remove-essential",
+ FORCE_REMOVE_ESSENTIAL,
+ FORCETYPE_DAMAGE,
+ N_("Remove an essential package"),
+ }, {
+ NULL
+ }
+};
+
+bool
+in_force(int flags)
+{
+ return (flags & force_flags) == flags;
+}
+
+void
+set_force(int flags)
+{
+ force_flags |= flags;
+}
+
+void
+reset_force(int flags)
+{
+ force_flags &= ~flags;
+}
+
+char *
+get_force_string(void)
+{
+ const struct forceinfo *fip;
+ struct varbuf vb = VARBUF_INIT;
+
+ for (fip = forceinfos; fip->name; fip++) {
+ if ((enum force_flags)fip->flag == FORCE_ALL ||
+ (fip->flag & force_mask) != fip->flag ||
+ !in_force(fip->flag))
+ continue;
+
+ if (vb.used)
+ varbuf_add_char(&vb, ',');
+ varbuf_add_str(&vb, fip->name);
+ }
+ varbuf_end_str(&vb);
+
+ return varbuf_detach(&vb);
+}
+
+static inline void
+print_forceinfo_line(int type, const char *name, const char *desc)
+{
+ printf(" %s %-18s %s\n", forcetype_str(type), name, desc);
+}
+
+static void
+print_forceinfo(const struct forceinfo *fi)
+{
+ char *desc, *line;
+
+ desc = m_strdup(gettext(fi->desc));
+
+ line = strtok(desc, "\n");
+ print_forceinfo_line(fi->type, fi->name, line);
+ while ((line = strtok(NULL, "\n")))
+ print_forceinfo_line(FORCETYPE_DISABLED, "", line);
+
+ free(desc);
+}
+
+void
+parse_force(const char *value, bool set)
+{
+ const struct forceinfo *fip;
+
+ if (strcmp(value, "help") == 0) {
+ char *force_string = get_force_string();
+
+ printf(_(
+"%s forcing options - control behavior when problems found:\n"
+" warn but continue: --force-<thing>,<thing>,...\n"
+" stop with error: --refuse-<thing>,<thing>,... | --no-force-<thing>,...\n"
+" Forcing things:\n"), dpkg_get_progname());
+
+ for (fip = forceinfos; fip->name; fip++)
+ if ((enum force_flags)fip->flag == FORCE_ALL ||
+ (fip->flag & force_mask) == fip->flag)
+ print_forceinfo(fip);
+
+ printf(_(
+"\n"
+"WARNING - use of options marked [!] can seriously damage your installation.\n"
+"Forcing options marked [*] are enabled by default.\n"));
+ m_output(stdout, _("<standard output>"));
+
+ printf(_(
+"\n"
+"Currently enabled options:\n"
+" %s\n"), force_string);
+
+ free(force_string);
+
+ exit(0);
+ }
+
+ for (;;) {
+ const char *comma;
+ size_t l;
+
+ comma = strchrnul(value, ',');
+ l = (size_t)(comma - value);
+ for (fip = forceinfos; fip->name; fip++)
+ if (strncmp(fip->name, value, l) == 0 &&
+ strlen(fip->name) == l)
+ break;
+
+ if (!fip->name) {
+ badusage(_("unknown force/refuse option '%.*s'"),
+ (int)min(l, 250), value);
+ } else if (fip->flag) {
+ if (set)
+ set_force(fip->flag);
+ else
+ reset_force(fip->flag);
+ } else {
+ warning(_("obsolete force/refuse option '%s'"),
+ fip->name);
+ }
+
+ if (*comma == '\0')
+ break;
+ value = ++comma;
+ }
+}
+
+void
+set_force_default(int mask)
+{
+ const char *force_env;
+ const struct forceinfo *fip;
+
+ force_mask = mask;
+
+ /* If we get passed force options from the environment, do not
+ * initialize from the built-in defaults. */
+ force_env = getenv("DPKG_FORCE");
+ if (force_env != NULL) {
+ if (force_env[0] != '\0')
+ parse_force(force_env, 1);
+ return;
+ }
+
+ for (fip = forceinfos; fip->name; fip++)
+ if (fip->type == FORCETYPE_ENABLED)
+ set_force(fip->flag);
+}
+
+void
+set_force_option(const struct cmdinfo *cip, const char *value)
+{
+ bool set = cip->arg_int;
+
+ parse_force(value, set);
+}
+
+void
+reset_force_option(const struct cmdinfo *cip, const char *value)
+{
+ reset_force(cip->arg_int);
+}
+
+void
+forcibleerr(int forceflag, const char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if (in_force(forceflag)) {
+ warning(_("overriding problem because --force enabled:"));
+ warningv(fmt, args);
+ } else {
+ ohshitv(fmt, args);
+ }
+ va_end(args);
+}
+
+int
+forcible_nonroot_error(int rc)
+{
+ if (in_force(FORCE_NON_ROOT) && errno == EPERM)
+ return 0;
+ return rc;
+}
diff --git a/src/common/force.h b/src/common/force.h
new file mode 100644
index 0000000..c232c7f
--- /dev/null
+++ b/src/common/force.h
@@ -0,0 +1,85 @@
+/*
+ * dpkg - main program for package management
+ * force.h - forced operation support
+ *
+ * Copyright © 1995 Ian Jackson <ijackson@chiark.greenend.org.uk>
+ * Copyright © 2006, 2008-2019 Guillem Jover <guillem@debian.org>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DPKG_FORCE_H
+#define DPKG_FORCE_H
+
+#include <dpkg/dpkg.h>
+#include <dpkg/options.h>
+
+enum DPKG_ATTR_ENUM_FLAGS force_flags {
+ FORCE_ARCHITECTURE = DPKG_BIT(0),
+ FORCE_BAD_PATH = DPKG_BIT(1),
+ FORCE_BAD_VERIFY = DPKG_BIT(2),
+ FORCE_BAD_VERSION = DPKG_BIT(3),
+ FORCE_BREAKS = DPKG_BIT(4),
+ FORCE_CONFF_ASK = DPKG_BIT(5),
+ FORCE_CONFF_DEF = DPKG_BIT(6),
+ FORCE_CONFF_MISS = DPKG_BIT(7),
+ FORCE_CONFF_NEW = DPKG_BIT(8),
+ FORCE_CONFF_OLD = DPKG_BIT(9),
+ FORCE_CONFIGURE_ANY = DPKG_BIT(10),
+ FORCE_CONFLICTS = DPKG_BIT(11),
+ FORCE_DEPENDS = DPKG_BIT(12),
+ FORCE_DEPENDS_VERSION = DPKG_BIT(13),
+ FORCE_DOWNGRADE = DPKG_BIT(14),
+ FORCE_HOLD = DPKG_BIT(15),
+ FORCE_NON_ROOT = DPKG_BIT(16),
+ FORCE_OVERWRITE = DPKG_BIT(17),
+ FORCE_OVERWRITE_DIR = DPKG_BIT(18),
+ FORCE_OVERWRITE_DIVERTED = DPKG_BIT(19),
+ FORCE_REMOVE_ESSENTIAL = DPKG_BIT(20),
+ FORCE_REMOVE_REINSTREQ = DPKG_BIT(21),
+ FORCE_SCRIPT_CHROOTLESS = DPKG_BIT(22),
+ FORCE_UNSAFE_IO = DPKG_BIT(23),
+ FORCE_STATOVERRIDE_ADD = DPKG_BIT(24),
+ FORCE_STATOVERRIDE_DEL = DPKG_BIT(25),
+ FORCE_SECURITY_MAC = DPKG_BIT(26),
+ FORCE_REMOVE_PROTECTED = DPKG_BIT(27),
+ FORCE_ALL = 0xffffffff,
+};
+
+bool
+in_force(int flags);
+void
+set_force(int flags);
+void
+reset_force(int flags);
+
+char *
+get_force_string(void);
+
+void
+parse_force(const char *value, bool set);
+
+void
+set_force_default(int mask);
+void
+set_force_option(const struct cmdinfo *cip, const char *value);
+void
+reset_force_option(const struct cmdinfo *cip, const char *value);
+
+void
+forcibleerr(int forceflag, const char *format, ...) DPKG_ATTR_PRINTF(2);
+int
+forcible_nonroot_error(int rc);
+
+#endif /* DPKG_FORCE_H */
diff --git a/src/common/security-mac.h b/src/common/security-mac.h
new file mode 100644
index 0000000..637c6f7
--- /dev/null
+++ b/src/common/security-mac.h
@@ -0,0 +1,30 @@
+/*
+ * dpkg - main program for package management
+ * security-mac.h - MAC-based security support
+ *
+ * Copyright © 2015 Guillem Jover <guillem@debian.org>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef DPKG_SECURITY_MAC_H
+#define DPKG_SECURITY_MAC_H
+
+#include <sys/stat.h>
+
+void dpkg_selabel_load(void);
+void dpkg_selabel_set_context(const char *matchpath, const char *path, mode_t mode);
+void dpkg_selabel_close(void);
+
+#endif /* DPKG_SECURITY_MAC_H */
diff --git a/src/common/selinux.c b/src/common/selinux.c
new file mode 100644
index 0000000..b5d29d8
--- /dev/null
+++ b/src/common/selinux.c
@@ -0,0 +1,156 @@
+/*
+ * dpkg - main program for package management
+ * selinux.c - SELinux support
+ *
+ * Copyright © 2007-2015 Guillem Jover <guillem@debian.org>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <compat.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <dpkg/i18n.h>
+#include <dpkg/dpkg.h>
+#include <dpkg/dpkg-db.h>
+
+#ifdef WITH_LIBSELINUX
+#include <selinux/selinux.h>
+#include <selinux/avc.h>
+#include <selinux/label.h>
+#endif
+
+#include "force.h"
+#include "security-mac.h"
+
+#ifdef WITH_LIBSELINUX
+static struct selabel_handle *sehandle;
+#endif
+
+#ifdef WITH_LIBSELINUX
+static int DPKG_ATTR_PRINTF(2)
+log_callback(int type, const char *fmt, ...)
+{
+ va_list ap;
+ char *msg;
+
+ switch (type) {
+ case SELINUX_ERROR:
+ case SELINUX_WARNING:
+ case SELINUX_AVC:
+ break;
+ default:
+ return 0;
+ }
+
+ va_start(ap, fmt);
+ m_vasprintf(&msg, fmt, ap);
+ va_end(ap);
+
+ warning("selinux: %s", msg);
+ free(msg);
+
+ return 0;
+}
+#endif
+
+void
+dpkg_selabel_load(void)
+{
+#ifdef WITH_LIBSELINUX
+ static int selinux_enabled = -1;
+
+ if (selinux_enabled < 0) {
+ int rc;
+
+ /* Set selinux_enabled if it is not already set (singleton). */
+ selinux_enabled = (in_force(FORCE_SECURITY_MAC) &&
+ is_selinux_enabled() > 0);
+ if (!selinux_enabled)
+ return;
+
+ /* Open the SELinux status notification channel, with fallback
+ * enabled for older kernels. */
+ rc = selinux_status_open(1);
+ if (rc < 0)
+ ohshit(_("cannot open security status notification channel"));
+
+ selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) {
+ .func_log = log_callback,
+ });
+ } else if (selinux_enabled && selinux_status_updated()) {
+ /* The SELinux policy got updated in the kernel, usually after
+ * upgrading the package shipping it, we need to reload. */
+ selabel_close(sehandle);
+ } else {
+ /* SELinux is either disabled or it does not need a reload. */
+ return;
+ }
+
+ sehandle = selabel_open(SELABEL_CTX_FILE, NULL, 0);
+ if (sehandle == NULL && security_getenforce() == 1)
+ ohshite(_("cannot get security labeling handle"));
+#endif
+}
+
+void
+dpkg_selabel_set_context(const char *matchpath, const char *path, mode_t mode)
+{
+#ifdef WITH_LIBSELINUX
+ char *scontext = NULL;
+ int ret;
+
+ /* If SELinux is not enabled just do nothing. */
+ if (sehandle == NULL)
+ return;
+
+ /*
+ * We use the _raw function variants here so that no translation
+ * happens from computer to human readable forms, to avoid issues
+ * when mcstransd has disappeared during the unpack process.
+ */
+
+ /* Do nothing if we can't figure out what the context is, or if it has
+ * no context; in which case the default context shall be applied. */
+ ret = selabel_lookup_raw(sehandle, &scontext, matchpath, mode & S_IFMT);
+ if (ret == -1 || (ret == 0 && scontext == NULL))
+ return;
+
+ ret = lsetfilecon_raw(path, scontext);
+ if (ret < 0 && errno != ENOTSUP)
+ ohshite(_("cannot set security context for file object '%s'"),
+ path);
+
+ freecon(scontext);
+#endif /* WITH_LIBSELINUX */
+}
+
+void
+dpkg_selabel_close(void)
+{
+#ifdef WITH_LIBSELINUX
+ if (sehandle == NULL)
+ return;
+
+ selinux_status_close();
+ selabel_close(sehandle);
+ sehandle = NULL;
+#endif
+}