Hello community, here is the log from the commit of package grub2 for openSUSE:Factory checked in at 2017-02-22 13:58:49 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/grub2 (Old) and /work/SRC/openSUSE:Factory/.grub2.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "grub2" Changes: -------- --- /work/SRC/openSUSE:Factory/grub2/grub2.changes 2017-02-20 14:28:17.625552693 +0100 +++ /work/SRC/openSUSE:Factory/.grub2.new/grub2.changes 2017-02-22 13:58:50.535010879 +0100 @@ -2,37 +1,0 @@ -Fri Feb 17 06:46:11 UTC 2017 - mch...@suse.com - -- grub2.spec: fix s390x file list. - -------------------------------------------------------------------- -Wed Feb 15 07:25:02 UTC 2017 - mch...@suse.com - -- Merge changes from SLE12 -- add grub2-emu-4-all.patch - * Build 'grub2-emu' wherever possible, to allow a better - implementation of that feature. -- add grub2-s390x-06-loadparm.patch, -- add grub2-commands-introduce-read_file-subcommand.patch: - * allow s390x to telecontrol grub2. (bsc#891946, bsc#892852) -- add grub2-s390x-06-loadparm.patch: - * ignore case and fix transliteration of parameter. (bsc#891946) -- add grub2-s390x-07-add-image-param-for-zipl-setup.patch - * Add --image switch to force zipl update to specific kernel - (bsc#928131) -- add grub2-s390x-08-workaround-part-to-disk.patch - * Ignore partition tables on s390x. (bsc#935127) -- add grub2-efi-chainload-harder.patch: - * allow XEN to be chain-loaded despite firmware flaws. (bnc#887793) - * Do not use shim lock protocol for reading pe header, it won't be - available when secure boot disabled (bsc#943380) - * Make firmware flaw condition be more precisely detected and add - debug message for the case - * Check msdos header to find PE file header (bsc#954126) -- grub2-s390x-04-grub2-install.patch: - * streamline boot to grub menu. (bsc#898198) - * Force '/usr' to read-only before calling kexec. (bsc#932951) -- grub2-once: - * add '--enum' option to enumerate boot-entries in a way - actually understood by 'grub2'. (bsc#892852, bsc#892811) - * Examine variables from grub environment in 'grub2-once'. (fate#319632) - -------------------------------------------------------------------- Old: ---- grub2-commands-introduce-read_file-subcommand.patch grub2-efi-chainload-harder.patch grub2-emu-4-all.patch grub2-s390x-06-loadparm.patch grub2-s390x-07-add-image-param-for-zipl-setup.patch grub2-s390x-08-workaround-part-to-disk.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ grub2.spec ++++++ --- /var/tmp/diff_new_pack.sjcI4X/_old 2017-02-22 13:58:52.954666733 +0100 +++ /var/tmp/diff_new_pack.sjcI4X/_new 2017-02-22 13:58:52.954666733 +0100 @@ -64,14 +64,9 @@ # Modules code is dynamically loaded and collected from a _fixed_ path. %define _libdir %{_exec_prefix}/lib -# Build grub2-emu everywhere (it may be "required" by 'grub2-once') -%define emu 1 - %ifarch ppc ppc64 ppc64le %define grubcpu powerpc %define platform ieee1275 -# emu does not build here yet... :-( -%define emu 0 %endif %ifarch %{ix86} x86_64 @@ -89,18 +84,15 @@ %define platform uboot %endif -%ifarch aarch64 -%define grubcpu arm64 -%define platform efi -%define only_efi 1 -%endif - %define grubarch %{grubcpu}-%{platform} # build efi bootloader on some platforms only: %if ! 0%{?efi:1} %global efi %{ix86} x86_64 ia64 aarch64 %{arm} %endif +%ifarch aarch64 +%define only_efi 1 +%endif %ifarch %{efi} %ifarch %{ix86} @@ -126,11 +118,6 @@ %define grubxenarch x86_64-xen %endif -%if %{platform} == emu -# force %{emu} to 1, e.g. for s390 -%define emu 1 -%endif - %if 0%{?suse_version} == 1110 %define only_efi %{nil} %define only_x86_64 %{nil} @@ -200,12 +187,6 @@ Patch71: grub2-menu-unrestricted.patch Patch72: grub2-mkconfig-arm.patch Patch74: grub2-accept-empty-module.patch -Patch75: grub2-s390x-06-loadparm.patch -Patch76: grub2-s390x-07-add-image-param-for-zipl-setup.patch -Patch77: grub2-s390x-08-workaround-part-to-disk.patch -Patch78: grub2-commands-introduce-read_file-subcommand.patch -Patch79: grub2-efi-chainload-harder.patch -Patch80: grub2-emu-4-all.patch # Btrfs snapshot booting related patches Patch101: grub2-btrfs-01-add-ability-to-boot-from-subvolumes.patch Patch102: grub2-btrfs-02-export-subvolume-envvars.patch @@ -299,7 +280,6 @@ %description branding-upstream Upstream branding for GRUB2's graphical console -%if ! 0%{?only_efi:1} %package %{grubarch} Summary: Bootloader with support for Linux, Multiboot and more @@ -329,8 +309,6 @@ file systems, computer architectures and hardware devices. This subpackage provides support for %{platform} systems. -%endif - %ifarch %{efi} %package %{grubefiarch} @@ -455,12 +433,6 @@ %patch71 -p1 %patch72 -p1 %patch74 -p1 -%patch75 -p1 -%patch76 -p1 -%patch77 -p1 -%patch78 -p1 -%patch79 -p1 -%patch80 -p1 %patch101 -p1 %patch102 -p1 %patch103 -p1 @@ -515,9 +487,6 @@ %ifarch %{ix86} x86_64 mkdir build-xen %endif -%if %{emu} -mkdir build-emu -%endif %build # autogen calls autoreconf -vi @@ -533,28 +502,6 @@ FFLAGS=" " export CFLAGS CXXFLAGS FFLAGS -%if %{emu} -cd build-emu -%define arch_specific --enable-device-mapper --disable-grub-mount -TFLAGS="-fPIC" - -# -static is needed so that autoconf script is able to link -# test that looks for _start symbol on 64 bit platforms -../configure TARGET_LDFLAGS=$TFLAGS \ - --prefix=%{_prefix} \ - --sysconfdir=%{_sysconfdir} \ - --target=%{_target_platform} \ - --with-platform=emu \ - %{arch_specific} \ - --program-transform-name=s,grub,%{name}, -make %{?_smp_mflags} -cd .. -if [ "%{platform}" = "emu" ]; then - rmdir build - mv build-emu build -fi -%endif - %ifarch %{ix86} x86_64 cd build-xen ../configure \ @@ -646,9 +593,13 @@ %define _target_platform i386-%{_vendor}-%{_target_os}%{?_gnu} %endif -%if %{platform} != "emu" +%ifarch s390x +%define arch_specific --enable-device-mapper --disable-grub-mount +TFLAGS="-fPIC" +%else %define arch_specific --enable-device-mapper TFLAGS="-static" +%endif # -static is needed so that autoconf script is able to link # test that looks for _start symbol on 64 bit platforms @@ -661,8 +612,6 @@ --program-transform-name=s,grub,%{name}, make %{?_smp_mflags} %endif -cd .. -%endif %install @@ -702,17 +651,10 @@ %if ! 0%{?only_efi:1} cd build make DESTDIR=$RPM_BUILD_ROOT install -cd .. +%else +cd build-efi %endif -if [ -d build-emu/grub-core ]; then - cd build-emu/grub-core - install -m 755 grub-emu $RPM_BUILD_ROOT%{_bindir}/%{name}-emu - install -m 755 grub-emu-lite $RPM_BUILD_ROOT%{_bindir}/%{name}-emu-lite - install -m 644 grub-emu.1 $RPM_BUILD_ROOT%{_mandir}/man1/%{name}-emu.1 - cd ../.. -fi - # *.module files are installed with executable bits due to the way grub2 build # system works. Clear executable bits to not confuse find-debuginfo.sh find $RPM_BUILD_ROOT%{_libdir}/%{name} \ @@ -936,11 +878,16 @@ fi %endif fi +%if 0%{?only_efi:1} +%define source_dir build-efi +%else +%define source_dir build +%endif %postun %service_del_postun grub2-once.service -%files -f %{name}.lang +%files -f %{source_dir}/%{name}.lang %defattr(-,root,root,-) %doc COPYING NEWS README %doc THANKS TODO ChangeLog @@ -970,6 +917,7 @@ %{_bindir}/%{name}-editenv %{_bindir}/%{name}-file %{_bindir}/%{name}-fstest +%{_bindir}/%{name}-glue-efi %{_bindir}/%{name}-kbdcomp %{_bindir}/%{name}-menulst2cfg %{_bindir}/%{name}-mkfont @@ -982,7 +930,6 @@ %{_bindir}/%{name}-mkstandalone %{_bindir}/%{name}-render-label %{_bindir}/%{name}-script-check -%{_bindir}/%{name}-syslinux2cfg %if 0%{?has_systemd:1} %{_unitdir}/grub2-once.service %endif @@ -998,6 +945,7 @@ %{_mandir}/man1/%{name}-editenv.1.* %{_mandir}/man1/%{name}-file.1.* %{_mandir}/man1/%{name}-fstest.1.* +%{_mandir}/man1/%{name}-glue-efi.1.* %{_mandir}/man1/%{name}-kbdcomp.1.* %{_mandir}/man1/%{name}-menulst2cfg.1.* %{_mandir}/man1/%{name}-mkfont.1.* @@ -1010,30 +958,29 @@ %{_mandir}/man1/%{name}-mkstandalone.1.* %{_mandir}/man1/%{name}-render-label.1.* %{_mandir}/man1/%{name}-script-check.1.* -%{_mandir}/man1/%{name}-syslinux2cfg.1.* %{_mandir}/man8/%{name}-install.8.* %{_mandir}/man8/%{name}-mkconfig.8.* %{_mandir}/man8/%{name}-probe.8.* %{_mandir}/man8/%{name}-reboot.8.* %{_mandir}/man8/%{name}-set-default.8.* -%if %{emu} -%{_bindir}/%{name}-emu* +%ifarch s390x +%{_bindir}/%{name}-emu +%{_bindir}/%{name}-emu-lite %{_mandir}/man1/%{name}-emu.1.* -%endif -%ifnarch s390x +%else %config %{_sysconfdir}/grub.d/30_os-prober -%{_bindir}/%{name}-glue-efi %{_bindir}/%{name}-mount +%{_bindir}/%{name}-syslinux2cfg %{_sbindir}/%{name}-bios-setup %{_sbindir}/%{name}-macbless %{_sbindir}/%{name}-ofpathname %{_sbindir}/%{name}-sparc64-setup -%{_mandir}/man1/%{name}-glue-efi.1.* %{_mandir}/man1/%{name}-mount.1.* %{_mandir}/man8/%{name}-bios-setup.8.* %{_mandir}/man8/%{name}-macbless.8.* %{_mandir}/man8/%{name}-ofpathname.8.* %{_mandir}/man8/%{name}-sparc64-setup.8.* +%{_mandir}/man1/%{name}-syslinux2cfg.1.* %endif %files branding-upstream ++++++ grub2-once ++++++ --- /var/tmp/diff_new_pack.sjcI4X/_old 2017-02-22 13:58:53.218629190 +0100 +++ /var/tmp/diff_new_pack.sjcI4X/_new 2017-02-22 13:58:53.218629190 +0100 @@ -8,151 +8,13 @@ my $grub2_dir; my $grub2_reboot; -my $grub2_editenv; my $show_mapped; my $id_name; my @menuentry; -my @enumentry; -my %E; -sub dPrint($) { - #print( STDERR @_[0]); -} - -sub sh_test($) { - my ( $exp ) = @_; - - dPrint( "?? '$exp' "); - $exp .= " ]" if ( $exp =~ m{^\[.*[^\]]\s*$} ); # gnaaa - #my $t = qx{set -x; $exp}; - my $t = qx{$exp}; - my $ret = $? >> 8; - $ret = ($ret == 0) ? 1 : 0; - dPrint("=> $ret ($t)\n"); - return $ret; -} - -sub read_cfg($$) { - my ($dir, $cfg) = @_; - - my $fh; - my $m = ""; - my $state = 1; # 1 == normal, 010 == if-false, 011 == if-true, 110 == else-false, 111 == else-true - my @State = (); - - if ($dir) { - %E = ( "config_directory" => $dir ); - dPrint("# VE: 'cd'='$dir'\n"); - $dir .= "/"; - if ($> == 0) { - open($fh, "$grub2_editenv - list |") || die "cannot read grub2 environment: $!\n"; - while (<$fh>) { - chomp; - if ( m{^([^\s=]+?)=(.*)$} ) { - my ($k, $v) = ($1, $2); - $v =~ s{^"([^"]*)"$}{$1}; - dPrint("# VE: '$k'='$v'\n"); - $E{$k} = $v; - } - } - close($fh); - } - } - - dPrint("# open($dir$cfg)\n"); - open($fh, "<$dir$cfg") || die "cannot read $cfg in $dir: $!\n"; - - LINE: while ( <$fh> ) { - s{^#.*$}{}; # get rid of trailing comments, - s{\s+$}{}; # trailing whitespace - s{\s*;$}{}; # including semicolons - next if (m{^\s*$}); # and empty lines. - s{^\s*}{ }; # force leading whitespace to one - - dPrint(sprintf("#%d: '%s' [%s]%04b\n", $., $_, join(",",@State), $state)); - if ( m{^ fi$} ) { - $state = pop( @State); - $m .= "$_\n"; - dPrint(sprintf(">FI: [%s]0b%04b\n", join(",",@State), $state)); - next; - } - if ($state & 0b10) { # {if,else}-* - if ( m{^ elif\s+(.*?)\s*; then$} && !($state & 0b1000)) { - if ($state & 0b1) { - $state = 0b110; # else-false - } else { - $state = 0b010 + sh_test( $1); # if-? - dPrint(sprintf("=EI: 0b%03b\n", $state)); - $m .= "$_\n"; - next; - } - } elsif ( m{^ else$} && !($state & 0b1000)) { - if (($state & 0b111) == 0b010) { # in 'if' but neither 'else' nor 'true' - $state = 0b111; # else-true - } else { - $state = 0b110; # else-false - } - $m .= "$_\n"; - dPrint(sprintf("=EL: 0b%03b\n", $state)); - next; - } - } - if ($state & 0b1) { # *-true or normal - dPrint("-I1: $_\n"); - } else { # *-false - dPrint("-I0: $_\n"); - if ( m{^ if (.*?)\s*; then$} ) { - push( @State, $state); - $state = 0b1000; - $m .= "$_\n"; - } - next; - } - - while ( m'(?:[^\\])(\$(?:{([^}]+?)}|([A-Za-z0-9_]+)))' ) { - my ($s, $k1, $k2) = ($1, $2, $3); - my $k = (defined($k1)) ? $k1 : $k2; - dPrint("# VT: '$k'\n"); - if (exists( $E{$k})) { - $s =~ s{([\$\{\}\"])}{\\$1}g; - dPrint("# VB: '$_'\n"); - s{$s}{$E{$k}} || die; - dPrint("# VR: '$_'\n"); - } else { - $s =~ s{([\$\{\}\"])}{\\$1}g; - s{$s}{} || die; - dPrint("# VR: '$_'\n"); - } - } - - if ( m{^ if (.*?)\s*; then$} ) { - push( @State, $state); - $state = 0b010 + sh_test( $1); - dPrint(sprintf("<IF: 0b%03b [%s]\n", $state, join (",", @State))); - } elsif ( m{^ (?:set\s+)?([^\s=]+?)=(.*)$} ) { - my ($k, $v) = ($1, $2); - $v =~ s{^"([^"]*)"$}{$1}; - dPrint("# VA: '$k'='$v'\n"); - $E{$k} = $v; - } elsif ( m{^ source\s+(\S+)$} ) { - my $f = $1; - $f =~ s{^"([^"]+)"$}{$1} && - dPrint("# f='$f'\n"); - if ( -r $f ) { - $m .= read_cfg("", $f); - } - next; - } - $m .= "$_\n"; - } - close ($fh); - return ($m); -} - -sub parse_menuentry($$$) { +sub parse_menuentry { - my ($parent, $pId, $menu) = @_; - my $c = 0; + my ($parent, $menu) = @_; my @m = $menu =~ /(submenu|menuentry) \s+ (.*?) ( \{ (?: [^{}]* | (?3))* \} )/sxg; for (my $i = 0; $i <= $#m; $i += 3) { @@ -161,13 +23,11 @@ my $title = `printf "%s\n" $m[$i+1] | head -1 | tr -d '\n'`; my $data = $m[$i+2]; my $name = ($parent) ? "$parent>$title" : "$title"; - my $eId = (($pId ne "") ? "$pId>" : "") . $c++; if ($type eq "menuentry") { push @menuentry, $name; - push @enumentry, [$name, $eId]; } elsif ($type eq "submenu") { - parse_menuentry ($name, $eId, $data); + &parse_menuentry ($name, $data); } } } @@ -207,7 +67,6 @@ if ($bl eq "grub2" || $bl eq "grub2-efi") { $grub2_dir = "/boot/grub2"; $grub2_reboot = "/usr/sbin/grub2-reboot"; - $grub2_editenv = "/usr/bin/grub2-editenv"; } last; } @@ -224,22 +83,26 @@ die "no grub2_dir" if ($grub2_dir eq ""); -my $m = read_cfg( $grub2_dir, "grub.cfg"); -# Note: only *one* top-level call to parse_menuentry() is possible -# or else it will start again with 0 (and no parent)! -parse_menuentry ("", "", $m); +open(MENU, "<$grub2_dir/grub.cfg") || die "cannot read grub.cfg in $grub2_dir: $!\n"; +undef $/; -my $ret = ""; -my $name = ""; -my $id = -1; +while (<MENU>) { + &parse_menuentry ("", $_); +} + +close (MENU); -if ($id_name eq '--enum') { - foreach my $e (@enumentry) { - printf "%-7s %s\n", $e->[1], $e->[0]; +if (open(MENU, "<$grub2_dir/custom.cfg")) { + while (<MENU>) { + &parse_menuentry ("", $_); } - exit 0; + close (MENU); } +my $ret = ""; +my $name = ""; +my $id = -1; + if ($id_name eq '--list') { my $c = 0; @@ -288,4 +151,4 @@ system "$grub2_reboot \"$name\""; enable_restore_grubenv_service; } - + ++++++ grub2-s390x-04-grub2-install.patch ++++++ --- /var/tmp/diff_new_pack.sjcI4X/_old 2017-02-22 13:58:53.274621226 +0100 +++ /var/tmp/diff_new_pack.sjcI4X/_new 2017-02-22 13:58:53.274621226 +0100 @@ -41,10 +41,6 @@ * dracut-grub2.sh: provide /boot from above to grub2-emu in chroot. V14: * grub2-zipl-setup: actually remove obsolete kernel/initrds. [bnc#892810] -V15: - * zipl2grub.conf: turn of zipl-prompt and quiescent plymouth. [bsc#898198] -V16: - * dracut-grub2.sh: force read-only '/usr' for kexec. [bsc#932951] --- Makefile.util.def | 39 +++ @@ -56,11 +52,11 @@ include/grub/util/install.h | 4 util/grub-install-common.c | 1 util/grub-install.c | 43 +++ - util/s390x/dracut-grub2.sh.in | 110 +++++++++ + util/s390x/dracut-grub2.sh.in | 106 ++++++++ util/s390x/dracut-module-setup.sh.in | 19 + util/s390x/zipl2grub.conf.in | 26 ++ util/s390x/zipl2grub.pl.in | 424 +++++++++++++++++++++++++++++++++++ - 13 files changed, 702 insertions(+), 4 deletions(-) + 13 files changed, 698 insertions(+), 4 deletions(-) Index: grub-2.02~rc1/Makefile.util.def =================================================================== @@ -90,23 +86,15 @@ }; program = { -@@ -417,6 +420,7 @@ program = { +@@ -402,6 +405,7 @@ program = { ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; - ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBUTIL) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; + emu_condition = COND_NOT_s390x; }; - data = { -@@ -628,6 +632,7 @@ program = { - common = grub-core/disk/host.c; - - common = util/resolve.c; -+ emu_condition = COND_s390x; - common = grub-core/kern/emu/argp_common.c; - common = grub-core/osdep/init.c; - -@@ -697,6 +702,38 @@ script = { + program = { +@@ -697,6 +701,38 @@ script = { }; script = { @@ -145,7 +133,7 @@ name = grub-mkconfig_lib; common = util/grub-mkconfig_lib.in; installdir = noinst; -@@ -1308,6 +1345,7 @@ program = { +@@ -1292,6 +1328,7 @@ program = { ldadd = libgrubkern.a; ldadd = grub-core/gnulib/libgnu.a; ldadd = '$(LIBINTL) $(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)'; @@ -469,7 +457,7 @@ =================================================================== --- /dev/null +++ grub-2.02~rc1/util/s390x/dracut-grub2.sh.in -@@ -0,0 +1,110 @@ +@@ -0,0 +1,106 @@ +#!/bin/sh +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh @@ -478,14 +466,12 @@ +if getargbool 0 initgrub && [ ! -e /grub2skip ] || [ -e /grub2force ]; then + #type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh + checkro() { -+ local tgt="$1" + local dev mp fs opts dc -+ local rofs=true ++ local rofs=false + while read dev mp fs opts dc; do -+ [ "$mp" = "$tgt" ] || continue ++ [ "$mp" = "/sysroot" ] || continue + case ",$opts," in + (*,ro,*) rofs=true;; -+ (*) rofs=false;; + esac + done < /proc/mounts + echo $rofs @@ -527,9 +513,9 @@ + bindir=@bindir@ + if [ -e /sysroot$bindir/grub2-emu ]; then + ++ + export TERM=$(getterm) -+ export grub2rofs=$(checkro /sysroot) -+ export grub2roufs=$(checkro /sysroot/usr) ++ export grub2rofs=$(checkro) + export grub2sysfs=$(checkd /sysroot/sys/devices/system/memory) + export grub2procfs=$(checkd /sysroot/proc/self) + export grub2bootfs=$(checkboot) @@ -554,7 +540,6 @@ + + CTTY="$CTTY --wait" + $grub2rofs || mount -o remount,ro /sysroot -+ $grub2roufs || mount -o remount,ro /sysroot/usr + $grub2sysfs || mount --bind {,/sysroot}/sys + $grub2procfs || mount --bind {,/sysroot}/proc + $grub2bootfs || mount --bind {,/sysroot}/boot @@ -573,7 +558,6 @@ + $grub2bootfs || umount /sysroot/boot + $grub2procfs || umount /sysroot/proc + $grub2sysfs || umount /sysroot/sys -+ $grub2roufs || mount -o remount,rw /sysroot/usr + $grub2rofs || mount -o remount,rw /sysroot + else + info "No $bindir/grub2-emu in /sysroot--trying to proceed without kexec..." @@ -619,7 +603,7 @@ + target = @zipldir@ + ramdisk = @zipldir@/initrd,0x2000000 + image = @zipldir@/image -+ parameters = "root=@GRUB_DEVICE@ @GRUB_EMU_CONMODE@ @GRUB_CMDLINE_LINUX@ @GRUB_CMDLINE_LINUX_DEFAULT@ initgrub quiet splash=silent plymouth.enable=0 " ++ parameters = "root=@GRUB_DEVICE@ @GRUB_EMU_CONMODE@ @GRUB_CMDLINE_LINUX@ @GRUB_CMDLINE_LINUX_DEFAULT@ initgrub quiet splash=silent " + +[skip-grub2] + target = @zipldir@ @@ -631,7 +615,7 @@ + target = @zipldir@ + timeout = 16 + default = 1 -+ prompt = 0 ++ prompt = 1 + 1 = grub2 + 2 = skip-grub2 +