diff options
668 files changed, 15881 insertions, 5804 deletions
diff --git a/INSTALL-WIN32.md b/INSTALL-WIN32.md index 8640ee3b51..1e5e1f45fa 100644 --- a/INSTALL-WIN32.md +++ b/INSTALL-WIN32.md @@ -6,29 +6,31 @@ Introduction This file describes how to build the Erlang emulator and the OTP libraries on Windows. The instructions apply to versions of Windows -supporting the Cygwin emulated gnuish environment for Windows. We've -built on the following platforms: Windows 2000 Professional, Windows -2003 server, Windows XP Home/Professional, and Windows Vista. Any -Windows95'ish platform will surely get you into trouble, what I'm not -sure of, but it certainly will... - -The procedure described uses Cygwin as a build environment, you run -the bash shell in Cygwin and uses gnu make/configure/autoconf etc to -do the build. The emulator C-source code is, however, mostly compiled -with Microsoft Visual C++â„¢, producing a native Windows binary. This -is the same procedure as we use to build the pre-built binaries. The -fact that we use VC++ and not gcc is explained further in the FAQ -section. +supporting the Cygwin emulated gnuish environment for Windows or the +Msys ditto. We've built on the following platforms: Windows 2003 +server, Windows XP Home/Professional, Windows Vista and Windows 7 (32 +and 64 bit). You can probably build on Windows 2000, but you will not +be able to install the latest Microsoft SDK, so you have to go back to +some earlier compiler. Any Windows95'ish platform will surely get you +into trouble, what I'm not sure of, but it certainly will... + +The procedure described uses either Cygwin or Msys as a build +environment, you run the bash shell in Cygwin/Msys and use gnu +make/configure/autoconf etc to do the build. The emulator C-source +code is, however, mostly compiled with Microsoft Visual C++â„¢, +producing a native Windows binary. This is the same procedure as we +use to build the pre-built binaries. The fact that we use VC++ and not +gcc is explained further in the FAQ section. I describe the build procedure to make it possible for open source customers to build the emulator, given that they have the needed tools. The binary Windows releases is still a preferred alternative if one does not have Microsoft's development tools and/or don't want to -install Cygwin. +install Cygwin or Msys. -To use Cygwin, one needs basic experience from a Unix environment, if +To use Cygwin/Msys, one needs basic experience from a Unix environment, if one does not know how to set environment variables, run programs etc -in a Unix environment, one will be quite lost in the Cygwin +in a Unix environment, one will be quite lost in the Cygwin os Msys ditto. I can unfortunately not teach all the world how to use Cygwin and bash, neither how to install Cygwin nor perform basic tasks on a computer. Please refer to other documentation on the net for @@ -41,11 +43,11 @@ to make the Erlang/OTP distribution for Windows better. Please submit any suggestions and patches to the appropriate [mailing lists] [1] to let them find their way into the next version of Erlang. If making changes to the build system (like makefiles etc) please bear in mind that the -same makefiles are used on Unix/VxWorks/OSEDelta, so that your changes +same makefiles are used on Unix/VxWorks, so that your changes don't break other platforms. That of course goes for C-code too, system specific code resides in the `$ERL_TOP/erts/emulator/sys/win32` and `$ERL_TOP/erts/etc/win32` directories mostly. The -`$ERL_TOP/erts/emulator/beam directory` is for common code. +`$ERL_TOP/erts/emulator/beam` directory is for common code. Before the R9C release of Erlang/OTP, the Windows release was built partly on a Unix (Solaris) box and partly on a Windows box, using Perl @@ -61,6 +63,21 @@ their problems, please try to solve the problems and submit solutions/workarounds. Remember, it's all about sharing, not about demanding... +Starting with R15B, our build system runs both on Cygwin and Msys +(MinGW's fork of an early cygwin version). Msys is a smaller package +to install and may on some machines run slightly faster. If Cygwin +gives you trouble, try Msys instead, and v.v. Beginning with R15B +there is also a native 64bit version of Erlang for 64bit Windows 7 +(only). These instructions apply to both the 32bit VM and the 64bit +ditto. + +Note that even if you build a 64bit VM, most of the directories and +files involved are still named win32. You can view the name win32 as +meaning any windows version not beeing 16bit. A few occurences of the +name Win64 are however present in the system, for example the +installation file for a 64 bit windows version of Erlang is by default +named `otp_win64_<version>.exe`. + Lets go then, I'll start with a little FAQ, based on in house questions and misunderstandings. @@ -70,10 +87,13 @@ Frequently Asked Questions * Q: So, now I can build Erlang using GCC on Windows? - A: No, unfortunately not. You'll need Microsoft's Visual C++ still, a - Bourne-shell script (cc.sh) wraps the Visual C++ compiler and runs it - from within the Cygwin environment. All other tools needed to build - Erlang are free-ware/open source, but not the C compiler. + A: No, unfortunately not. You'll need Microsoft's Visual C++ + still, a Bourne-shell script (cc.sh) wraps the Visual C++ compiler + and runs it from within the Cygwin environment. All other tools + needed to build Erlang are free-ware/open source, but not the C + compiler. The Windows SDK is however enough to build Erlang, you + do not need to buy Visual C++, just download the SDK (SDK version + 7.1 == Visual studio 2010). * Q: Why haven't you got rid of VC++ then, you \*\*\*\*\*\*? @@ -83,18 +103,22 @@ Frequently Asked Questions directories). Unfortunately the development of the SMP version for Windows broke the mingw build and we chose to focus on the VC++ build as the performance has been much better in the VC++ versions. The - mingw build will be back, but as long as VC++ gives better + mingw build will possibly be back, but as long as VC++ gives better performance, the commercial build will be a VC++ one. -* Q: OK, VC++ you need, but now you've started to demand a very recent +* Q: OK, you need VC++, but now you've started to demand a very recent (and expensive) version of Visual studio, not the old and stable VC++ 6.0 that was used in earlier versions. Why? - A: The SMP version of Erlang needs features in the Visual Studio 2005. - Can't live without them. Besides the new compiler gives the Erlang - emulator a ~40% performance boost(!). Alternatively you can build Erlang - successfully using the free (proprietary) Visual Studio 2008 Express - edition C++ compiler. + A: Well, it's not expensive, it's free (as in free beer). Just + download and install the latest Windows SDK from Microsoft and all + the tools you need are there. The included debugger (WinDbg) is + also quite usable, it's what I used when porting Erlang to 64bit + Windows. Another reason to use the latest Microsoft compilers is + DLL compatibility. DLL's using a new version of the standard + library might not load if the VM is compiled with an old VC++ + version, why we should aim to use the latest freely available SDK + and compiler. * Q: Can/will I build a Cygwin binary with the procedure you describe? @@ -112,15 +136,15 @@ Frequently Asked Questions * Q: Hah, I saw you, you used GCC even though you said you didn't! - A: OK, I admit, one of the files is compiled using Cygwin's GCC and - the resulting object code is then converted to MS VC++ compatible coff - using a small C hack. It's because that particular file, `beam_emu.c` - benefits immensely from being able to use the GCC labels-as-values - extension, which boosts emulator performance by up to 50%. That does - unfortunately not (yet) mean that all of OTP could be compiled using - GCC, that particular source code does not do anything system specific - and actually is adopted to the fact that GCC is used to compile it on - Windows. + A: OK, I admit, one of the files is compiled using Cygwin's or + MinGW's GCC and the resulting object code is then converted to MS + VC++ compatible coff using a small C hack. It's because that + particular file, `beam_emu.c` benefits immensely from being able + to use the GCC labels-as-values extension, which boosts emulator + performance by up to 50%. That does unfortunately not (yet) mean + that all of OTP could be compiled using GCC, that particular + source code does not do anything system specific and actually is + adopted to the fact that GCC is used to compile it on Windows. * Q: So now there's a MS VC++ project file somewhere and I can build OTP using the nifty VC++ GUI? @@ -135,31 +159,36 @@ Frequently Asked Questions * Q: So how does it all work then? - A: Cygwin is the environment, which closely resembles the environments - found on any Unix machine. It's almost like you had a virtual Unix - machine inside Windows. Configure, given certain parameters, then - creates makefiles that are used by the Cygwin gnu-make to built the - system. Most of the actual compilers etc are not, however, Cygwin - tools, so I've written a couple of wrappers (Bourne-shell scripts), - which reside in `$ERL_TOP/etc/win32/cygwin_tools` and they all do - conversion of parameters and switches common in the Unix environment - to fit the native Windows tools. Most notable is of course the paths, - which in Cygwin are Unix-like paths with "forward slashes" (/) and no - drive letters, the Cygwin specific command `cygpath` is used for most - of the path conversions. Luckily most compilers accept forward slashes - instead of backslashes as path separators, one still have to get the - drive letters etc right, though. The wrapper scripts are not general - in the sense that, for example, cc.sh would understand and translates - every possible gcc option and passes correct options to cl.exe. The - principle is that the scripts are powerful enough to allow building of - Erlang/OTP, no more, no less. They might need extensions to cope with - changes during the development of Erlang, that's one of the reasons I - made them into shell-scripts and not Perl-scripts, I believe they are - easier to understand and change that way. I might be wrong though, - cause another reason I didn't write them in Perl is because I've never - liked Perl and my Perl code is no pleasant reading... - - In `$ERL_TOP`, there is a script called `otp_build`, that script handles + A: Cygwin or Msys is the environment, which closely resembles the + environments found on any Unix machine. It's almost like you had a + virtual Unix machine inside Windows. Configure, given certain + parameters, then creates makefiles that are used by the + Cygwin/Msys gnu-make to built the system. Most of the actual + compilers etc are not, however, Cygwin/Msys tools, so I've written + a couple of wrappers (Bourne-shell scripts), which reside in + `$ERL_TOP/etc/win32/cygwin_tools` and + `$ERL_TOP/etc/win32/msys_tools`. They all do conversion of + parameters and switches common in the Unix environment to fit the + native Windows tools. Most notable is of course the paths, which + in Cygwin/Msys are Unix-like paths with "forward slashes" (/) and + no drive letters, the Cygwin specific command `cygpath` is used + for most of the path conversions in a Cygwin environment, other + tools are used (when needed) in the corresponding Msys + environment. Luckily most compilers accept forward slashes instead + of backslashes as path separators, but one still have to get the drive + letters etc right, though. The wrapper scripts are not general in + the sense that, for example, cc.sh would understand and translates + every possible gcc option and passes correct options to + cl.exe. The principle is that the scripts are powerful enough to + allow building of Erlang/OTP, no more, no less. They might need + extensions to cope with changes during the development of Erlang, + that's one of the reasons I made them into shell-scripts and not + Perl-scripts, I believe they are easier to understand and change + that way. I might be wrong though, cause another reason I didn't + write them in Perl is because I've never liked Perl and my Perl + code is no pleasant reading... + + In `$ERL_TOP`, there is a script called `otp_build`. That script handles the hassle of giving all the right parameters to `configure`/`make` and also helps you set up the correct environment variables to work with the Erlang source under Cygwin. @@ -177,17 +206,19 @@ Frequently Asked Questions A: Yes, we use the exactly same build procedure. -* Q: Which version of Cygwin and other tools do you use then? +* Q: Which version of Cygwin/Msys and other tools do you use then? - A: For Cygwin we try to use the latest releases available when - building. What versions you use shouldn't really matter, I try to - include workarounds for the bugs I've found in different Cygwin - releases, please help me to add workarounds for new Cygwin-related - bugs as soon as you encounter them. Also please do submit bug reports - to the appropriate Cygwin developers. The Cygwin GCC we used for %OTP-REL% - was version 3.4.4. We used VC++ 8.0 (i.e. Visual studio 2005 SP1), - Sun's JDK 1.5.0\_17, NSIS 2.37, and Win32 OpenSSL 0.9.8e. Please read - the next section for details on what you need. + A: For Cygwin and Msys alike, we try to use the latest releases + available when building. What versions you use shouldn't really + matter, I try to include workarounds for the bugs I've found in + different Cygwin/Msys releases, please help me to add workarounds + for new Cygwin/Msys-related bugs as soon as you encounter + them. Also please do submit bug reports to the appropriate Cygwin + adn/or Msys developers. The GCC we used for %OTP-REL% was version + 4.7.0 (MinGW 64bit) and 4.3.4 (Cygwin 32bit). We used VC++ 10.0 + (i.e. Visual studio 2010), Sun's JDK 1.5.0\_17 (32bit) and Sun's + JDK 1.7.0\_1 (64bit), NSIS 2.46, and Win32 OpenSSL 0.9.8r. Please + read the next section for details on what you need. * Q: Can you help me setup X in Cygwin? @@ -201,24 +232,21 @@ Frequently Asked Questions described as much as I could about the installation of the needed tools. Once the tools are installed, building is quite easy. I also have tried to make this instruction understandable for people with - limited Unix experience. Cygwin is a whole new environment to some + limited Unix experience. Cygwin/Msys is a whole new environment to some Windows users, why careful explanation of environment variables etc seemed to be in place. The short story, for the experienced and impatient is: - * Get and install complete Cygwin (latest) - - * (Buy and) Install Microsoft Visual studio 2005 and SP1 (or higher) + * Get and install complete Cygwin (latest) or complete MinGW with msys - * Alternatively install the free MS Visual Studio 2008 Express [msvc++] - and the Windows SDK [32bit-SDK] or [64bit-SDK] depending on the Windows - platform you are running. + * Install Microsofts Windows SDK 7.1 (and .Net 4) - * Get and install Sun's JDK 1.4.2 + * Get and install Sun's JDK 1.5.0 or higher * Get and install NSIS 2.01 or higher (up to 2.46 tried and working) - * Get and install OpenSSL 0.9.7c or higher (up to 1.0.0a tried & working) + * Get, build and install OpenSSL 0.9.8r or higher (up to 1.0.0a + tried & working) with static libs. * Get the Erlang source distribution (from <http://www.erlang.org/download.html>) and unpack with Cygwin's `tar`. @@ -251,10 +279,9 @@ Tools you Need and Their Environment ------------------------------------ You need some tools to be able to build Erlang/OTP on Windows. Most -notably you'll need Cygwin and Microsoft VC++, but you also might want -a Java compiler, the NSIS install system and OpenSSL. Only VC++ costs -money, but then again it costs a lot of money, I know... -Well' here's the list: +notably you'll need Cygwin or Msys and Microsofts Windows SDK, but +you also might want a Java compiler, the NSIS install system and +OpenSSL. Well' here's the list: * Cygwin, the very latest is usually best. Get all the development tools and of course all the basic ditto. In fact getting the complete @@ -263,6 +290,10 @@ Well' here's the list: sure *not* to install a Cygwin'ish Java... The Cygwin jar command is used but Sun's Java compiler and virtual machine... + If you are going to build a 64bit Windows version, you should make + sure to get MinGWs 64bit gcc installed with cygwin. It's in one of + the development packages. + URL: <http://www.cygwin.com> Get the installer from the web site and use that to install @@ -302,72 +333,205 @@ Well' here's the list: haven't tried and know of no one that has. I expect that you use bash in all shell examples. -* Microsoft Visual Studio 2005 SP1. Please don't skip the service - pack! The installer might update your environment so that you can run - the `cl` command from the bash prompt, then again it might - not... There is always a BAT file in VC\Bin under the installation - directory (default `C:\Program Files\Microsoft Visual Studio 8`) called - `VCVARS32.BAT`. Either add the environment settings in that file to the - global environment settings in Windows or add the corresponding BASH - environment settings to your `.profile`/`.bashrc`. For example, in my case - I could add the following to `.profile` - - #Visual C++ Root directory as Cygwin style pathname - VCROOT=/cygdrive/c/Program\ Files/Microsoft\ Visual\ Studio 8 - - # Visual C++ Root directory as Windows style pathname - WIN_VCROOT="C:\\Program Files\\Microsoft Visual Studio 8" - - # The PATH variable should be Cygwin'ish - PATH=$VCROOT/Common7/IDE:$VCROOT/VC/BIN:$VCROOT/Common7/Tools:\ - $VCROOT/Common7/Tools/bin:$VCROOT/VC/PlatformSDK/bin:$VCROOT/SDK/v2.0/bin:\ - $VCROOT/VC/VCPackages:$PATH - - # Lib and INCLUDE should be Windows'ish - # Note that semicolon (;) is used to separate Windows style paths but - # colon (:) to separate Cygwin ditto! - - LIBPATH=$WIN_VCROOT\\VC\\ATLMFC\\LIB - - LIB=$WIN_VCROOT\\VC\\ATLMFC\\LIB\;$WIN_VCROOT\\VC\\LIB\;\ - $WIN_VCROOT\\VC\\PlatformSDK\\lib\;$WIN_VCROOT\\SDK\\v2.0\\lib - - INCLUDE=$WIN_VCROOT\\VC\\ATLMFC\\INCLUDE\;$WIN_VCROOT\\VC\\INCLUDE\;\ - $WIN_VCROOT\\VC\\PlatformSDK\\include - - export PATH LIB INCLUDE - - Make a simple hello world and try to compile it with the `cl` command - from within bash. If that does not work, your environment needs - fixing. Also remember to fix up the PATH environment, especially old - Erlang installations might have inserted quoted paths that Cygwin does - not understand. Remove or correct such paths. There should be no - backslashes in your path environment variable in Cygwin bash, but LIB - and INCLUDE should contain Windows style paths with semicolon, - drive letters and backslashes. - - If you wish to use Visual Studio 2008, a couple things need to be tweaked, - namely the fact that some of the SDK stuff is installed in (by default) - `C:\Program Files\Microsoft SDKs\v6.0A` . Just ensure that that - `C:\Program Files\Microsoft SDKs\v6.0A\Lib` is in `LIB` and - `C:\Program Files\Microsoft SDKs\v6.0A\Include` is in `INCLUDE`. A symptom - of not doing this is errors about finding kernel32.lib and windows.h. - - Additionally, if you encounter errors about mc.exe not being found, you must - install the entire Windows SDK (the partial SDK included in visual studio - apparently does not include it). After installing it you'll want to add - something like: `/c/cygdrive/Program\ Files/Microsoft\ SDKs/v7.0/bin` to - your `PATH` to allow the environment to find mc.exe. The next Visual Studio - (2010) is expected to include this tool. - - Alternatively install the free MS Visual Studio 2008 Express [msvc++] and - the Windows SDK [32bit-SDK] or [64bit-SDK] depending on the Windows - platform you are running, which includes the missing mc.exe message - compiler. - -[msvc++]: http://download.microsoft.com/download/E/8/E/E8EEB394-7F42-4963-A2D8-29559B738298/VS2008ExpressWithSP1ENUX1504728.iso -[32bit-SDK]: http://download.microsoft.com/download/2/E/9/2E911956-F90F-4BFB-8231-E292A7B6F287/GRMSDK_EN_DVD.iso -[64bit-SDK]: http://download.microsoft.com/download/2/E/9/2E911956-F90F-4BFB-8231-E292A7B6F287/GRMSDKX_EN_DVD.iso +* Alternatively you download MinGW and Msys. You'll find the latest + installer at: + + URL: <http://sourceforge.net/projects/mingw/files/Installer/mingw-get-inst/> + + Make sure to install everything they've got. + + To be able to build the 64bit VM, you will also need the 64bit + MinGW compiler from: + + URL: <http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Automated%20Builds/> + + The latest version should do it. Make sure you download the + `mingw-w64-bin_i686-mingw_<something>.zip`, not a linux + version. You unzip the package on top of your MinGW installation + (`c:\MinGW`) and that's it. + + Setting up your environment in Msys is similar to setting it up in + Cygwin. + +* Microsofts Windows SDK version 7.1 (corresponding to VC++ 10.0 and + Visual Studio 2010). You'll find it here: + + URL: <http://www.microsoft.com/download/en/details.aspx?id=8279> + + but before you install that, you need to have .Net 4 installed, + you'll find that here: + + URL: <http://www.microsoft.com/download/en/details.aspx?id=17851> + + Use the web installer for the SDK, at least when I tried + downloading the whole package as an image, I got SDK 7.0 instead, + which is not what you want... + + There will be a Windows command file in `%PROGRAMFILES%\Mirosoft + SDKs\Windows\v7.1\Bin\SetEnv.cmd` that set's the appropriate + environment for a Windows command prompt. This is not appropriate + for bash, so you'll need to convert it to bash-style environments + by editing your `.bash_profile`. In my case, where the SDK is + installed in the default directory and `%PROGRAMFILES%` is + `C:\Program Files`, the commands for setting up a 32bit build + environment (on a 64bit or 32bit machine) look like this (in cygwin): + + # Some common paths + C_DRV=/cygdrive/c + PRG_FLS=$C_DRV/Program\ Files + + # nsis + NSIS_BIN=$PRG_FLS/NSIS + # java + JAVA_BIN=$PRG_FLS/Java/jdk1.6.0_16/bin + + ## + ## MS SDK + ## + + CYGWIN=nowinsymlinks + MVS10="$PRG_FILES/Microsoft Visual Studio 10.0" + WIN_MVS10="C:\\Program Files\\Microsoft Visual Studio 10.0" + SDK10="$PRG_FILES/Microsoft SDKs/Windows/v7.1" + WIN_SDK10="C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1" + + PATH="$NSIS_BIN:\ + $MVS10/Common7/IDE:\ + $MVS10/Common7/Tools:\ + $MVS10/VC/Bin:\ + $MVS10/VC/Bin/VCPackages:\ + $SDK10/Bin/NETFX 4.0 Tools:\ + $SDK10/Bin:\ + /usr/local/bin:/usr/bin:/bin:\ + /cygdrive/c/WINDOWS/system32:/cygdrive/c/WINDOWS:\ + /cygdrive/c/WINDOWS/system32/Wbem:\ + $JAVA_BIN" + + LIBPATH="$WIN_MVS10\\VC\\LIB" + + LIB="$WIN_MVS10\\VC\\LIB;$WIN_SDK10\\LIB" + + INCLUDE="$WIN_MVS10\\VC\\INCLUDE;$WIN_SDK10\\INCLUDE;$WIN_SDK10\\INCLUDE\\gl" + + export CYGWIN PATH LIBPATH LIB INCLUDE + + If you're using Msys instead, the only thing you need to change is + the `C_DRV` setting, which would read: + + C_DRV=/c + + And of course you might need to change `C:\Program Files` etc if + you're using a non-english version of Windows (XP). Note that in + later versions of Windows, the national adoptions of the program + files directories etc are not on the file system but only in the + explorer, so even if explorer says that your programs reside in + e.g. `C:\Program`, they might still reside in `C:\Program Files` + in reality... + + If you are building a 64 bit verision of Erlang, you should set up + PATHs etc a little differently. I use the following script to + make things work in both Cygwin and Msys: + + make_winpath() + { + P=$1 + if [ "$IN_CYGWIN" = "true" ]; then + cygpath -d "$P" + else + (cd "$P" && /bin/cmd //C "for %i in (".") do @echo %~fsi") + fi + } + + make_upath() + { + P=$1 + if [ "$IN_CYGWIN" = "true" ]; then + cygpath "$P" + else + echo "$P" | /bin/sed 's,^\([a-zA-Z]\):\\,/\L\1/,;s,\\,/,g' + fi + } + + # Some common paths + if [ -x /usr/bin/msysinfo ]; then + # Without this the path conversion won't work + COMSPEC='C:\Windows\SysWOW64\cmd.exe' + MSYSTEM=MINGW32 + export MSYSTEM COMSPEC + IN_CYGWIN=false + else + CYGWIN=nowinsymlinks + export CYGWIN + IN_CYGWIN=true + fi + + if [ "$IN_CYGWIN" = "true" ]; then + PATH=/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:\ + /cygdrive/c/windows/system32:/cygdrive/c/windows:/cygdrive/c/windows/system32/Wbem + else + PATH=/usr/local/bin:/mingw/bin:/bin:/c/Windows/system32:/c/Windows:\ + /c/Windows/System32/Wbem + fi + + if [ "$IN_CYGWIN" = "true" ]; then + C_DRV=/cygdrive/c + else + C_DRV=/c + fi + + PRG_FLS64=$C_DRV/Program\ Files + PRG_FLS32=$C_DRV/Program\ Files\ \(x86\) + VISUAL_STUDIO_ROOT32=$PRG_FLS32/Microsoft\ Visual\ Studio\ 10.0 + MS_SDK_ROOT64=$PRG_FLS64/Microsoft\ SDKs/Windows/v7.1 + + # Okay, now mangle the paths and get rid of spaces by using short names + WIN_VCROOT32=`make_winpath "$VISUAL_STUDIO_ROOT32"` + VCROOT32=`make_upath $WIN_VCROOT32` + WIN_SDKROOT64=`make_winpath "$MS_SDK_ROOT64"` + SDKROOT64=`make_upath $WIN_SDKROOT64` + WIN_PROGRAMFILES32=`make_winpath "$PRG_FLS32"` + PROGRAMFILES32=`make_upath $WIN_PROGRAMFILES32` + + WIN_PROGRAMFILES64=`make_winpath "$PRG_FLS64"` + PROGRAMFILES64=`make_upath $WIN_PROGRAMFILES64` + + # nsis + NSIS_BIN=$PROGRAMFILES32/NSIS + # java + JAVA_BIN=$PROGRAMFILES64/Java/jdk1.7.0_01/bin + + ## The PATH variable should be Unix'ish + VCPATH=$VCROOT32/Common7/IDE:$VCROOT32/VC/BIN/amd64:$VCROOT32/Common7/Tools:\ + $VCROOT32/VC/VCPackages:$SDKROOT64/bin/NETFX4~1.0TO/x64:$SDKROOT64/bin/x64:\ + $SDKROOT64/bin + + ## Microsoft SDK libs + + LIBPATH=$WIN_VCROOT32\\VC\\LIB\\amd64 + LIB=$WIN_VCROOT32\\VC\\LIB\\amd64\;$WIN_SDKROOT64\\LIB\\X64 + INCLUDE=$WIN_VCROOT32\\VC\\INCLUDE\;$WIN_SDKROOT64\\include\;\ + $WIN_SDKROOT64\\include\\gl + + # Put nsis, c compiler and java in path + PATH=$NSIS_BIN:$VCPATH:$PATH:$JAVA_BIN + + # Make sure LIB and INCLUDE is available for others + export PATH LIBPATH LIB INCLUDE + + All this is derived from the SetEnv.cmd command file mentioned + earlier. The bottom line is to set the PATH so that NSIS and + Microsoft SDK is found before the Msys/Cygwin tools and that Java + is last in the PATH. + + Make a simple hello world (maybe one that prints out + `sizeof(void *)`) and try to compile it with the `cl` command from within + bash. If that does not work, your environment needs fixing. Also + remember to fix up the PATH environment, especially old Erlang + installations might have inserted quoted paths that Cygwin/Msys + does not understand. Remove or correct such paths. There should be + no backslashes in your path environment variable in Cygwin bash, + but LIB and INCLUDE should contain Windows style paths with + semicolon, drive letters and backslashes. * Sun's Java JDK 1.5.0 or higher. Our Java code (jinterface, ic) is written for JDK 1.5.0. Get it for Windows and install it, the JRE is @@ -378,11 +542,11 @@ Well' here's the list: Add javac *LAST* to your path environment in bash, in my case this means: - PATH="$PATH:/cygdrive/c/Program Files/Java/jdk1.5.0_17/bin" + `PATH="$PATH:/cygdrive/c/Program Files/Java/jdk1.5.0_17/bin"` No `CLASSPATH` or anything is needed. Type `javac` at the bash prompt and you should get a list of available Java options. Make sure by - typing `which java` that you use the Java you installed. Note however that + typing `type java` that you use the Java you installed. Note however that Cygwin's `jar.exe` is used, that's why the JDK bin-directory should be added last in the `PATH`. @@ -402,29 +566,75 @@ Well' here's the list: type makensis at the bash prompt and you should get a list of options if everything is OK. -* OpenSSL for Windows. This is if you want the SSL and crypto - applications to compile (and run). Go to <http://www.openssl.org>, click - on the `Related` link and then on the `Binaries` link (upper right - corner of the page last time I looked), you can then reach the - "Shining Lights Productions" Web site for Windows binaries - distributions. Get the latest 32-bit installer, or use 0.9.7c if you get - trouble with the latest, and install to C:\OpenSSL which is where the - Makefiles are expecting to find it. It's a nifty installer. The rest should - be handled by `configure`, you needn't put anything in the path or anything. - - If you want to build openssl for windows yourself (which might be - possible, as you wouldn't be reading this if you weren't a - compile-it-yourself person), you either have to put the resulting - DLL's in your path or in the windows system directory and either - specify where you put the includes etc with the configure-parameter - `--with-ssl=<cygwin path to the root>` or put your installation directly - under `c:\OpenSSL`. The directory structure under the installation root - for OpenSSL is expected to be one with subdirectories named `include`, - `bin` and `lib`, possibly with a `VC` subdirectory of `lib` containing - the actual `.lib` files. Note that the cygwin distributed OpenSSL cannot be - used, it results in cygwin depending binaries and it has unix style - archives (`.a`, not `.lib`). +* OpenSSL. This is if you want the SSL and crypto applications to + compile (and run). There are prebuilt binaries available, but I + strongly recommend building this yourself. It's quite easy. + + First get the source from + + URL: <http://openssl.org/source/> + + I would recommend using 0.9.8r. + + Download the tar file and unpack it (using your bash prompt) into + a directory of your choise. + + You will need a Windowish Perl for the build. ActiveState has one: + + URL: <http://www.activestate.com/activeperl/downloads> + + Download and install that. Disable options to associate it with + the .pl suffix and/or adding things to PATH, they are not needed. + + Now fire up the Microsoft Windows SDK command prompt in RELEASE + mode for the architecture you are going to build. The easiest is + to copy the shortcut from the SDKs start menu item and edit the + command line in the shortcut (Right click->Properties) to end with + `/Release`. Make sure the banner when you double click your + shortcut (the text in the resulting command window) says + `Targeting Windows XP x64 Release` if you are going to do a 64 bit + build and `Targeting Windows XP x86 Release` if you are building a + 32 bit version. + + Now cd to where you unpacked the OpenSSL source using your Release + Windows command prompt (it should be on the same drive as where + you are going to install it if everything is to work smothly). + + `C:\> cd <some dir>` + + Add ActiveState (or some other windows perl, not cygwins) to your PATH: + + `C:\...\> set PATH=C:\Perl\bin;%PATH%` + + Configure OpenSSL for 32 bit: + `C:\...\> perl Configure VC-WIN32 --prefix=/OpenSSL` + + Or for 64 bit: + + `C:\...\> perl Configure VC-WIN64A --prefix=/OpenSSL-Win64` + + Do some setup (for 32 bit): + + `C:\...\> ms\do_win32` + + The same for 64 bit: + + `C:\...\> ms\do_win64a` + + Then build static libraries and install: + + `C:\...\> nmake -f ms\nt.mak` + `C:\...\> nmake -f ms\nt.mak install` + + That's it - you now have your perfectly consistent static build of + openssl. If you want to get rid of any possibly patented + algorithms in the lib, just read up on the OpenSSL FAQ and follow + the instructions. + + The installation locations chosen are where configure will look + for OpenSSL, so try to keep them as is. + * Building with wxWidgets. Download wxWidgets-2.8.9 or higher patch release (2.9.\* is a developer release which currently does not work with wxErlang). @@ -473,6 +683,9 @@ Well' here's the list: erlang system without gs (which might be okay as you probably will use wx anyway). + Note that there is no special 64bit version of TCL/TK needed, you + can use the 32bit program even for a 64bit build. + The Shell Environment --------------------- @@ -500,6 +713,12 @@ the ksh variant: $ cd $ERL_TOP $ eval $(./otp_build env_win32) +If you are building a 64 bit version, you supply `otp_build` with an architecture parameter: + + $ cd $ERL_TOP + $ eval `./otp_build env_win32 x64` + + This should do the final touch to the environment and building should be easy after this. You could run `./otp_build env_win32` without `eval` just to see what it does, and to see that the environment it @@ -509,10 +728,11 @@ style short names instead), the variables `OVERRIDE_TARGET`, `CC`, `CXX`, `$ERL_TOP/erts/etc/win32/cygwin_tools/vc` and `$ERL_TOP/erts/etc/win32/cygwin_tool` are added first in the PATH. -Try now a `which erlc`. That should result in the erlc wrapper script +Try now a `type erlc`. That should result in the erlc wrapper script (which does not have the .sh extension, for reasons best kept -untold...). It should reside in `$ERL_TOP/erts/etc/win32/cygwin_tools`. -You could also try `which cc.sh`, which `ar.sh` etc. +untold...). It should reside in `$ERL_TOP/erts/etc/win32/cygwin_tools` +or `$ERL_TOP/erts/etc/win32/msys_tools`. You could also try `which +cc.sh`, which `ar.sh` etc. Now you're ready to build... @@ -520,8 +740,8 @@ Now you're ready to build... Building and Installing ----------------------- -Now it's assumed that you have executed `` eval `./otp_build env_win32` `` -for this particular shell... +Now it's assumed that you have executed `` eval `./otp_build env_win32` `` or +`` eval `./otp_build env_win32 x64` `` for this particular shell... Building is easiest using the `otp_build` script. That script takes care of running configure, bootstrapping etc on Windows in a simple @@ -613,6 +833,13 @@ Lets get into more detail: $ release/win32/otp_win32_%OTP-REL% /S ... + or + + $ cd $ERL_TOP + $ release/win32/otp_win64_%OTP-REL% /S + ... + + and after a while Erlang/OTP-%OTP-REL% will have been installed in `C:\Program Files\erl%ERTS-VSN%\`, with shortcuts in the menu etc. @@ -735,6 +962,22 @@ Remember that: That's basically all you need to get going. +Using GIT +--------- + +You might want to check out versions of the source code from GitHUB. That is possible directly in cygwin, but not in Msys. There is a project MsysGIT: + +URL:<http://code.google.com/p/msysgit/> + +that makes a nice Git port. The msys prompt you get from MsysGIT is +however not compatible with the full version from MinGW, so you will +need to check out files using MsysGITs command prompt and then switch +to a common Msys command prompt for building. Also all test suites +cannot be built as MsysGIT/Msys does not handle symbolic links. To +build test suites on Windows, you will need Cygwin for now. Hopefully +all symbolic links will disappear from our repository soon and this +issue will disappear. + Final Words ----------- My hope is that the possibility to build the whole system on Windows @@ -752,11 +995,15 @@ be good. The idea to do this came from his work, so credit is well deserved. Of course this would have been completely impossible without the -excellent Cygwin package. The guys at Cygnus solutions and Redhat -deserves a huge THANKS! as well as all the other people in the free -software community who have helped in creating the magnificent +excellent Cygwin. The guys at Cygnus solutions and +Redhat deserves a huge THANKS! as well as all the other people in the +free software community who have helped in creating the magnificent software that constitutes Cygwin. +Also the people developing the alternative command prompt Msys anfd +the MinGW compiler are worth huge THANKS! The 64bit port would have +been impossible without the 64bit MinGW compiler. + Good luck and Happy Hacking, Patrik, OTP diff --git a/Makefile.in b/Makefile.in index c88e967e36..2ded1b4356 100644 --- a/Makefile.in +++ b/Makefile.in @@ -598,6 +598,18 @@ secondary_bootstrap_copy: cp $$x $$TF; \ true; \ done + if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl ; fi + if test ! -d $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/include ; then mkdir $(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/include ; fi + for x in lib/xmerl/include/*.hrl; do \ + BN=`basename $$x`; \ + TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/xmerl/include/$$BN; \ + test -f $$TF && \ + test '!' -z "`find $$x -newer $$TF -print`" && \ + cp $$x $$TF; \ + test '!' -f $$TF && \ + cp $$x $$TF; \ + true; \ + done tertiary_bootstrap_build: cd lib && \ @@ -695,6 +707,18 @@ tertiary_bootstrap_copy: cp $$x $$TF; \ true; \ done +# copy wx_object to remove undef behaviour warnings + for x in lib/wx/ebin/wx_object.beam; do \ + BN=`basename $$x`; \ + TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/wx/ebin/$$BN; \ + test -f $$TF && \ + test '!' -z "`find $$x -newer $$TF -print`" && \ + cp $$x $$TF; \ + test '!' -f $$TF && \ + cp $$x $$TF; \ + true; \ + done + for x in lib/test_server/include/*.hrl; do \ BN=`basename $$x`; \ TF=$(BOOTSTRAP_ROOT)/bootstrap/lib/test_server/include/$$BN; \ diff --git a/bootstrap/bin/start.boot b/bootstrap/bin/start.boot Binary files differindex d0ac42d595..bdaf605488 100644 --- a/bootstrap/bin/start.boot +++ b/bootstrap/bin/start.boot diff --git a/bootstrap/bin/start_clean.boot b/bootstrap/bin/start_clean.boot Binary files differindex d0ac42d595..bdaf605488 100644 --- a/bootstrap/bin/start_clean.boot +++ b/bootstrap/bin/start_clean.boot diff --git a/bootstrap/lib/compiler/ebin/beam_asm.beam b/bootstrap/lib/compiler/ebin/beam_asm.beam Binary files differindex 103ed82529..4da4c26d92 100644 --- a/bootstrap/lib/compiler/ebin/beam_asm.beam +++ b/bootstrap/lib/compiler/ebin/beam_asm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_block.beam b/bootstrap/lib/compiler/ebin/beam_block.beam Binary files differindex a5699221fe..a7bb91adbb 100644 --- a/bootstrap/lib/compiler/ebin/beam_block.beam +++ b/bootstrap/lib/compiler/ebin/beam_block.beam diff --git a/bootstrap/lib/compiler/ebin/beam_bool.beam b/bootstrap/lib/compiler/ebin/beam_bool.beam Binary files differindex d8f91ec36d..252257b71d 100644 --- a/bootstrap/lib/compiler/ebin/beam_bool.beam +++ b/bootstrap/lib/compiler/ebin/beam_bool.beam diff --git a/bootstrap/lib/compiler/ebin/beam_bsm.beam b/bootstrap/lib/compiler/ebin/beam_bsm.beam Binary files differindex 02f82a9341..0c998c8e8c 100644 --- a/bootstrap/lib/compiler/ebin/beam_bsm.beam +++ b/bootstrap/lib/compiler/ebin/beam_bsm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_dead.beam b/bootstrap/lib/compiler/ebin/beam_dead.beam Binary files differindex 2f0f423f16..17cced3c1a 100644 --- a/bootstrap/lib/compiler/ebin/beam_dead.beam +++ b/bootstrap/lib/compiler/ebin/beam_dead.beam diff --git a/bootstrap/lib/compiler/ebin/beam_disasm.beam b/bootstrap/lib/compiler/ebin/beam_disasm.beam Binary files differindex 377c738709..f90b5c9ae7 100644 --- a/bootstrap/lib/compiler/ebin/beam_disasm.beam +++ b/bootstrap/lib/compiler/ebin/beam_disasm.beam diff --git a/bootstrap/lib/compiler/ebin/beam_except.beam b/bootstrap/lib/compiler/ebin/beam_except.beam Binary files differnew file mode 100644 index 0000000000..5bd28a35d9 --- /dev/null +++ b/bootstrap/lib/compiler/ebin/beam_except.beam diff --git a/bootstrap/lib/compiler/ebin/beam_jump.beam b/bootstrap/lib/compiler/ebin/beam_jump.beam Binary files differindex f45b8d3124..4811360890 100644 --- a/bootstrap/lib/compiler/ebin/beam_jump.beam +++ b/bootstrap/lib/compiler/ebin/beam_jump.beam diff --git a/bootstrap/lib/compiler/ebin/beam_receive.beam b/bootstrap/lib/compiler/ebin/beam_receive.beam Binary files differindex ae873a1082..43f41f6535 100644 --- a/bootstrap/lib/compiler/ebin/beam_receive.beam +++ b/bootstrap/lib/compiler/ebin/beam_receive.beam diff --git a/bootstrap/lib/compiler/ebin/beam_trim.beam b/bootstrap/lib/compiler/ebin/beam_trim.beam Binary files differindex b1275f787a..86f5d027f4 100644 --- a/bootstrap/lib/compiler/ebin/beam_trim.beam +++ b/bootstrap/lib/compiler/ebin/beam_trim.beam diff --git a/bootstrap/lib/compiler/ebin/beam_type.beam b/bootstrap/lib/compiler/ebin/beam_type.beam Binary files differindex 6689135457..116da39f89 100644 --- a/bootstrap/lib/compiler/ebin/beam_type.beam +++ b/bootstrap/lib/compiler/ebin/beam_type.beam diff --git a/bootstrap/lib/compiler/ebin/beam_utils.beam b/bootstrap/lib/compiler/ebin/beam_utils.beam Binary files differindex b80810bfb2..9c6ad019f9 100644 --- a/bootstrap/lib/compiler/ebin/beam_utils.beam +++ b/bootstrap/lib/compiler/ebin/beam_utils.beam diff --git a/bootstrap/lib/compiler/ebin/beam_validator.beam b/bootstrap/lib/compiler/ebin/beam_validator.beam Binary files differindex fd3aa7eee5..52643de79a 100644 --- a/bootstrap/lib/compiler/ebin/beam_validator.beam +++ b/bootstrap/lib/compiler/ebin/beam_validator.beam diff --git a/bootstrap/lib/compiler/ebin/cerl.beam b/bootstrap/lib/compiler/ebin/cerl.beam Binary files differindex 399aeb6442..dcebe13bc8 100644 --- a/bootstrap/lib/compiler/ebin/cerl.beam +++ b/bootstrap/lib/compiler/ebin/cerl.beam diff --git a/bootstrap/lib/compiler/ebin/cerl_clauses.beam b/bootstrap/lib/compiler/ebin/cerl_clauses.beam Binary files differindex e4db75d0e0..97e96c47bd 100644 --- a/bootstrap/lib/compiler/ebin/cerl_clauses.beam +++ b/bootstrap/lib/compiler/ebin/cerl_clauses.beam diff --git a/bootstrap/lib/compiler/ebin/cerl_inline.beam b/bootstrap/lib/compiler/ebin/cerl_inline.beam Binary files differindex 582604e3cc..b640e22ce6 100644 --- a/bootstrap/lib/compiler/ebin/cerl_inline.beam +++ b/bootstrap/lib/compiler/ebin/cerl_inline.beam diff --git a/bootstrap/lib/compiler/ebin/cerl_trees.beam b/bootstrap/lib/compiler/ebin/cerl_trees.beam Binary files differindex 673954eaac..df3f351c8d 100644 --- a/bootstrap/lib/compiler/ebin/cerl_trees.beam +++ b/bootstrap/lib/compiler/ebin/cerl_trees.beam diff --git a/bootstrap/lib/compiler/ebin/compile.beam b/bootstrap/lib/compiler/ebin/compile.beam Binary files differindex b228900c41..e2bd3c4ce0 100644 --- a/bootstrap/lib/compiler/ebin/compile.beam +++ b/bootstrap/lib/compiler/ebin/compile.beam diff --git a/bootstrap/lib/compiler/ebin/core_lib.beam b/bootstrap/lib/compiler/ebin/core_lib.beam Binary files differindex ddb5278d00..1a60454b42 100644 --- a/bootstrap/lib/compiler/ebin/core_lib.beam +++ b/bootstrap/lib/compiler/ebin/core_lib.beam diff --git a/bootstrap/lib/compiler/ebin/core_lint.beam b/bootstrap/lib/compiler/ebin/core_lint.beam Binary files differindex 225fa95aea..08fef1eb71 100644 --- a/bootstrap/lib/compiler/ebin/core_lint.beam +++ b/bootstrap/lib/compiler/ebin/core_lint.beam diff --git a/bootstrap/lib/compiler/ebin/core_parse.beam b/bootstrap/lib/compiler/ebin/core_parse.beam Binary files differindex 11926c4a16..4f555d8036 100644 --- a/bootstrap/lib/compiler/ebin/core_parse.beam +++ b/bootstrap/lib/compiler/ebin/core_parse.beam diff --git a/bootstrap/lib/compiler/ebin/core_pp.beam b/bootstrap/lib/compiler/ebin/core_pp.beam Binary files differindex f1841d810b..ef3504058a 100644 --- a/bootstrap/lib/compiler/ebin/core_pp.beam +++ b/bootstrap/lib/compiler/ebin/core_pp.beam diff --git a/bootstrap/lib/compiler/ebin/core_scan.beam b/bootstrap/lib/compiler/ebin/core_scan.beam Binary files differindex e0e4859095..245e59483d 100644 --- a/bootstrap/lib/compiler/ebin/core_scan.beam +++ b/bootstrap/lib/compiler/ebin/core_scan.beam diff --git a/bootstrap/lib/compiler/ebin/sys_core_fold.beam b/bootstrap/lib/compiler/ebin/sys_core_fold.beam Binary files differindex b07afc0938..046a358910 100644 --- a/bootstrap/lib/compiler/ebin/sys_core_fold.beam +++ b/bootstrap/lib/compiler/ebin/sys_core_fold.beam diff --git a/bootstrap/lib/compiler/ebin/sys_core_inline.beam b/bootstrap/lib/compiler/ebin/sys_core_inline.beam Binary files differindex 5b9e9d7c3e..907c9d53a5 100644 --- a/bootstrap/lib/compiler/ebin/sys_core_inline.beam +++ b/bootstrap/lib/compiler/ebin/sys_core_inline.beam diff --git a/bootstrap/lib/compiler/ebin/sys_expand_pmod.beam b/bootstrap/lib/compiler/ebin/sys_expand_pmod.beam Binary files differindex fbe8079575..1649b9f2ff 100644 --- a/bootstrap/lib/compiler/ebin/sys_expand_pmod.beam +++ b/bootstrap/lib/compiler/ebin/sys_expand_pmod.beam diff --git a/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam Binary files differindex 4b3e984ed4..a7ca15a033 100644 --- a/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam +++ b/bootstrap/lib/compiler/ebin/sys_pre_attributes.beam diff --git a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam Binary files differindex 12664c7270..d716583b97 100644 --- a/bootstrap/lib/compiler/ebin/sys_pre_expand.beam +++ b/bootstrap/lib/compiler/ebin/sys_pre_expand.beam diff --git a/bootstrap/lib/compiler/ebin/v3_codegen.beam b/bootstrap/lib/compiler/ebin/v3_codegen.beam Binary files differindex 3a8d68a611..a053c54295 100644 --- a/bootstrap/lib/compiler/ebin/v3_codegen.beam +++ b/bootstrap/lib/compiler/ebin/v3_codegen.beam diff --git a/bootstrap/lib/compiler/ebin/v3_core.beam b/bootstrap/lib/compiler/ebin/v3_core.beam Binary files differindex ff7144c2bc..ba92ff6fb0 100644 --- a/bootstrap/lib/compiler/ebin/v3_core.beam +++ b/bootstrap/lib/compiler/ebin/v3_core.beam diff --git a/bootstrap/lib/compiler/ebin/v3_kernel.beam b/bootstrap/lib/compiler/ebin/v3_kernel.beam Binary files differindex 48b89b374b..0c2e54032a 100644 --- a/bootstrap/lib/compiler/ebin/v3_kernel.beam +++ b/bootstrap/lib/compiler/ebin/v3_kernel.beam diff --git a/bootstrap/lib/compiler/ebin/v3_life.beam b/bootstrap/lib/compiler/ebin/v3_life.beam Binary files differindex b7996884f4..ec8fcda8ee 100644 --- a/bootstrap/lib/compiler/ebin/v3_life.beam +++ b/bootstrap/lib/compiler/ebin/v3_life.beam diff --git a/bootstrap/lib/kernel/ebin/application_controller.beam b/bootstrap/lib/kernel/ebin/application_controller.beam Binary files differindex 38614f1285..9c94dbd5c7 100644 --- a/bootstrap/lib/kernel/ebin/application_controller.beam +++ b/bootstrap/lib/kernel/ebin/application_controller.beam diff --git a/bootstrap/lib/kernel/ebin/code_server.beam b/bootstrap/lib/kernel/ebin/code_server.beam Binary files differindex 567dcf93df..adc53aa5f3 100644 --- a/bootstrap/lib/kernel/ebin/code_server.beam +++ b/bootstrap/lib/kernel/ebin/code_server.beam diff --git a/bootstrap/lib/kernel/ebin/disk_log.beam b/bootstrap/lib/kernel/ebin/disk_log.beam Binary files differindex 3162c166fb..8dbe895823 100644 --- a/bootstrap/lib/kernel/ebin/disk_log.beam +++ b/bootstrap/lib/kernel/ebin/disk_log.beam diff --git a/bootstrap/lib/kernel/ebin/disk_log_1.beam b/bootstrap/lib/kernel/ebin/disk_log_1.beam Binary files differindex a61ef2ad3f..5e286cdd48 100644 --- a/bootstrap/lib/kernel/ebin/disk_log_1.beam +++ b/bootstrap/lib/kernel/ebin/disk_log_1.beam diff --git a/bootstrap/lib/kernel/ebin/disk_log_server.beam b/bootstrap/lib/kernel/ebin/disk_log_server.beam Binary files differindex 39197f3995..d985f64937 100644 --- a/bootstrap/lib/kernel/ebin/disk_log_server.beam +++ b/bootstrap/lib/kernel/ebin/disk_log_server.beam diff --git a/bootstrap/lib/kernel/ebin/dist_ac.beam b/bootstrap/lib/kernel/ebin/dist_ac.beam Binary files differindex c86598a689..3eae6b82a7 100644 --- a/bootstrap/lib/kernel/ebin/dist_ac.beam +++ b/bootstrap/lib/kernel/ebin/dist_ac.beam diff --git a/bootstrap/lib/kernel/ebin/dist_util.beam b/bootstrap/lib/kernel/ebin/dist_util.beam Binary files differindex 094d909535..7fc3325da4 100644 --- a/bootstrap/lib/kernel/ebin/dist_util.beam +++ b/bootstrap/lib/kernel/ebin/dist_util.beam diff --git a/bootstrap/lib/kernel/ebin/file.beam b/bootstrap/lib/kernel/ebin/file.beam Binary files differindex 3cdbaee1bf..c3289ba11f 100644 --- a/bootstrap/lib/kernel/ebin/file.beam +++ b/bootstrap/lib/kernel/ebin/file.beam diff --git a/bootstrap/lib/kernel/ebin/file_io_server.beam b/bootstrap/lib/kernel/ebin/file_io_server.beam Binary files differindex 3783cd7b11..8193949718 100644 --- a/bootstrap/lib/kernel/ebin/file_io_server.beam +++ b/bootstrap/lib/kernel/ebin/file_io_server.beam diff --git a/bootstrap/lib/kernel/ebin/file_server.beam b/bootstrap/lib/kernel/ebin/file_server.beam Binary files differindex 7b03c3ea0d..fd9a9924bb 100644 --- a/bootstrap/lib/kernel/ebin/file_server.beam +++ b/bootstrap/lib/kernel/ebin/file_server.beam diff --git a/bootstrap/lib/kernel/ebin/global.beam b/bootstrap/lib/kernel/ebin/global.beam Binary files differindex b4a6a5dc3e..96d7365006 100644 --- a/bootstrap/lib/kernel/ebin/global.beam +++ b/bootstrap/lib/kernel/ebin/global.beam diff --git a/bootstrap/lib/kernel/ebin/global_group.beam b/bootstrap/lib/kernel/ebin/global_group.beam Binary files differindex f1e6fa219e..dd7d0e429e 100644 --- a/bootstrap/lib/kernel/ebin/global_group.beam +++ b/bootstrap/lib/kernel/ebin/global_group.beam diff --git a/bootstrap/lib/kernel/ebin/group.beam b/bootstrap/lib/kernel/ebin/group.beam Binary files differindex 67f78948d4..8e813f6964 100644 --- a/bootstrap/lib/kernel/ebin/group.beam +++ b/bootstrap/lib/kernel/ebin/group.beam diff --git a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam Binary files differindex 515fe47da6..9412148a16 100644 --- a/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam +++ b/bootstrap/lib/kernel/ebin/hipe_unified_loader.beam diff --git a/bootstrap/lib/kernel/ebin/inet_dns.beam b/bootstrap/lib/kernel/ebin/inet_dns.beam Binary files differindex be1c7c4766..7f262cf20d 100644 --- a/bootstrap/lib/kernel/ebin/inet_dns.beam +++ b/bootstrap/lib/kernel/ebin/inet_dns.beam diff --git a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam Binary files differindex 4bf616ad46..4e6ce0fc5e 100644 --- a/bootstrap/lib/kernel/ebin/inet_gethost_native.beam +++ b/bootstrap/lib/kernel/ebin/inet_gethost_native.beam diff --git a/bootstrap/lib/kernel/ebin/net_kernel.beam b/bootstrap/lib/kernel/ebin/net_kernel.beam Binary files differindex 451d054667..a81f3e47d5 100644 --- a/bootstrap/lib/kernel/ebin/net_kernel.beam +++ b/bootstrap/lib/kernel/ebin/net_kernel.beam diff --git a/bootstrap/lib/kernel/ebin/user.beam b/bootstrap/lib/kernel/ebin/user.beam Binary files differindex 6433bcf859..f3aae4a980 100644 --- a/bootstrap/lib/kernel/ebin/user.beam +++ b/bootstrap/lib/kernel/ebin/user.beam diff --git a/bootstrap/lib/kernel/include/dist.hrl b/bootstrap/lib/kernel/include/dist.hrl index aea1ab81ba..5b52f6f294 100644 --- a/bootstrap/lib/kernel/include/dist.hrl +++ b/bootstrap/lib/kernel/include/dist.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/bootstrap/lib/kernel/include/dist_util.hrl b/bootstrap/lib/kernel/include/dist_util.hrl index f2b0598532..c3a7f97418 100644 --- a/bootstrap/lib/kernel/include/dist_util.hrl +++ b/bootstrap/lib/kernel/include/dist_util.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/bootstrap/lib/kernel/include/file.hrl b/bootstrap/lib/kernel/include/file.hrl index 3889bce393..bf97173122 100644 --- a/bootstrap/lib/kernel/include/file.hrl +++ b/bootstrap/lib/kernel/include/file.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,10 +25,11 @@ {size :: non_neg_integer(), % Size of file in bytes. type :: 'device' | 'directory' | 'other' | 'regular' | 'symlink', access :: 'read' | 'write' | 'read_write' | 'none', - atime :: file:date_time(), % The local time the file was last read: - % {{Year, Mon, Day}, {Hour, Min, Sec}}. - mtime :: file:date_time(), % The local time the file was last written. - ctime :: file:date_time(), % The interpretation of this time field + atime :: file:date_time() | integer(), % The local time the file was last read: + % {{Year, Mon, Day}, {Hour, Min, Sec}}. + % atime, ctime, mtime may also be unix epochs() + mtime :: file:date_time() | integer(), % The local time the file was last written. + ctime :: file:date_time() | integer(), % The interpretation of this time field % is dependent on operating system. % On Unix it is the last time the file % or the inode was changed. On Windows, diff --git a/bootstrap/lib/kernel/include/net_address.hrl b/bootstrap/lib/kernel/include/net_address.hrl index 5342076507..9b9ea42931 100644 --- a/bootstrap/lib/kernel/include/net_address.hrl +++ b/bootstrap/lib/kernel/include/net_address.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/bootstrap/lib/stdlib/ebin/base64.beam b/bootstrap/lib/stdlib/ebin/base64.beam Binary files differindex 04a1388637..07877625dd 100644 --- a/bootstrap/lib/stdlib/ebin/base64.beam +++ b/bootstrap/lib/stdlib/ebin/base64.beam diff --git a/bootstrap/lib/stdlib/ebin/beam_lib.beam b/bootstrap/lib/stdlib/ebin/beam_lib.beam Binary files differindex 01fc86def0..afe3bcc466 100644 --- a/bootstrap/lib/stdlib/ebin/beam_lib.beam +++ b/bootstrap/lib/stdlib/ebin/beam_lib.beam diff --git a/bootstrap/lib/stdlib/ebin/dets.beam b/bootstrap/lib/stdlib/ebin/dets.beam Binary files differindex 73be548a89..4a33312cc0 100644 --- a/bootstrap/lib/stdlib/ebin/dets.beam +++ b/bootstrap/lib/stdlib/ebin/dets.beam diff --git a/bootstrap/lib/stdlib/ebin/dets_server.beam b/bootstrap/lib/stdlib/ebin/dets_server.beam Binary files differindex d71185c9dd..26de164bd9 100644 --- a/bootstrap/lib/stdlib/ebin/dets_server.beam +++ b/bootstrap/lib/stdlib/ebin/dets_server.beam diff --git a/bootstrap/lib/stdlib/ebin/dets_utils.beam b/bootstrap/lib/stdlib/ebin/dets_utils.beam Binary files differindex a372faf6ac..e4cd1e8b2e 100644 --- a/bootstrap/lib/stdlib/ebin/dets_utils.beam +++ b/bootstrap/lib/stdlib/ebin/dets_utils.beam diff --git a/bootstrap/lib/stdlib/ebin/dets_v8.beam b/bootstrap/lib/stdlib/ebin/dets_v8.beam Binary files differindex a20f0469ce..c8e1549256 100644 --- a/bootstrap/lib/stdlib/ebin/dets_v8.beam +++ b/bootstrap/lib/stdlib/ebin/dets_v8.beam diff --git a/bootstrap/lib/stdlib/ebin/dets_v9.beam b/bootstrap/lib/stdlib/ebin/dets_v9.beam Binary files differindex a52d126adf..8cfcb9f8f1 100644 --- a/bootstrap/lib/stdlib/ebin/dets_v9.beam +++ b/bootstrap/lib/stdlib/ebin/dets_v9.beam diff --git a/bootstrap/lib/stdlib/ebin/epp.beam b/bootstrap/lib/stdlib/ebin/epp.beam Binary files differindex 0cc31bcac9..55f5adc24d 100644 --- a/bootstrap/lib/stdlib/ebin/epp.beam +++ b/bootstrap/lib/stdlib/ebin/epp.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_compile.beam b/bootstrap/lib/stdlib/ebin/erl_compile.beam Binary files differindex 1ce1d02ef0..6fd4e3373e 100644 --- a/bootstrap/lib/stdlib/ebin/erl_compile.beam +++ b/bootstrap/lib/stdlib/ebin/erl_compile.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_eval.beam b/bootstrap/lib/stdlib/ebin/erl_eval.beam Binary files differindex 3be5213113..6198c4f43a 100644 --- a/bootstrap/lib/stdlib/ebin/erl_eval.beam +++ b/bootstrap/lib/stdlib/ebin/erl_eval.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam Binary files differindex c5c1d71941..5c9663cd54 100644 --- a/bootstrap/lib/stdlib/ebin/erl_expand_records.beam +++ b/bootstrap/lib/stdlib/ebin/erl_expand_records.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_lint.beam b/bootstrap/lib/stdlib/ebin/erl_lint.beam Binary files differindex 55ec220d55..798924c19b 100644 --- a/bootstrap/lib/stdlib/ebin/erl_lint.beam +++ b/bootstrap/lib/stdlib/ebin/erl_lint.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_parse.beam b/bootstrap/lib/stdlib/ebin/erl_parse.beam Binary files differindex c026e8401f..85fa455908 100644 --- a/bootstrap/lib/stdlib/ebin/erl_parse.beam +++ b/bootstrap/lib/stdlib/ebin/erl_parse.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_scan.beam b/bootstrap/lib/stdlib/ebin/erl_scan.beam Binary files differindex b5e7c1c24e..9e70ed846e 100644 --- a/bootstrap/lib/stdlib/ebin/erl_scan.beam +++ b/bootstrap/lib/stdlib/ebin/erl_scan.beam diff --git a/bootstrap/lib/stdlib/ebin/erl_tar.beam b/bootstrap/lib/stdlib/ebin/erl_tar.beam Binary files differindex 9de0e978e3..7eacf3272c 100644 --- a/bootstrap/lib/stdlib/ebin/erl_tar.beam +++ b/bootstrap/lib/stdlib/ebin/erl_tar.beam diff --git a/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam b/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam Binary files differindex f5609d124c..496e41c858 100644 --- a/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam +++ b/bootstrap/lib/stdlib/ebin/error_logger_file_h.beam diff --git a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam Binary files differindex 886bba634c..3c4c135495 100644 --- a/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam +++ b/bootstrap/lib/stdlib/ebin/error_logger_tty_h.beam diff --git a/bootstrap/lib/stdlib/ebin/escript.beam b/bootstrap/lib/stdlib/ebin/escript.beam Binary files differindex 18066abf53..93c1109b41 100644 --- a/bootstrap/lib/stdlib/ebin/escript.beam +++ b/bootstrap/lib/stdlib/ebin/escript.beam diff --git a/bootstrap/lib/stdlib/ebin/ets.beam b/bootstrap/lib/stdlib/ebin/ets.beam Binary files differindex 8bc5103946..642689d749 100644 --- a/bootstrap/lib/stdlib/ebin/ets.beam +++ b/bootstrap/lib/stdlib/ebin/ets.beam diff --git a/bootstrap/lib/stdlib/ebin/eval_bits.beam b/bootstrap/lib/stdlib/ebin/eval_bits.beam Binary files differindex ac375672f6..73e20d9a8d 100644 --- a/bootstrap/lib/stdlib/ebin/eval_bits.beam +++ b/bootstrap/lib/stdlib/ebin/eval_bits.beam diff --git a/bootstrap/lib/stdlib/ebin/file_sorter.beam b/bootstrap/lib/stdlib/ebin/file_sorter.beam Binary files differindex 0c910821f6..633d8acd10 100644 --- a/bootstrap/lib/stdlib/ebin/file_sorter.beam +++ b/bootstrap/lib/stdlib/ebin/file_sorter.beam diff --git a/bootstrap/lib/stdlib/ebin/filename.beam b/bootstrap/lib/stdlib/ebin/filename.beam Binary files differindex 898ed0804f..e371f3f478 100644 --- a/bootstrap/lib/stdlib/ebin/filename.beam +++ b/bootstrap/lib/stdlib/ebin/filename.beam diff --git a/bootstrap/lib/stdlib/ebin/gb_trees.beam b/bootstrap/lib/stdlib/ebin/gb_trees.beam Binary files differindex bbe958dc66..edf1805440 100644 --- a/bootstrap/lib/stdlib/ebin/gb_trees.beam +++ b/bootstrap/lib/stdlib/ebin/gb_trees.beam diff --git a/bootstrap/lib/stdlib/ebin/gen.beam b/bootstrap/lib/stdlib/ebin/gen.beam Binary files differindex db59451d78..bd08292a87 100644 --- a/bootstrap/lib/stdlib/ebin/gen.beam +++ b/bootstrap/lib/stdlib/ebin/gen.beam diff --git a/bootstrap/lib/stdlib/ebin/gen_fsm.beam b/bootstrap/lib/stdlib/ebin/gen_fsm.beam Binary files differindex 03f40579cb..f763cab747 100644 --- a/bootstrap/lib/stdlib/ebin/gen_fsm.beam +++ b/bootstrap/lib/stdlib/ebin/gen_fsm.beam diff --git a/bootstrap/lib/stdlib/ebin/gen_server.beam b/bootstrap/lib/stdlib/ebin/gen_server.beam Binary files differindex 922c501ff2..fe4e109508 100644 --- a/bootstrap/lib/stdlib/ebin/gen_server.beam +++ b/bootstrap/lib/stdlib/ebin/gen_server.beam diff --git a/bootstrap/lib/stdlib/ebin/io_lib.beam b/bootstrap/lib/stdlib/ebin/io_lib.beam Binary files differindex 07cefba99e..b240aa157d 100644 --- a/bootstrap/lib/stdlib/ebin/io_lib.beam +++ b/bootstrap/lib/stdlib/ebin/io_lib.beam diff --git a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam Binary files differindex f7a239e18c..be283307f3 100644 --- a/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam +++ b/bootstrap/lib/stdlib/ebin/io_lib_pretty.beam diff --git a/bootstrap/lib/stdlib/ebin/lib.beam b/bootstrap/lib/stdlib/ebin/lib.beam Binary files differindex 5d44d3f8f1..4b67bbb774 100644 --- a/bootstrap/lib/stdlib/ebin/lib.beam +++ b/bootstrap/lib/stdlib/ebin/lib.beam diff --git a/bootstrap/lib/stdlib/ebin/ms_transform.beam b/bootstrap/lib/stdlib/ebin/ms_transform.beam Binary files differindex 1af64e9d63..bc16416161 100644 --- a/bootstrap/lib/stdlib/ebin/ms_transform.beam +++ b/bootstrap/lib/stdlib/ebin/ms_transform.beam diff --git a/bootstrap/lib/stdlib/ebin/otp_internal.beam b/bootstrap/lib/stdlib/ebin/otp_internal.beam Binary files differindex e69809b2b6..636a7a24d5 100644 --- a/bootstrap/lib/stdlib/ebin/otp_internal.beam +++ b/bootstrap/lib/stdlib/ebin/otp_internal.beam diff --git a/bootstrap/lib/stdlib/ebin/pool.beam b/bootstrap/lib/stdlib/ebin/pool.beam Binary files differindex a16364e1d9..3b1dbc3524 100644 --- a/bootstrap/lib/stdlib/ebin/pool.beam +++ b/bootstrap/lib/stdlib/ebin/pool.beam diff --git a/bootstrap/lib/stdlib/ebin/qlc.beam b/bootstrap/lib/stdlib/ebin/qlc.beam Binary files differindex 1576557a09..716f28b661 100644 --- a/bootstrap/lib/stdlib/ebin/qlc.beam +++ b/bootstrap/lib/stdlib/ebin/qlc.beam diff --git a/bootstrap/lib/stdlib/ebin/qlc_pt.beam b/bootstrap/lib/stdlib/ebin/qlc_pt.beam Binary files differindex 805203b00e..f51bc3ccbd 100644 --- a/bootstrap/lib/stdlib/ebin/qlc_pt.beam +++ b/bootstrap/lib/stdlib/ebin/qlc_pt.beam diff --git a/bootstrap/lib/stdlib/ebin/queue.beam b/bootstrap/lib/stdlib/ebin/queue.beam Binary files differindex 663b1a49ff..5ebb0f9cc6 100644 --- a/bootstrap/lib/stdlib/ebin/queue.beam +++ b/bootstrap/lib/stdlib/ebin/queue.beam diff --git a/bootstrap/lib/stdlib/ebin/re.beam b/bootstrap/lib/stdlib/ebin/re.beam Binary files differindex 85125291e9..4b9cbb7cfc 100644 --- a/bootstrap/lib/stdlib/ebin/re.beam +++ b/bootstrap/lib/stdlib/ebin/re.beam diff --git a/bootstrap/lib/stdlib/ebin/sofs.beam b/bootstrap/lib/stdlib/ebin/sofs.beam Binary files differindex 5d9b1bd6c0..a0c8c58c03 100644 --- a/bootstrap/lib/stdlib/ebin/sofs.beam +++ b/bootstrap/lib/stdlib/ebin/sofs.beam diff --git a/bootstrap/lib/stdlib/ebin/string.beam b/bootstrap/lib/stdlib/ebin/string.beam Binary files differindex 5086591504..3ace8184d0 100644 --- a/bootstrap/lib/stdlib/ebin/string.beam +++ b/bootstrap/lib/stdlib/ebin/string.beam diff --git a/bootstrap/lib/stdlib/ebin/supervisor.beam b/bootstrap/lib/stdlib/ebin/supervisor.beam Binary files differindex 9d3b9ddd87..98c8f6d42e 100644 --- a/bootstrap/lib/stdlib/ebin/supervisor.beam +++ b/bootstrap/lib/stdlib/ebin/supervisor.beam diff --git a/bootstrap/lib/stdlib/ebin/unicode.beam b/bootstrap/lib/stdlib/ebin/unicode.beam Binary files differindex b560f13933..7dcf140730 100644 --- a/bootstrap/lib/stdlib/ebin/unicode.beam +++ b/bootstrap/lib/stdlib/ebin/unicode.beam diff --git a/bootstrap/lib/stdlib/ebin/zip.beam b/bootstrap/lib/stdlib/ebin/zip.beam Binary files differindex ca76a6fa3b..2907ee286b 100644 --- a/bootstrap/lib/stdlib/ebin/zip.beam +++ b/bootstrap/lib/stdlib/ebin/zip.beam diff --git a/erts/Makefile.in b/erts/Makefile.in index 6e259c1772..1979c50781 100644 --- a/erts/Makefile.in +++ b/erts/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2006-2011. All Rights Reserved. +# Copyright Ericsson AB 2006-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ include vsn.mk # ---------------------------------------------------------------------- # Other erts dirs than the emulator dir... -ERTSDIRS = doc/src etc epmd lib_src +ERTSDIRS = etc epmd lib_src XINSTDIRS = preloaded ifeq ($(NO_START_SCRIPTS),) ERTSDIRS += start_scripts @@ -40,42 +40,36 @@ ifeq ($(BUILD_HYBRID_EMU),yes) EXTRA_FLAVORS += hybrid endif -# -# Some byggy 'make's get confused when a directory is created and used -# for storing files which other files depend on during the same "make -# session". As a workaround we do a 'make generate' (which creates -# all directories) before doing 'make opt', etc... -# - +.PHONY: all ifneq ($(BUILD_HYBRID_EMU),yes) all: smp opt else all: hybrid smp opt endif -debug opt docs clean: - @ case $@ in \ - docs|clean) ;; \ - *) ( cd emulator && $(MAKE) generate TYPE=$@ FLAVOR=$(FLAVOR)) ;; \ - esac - @ ( cd emulator && $(MAKE) $@ FLAVOR=$(FLAVOR)) - @for d in $(ERTSDIRS); do \ +.PHONY: docs +docs: + ( cd doc/src && $(MAKE) $@ ) + +.PHONY: debug opt clean +debug opt clean: + for d in emulator $(ERTSDIRS); do \ if test -d $$d; then \ - ( cd $$d && $(MAKE) $@ ) || exit $$? ; \ + ( cd $$d && $(MAKE) $@ FLAVOR=$(FLAVOR) ) || exit $$? ; \ fi ; \ - done + done # ---------------------------------------------------------------------- # These are "convenience targets", provided as shortcuts for developers # - don't use them in scripts or assume they will always stay like this! # +.PHONY: $(EXTRA_FLAVORS) $(EXTRA_FLAVORS): - @ ( cd emulator \ - && $(MAKE) generate TYPE=opt FLAVOR=$@ \ - && $(MAKE) opt FLAVOR=$@ ) + ( cd emulator && $(MAKE) opt FLAVOR=$@ ) ifneq ($(BUILD_HYBRID_EMU),yes) +.PHONY: hybrid hybrid: @echo '*** Omitted build of hybrid heap emulator' @echo '*** since target is $(TARGET)' @@ -88,6 +82,7 @@ endif # The copying of beam.dll should be removed when the beam dll need no longer be # in the same directory... +.PHONY: local_setup local_setup: @cd start_scripts && $(MAKE) @echo `ls $(ERL_TOP)/bin/` @@ -134,11 +129,13 @@ local_setup: $(ERL_TOP)/bin/start_clean.script # Run the configure script +.PHONY: configure configure: @set -e ; cd autoconf && $(MAKE) # Remake the makefiles, if you already have configured but you have edited # a "Makefile.in". +.PHONY: makefiles makefiles: @set -e ; cd autoconf && $(MAKE) $@ @@ -146,21 +143,17 @@ makefiles: # Release targets # -release release_docs: -ifeq ($(BUILD_HYBRID_EMU),yes) - @if test $@ = release; then ( cd emulator && $(MAKE) $@ FLAVOR=hybrid) fi -else - @if test $@ = release; then ( $(MAKE) hybrid ) fi -endif - @if test $@ = release; then ( cd emulator && $(MAKE) $@ FLAVOR=smp) fi - @ (cd emulator && $(MAKE) $@ FLAVOR=plain) - @for d in $(ERTSDIRS) $(XINSTDIRS); do \ +.PHONY: release +release: + for f in plain $(EXTRA_FLAVORS) ; do \ + ( cd emulator && $(MAKE) release FLAVOR=$$f ) \ + done + for d in $(ERTSDIRS) $(XINSTDIRS); do \ if test -d $$d; then \ ( cd $$d && $(MAKE) $@ ) || exit $$? ; \ fi ; \ done -# ---------------------------------------------------------------------- - -.PHONY: debug opt docs clean local_setup configure release \ - release_docs run_test_cases hybrid smp +.PHONY: release_docs +release_docs: + ( cd doc/src && $(MAKE) $@ ) diff --git a/erts/configure.in b/erts/configure.in index 50f8908f7a..b801994e14 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script. -*-m4-*- dnl %CopyrightBegin% dnl -dnl Copyright Ericsson AB 1997-2011. All Rights Reserved. +dnl Copyright Ericsson AB 1997-2012. All Rights Reserved. dnl dnl The contents of this file are subject to the Erlang Public License, dnl Version 1.1, (the "License"); you may not use this file except in @@ -4373,7 +4373,6 @@ dnl Note that the output files are relative to $srcdir AC_OUTPUT( emulator/$host/Makefile:emulator/Makefile.in - emulator/zlib/$host/Makefile:emulator/zlib/Makefile.in epmd/src/$host/Makefile:epmd/src/Makefile.in etc/common/$host/Makefile:etc/common/Makefile.in include/internal/$host/ethread.mk:include/internal/ethread.mk.in diff --git a/erts/doc/src/driver.xml b/erts/doc/src/driver.xml index 9f246c4a6c..ac5729880d 100644 --- a/erts/doc/src/driver.xml +++ b/erts/doc/src/driver.xml @@ -30,11 +30,11 @@ </header> <note><p>This document was written a long time ago. A lot of it is still - valid, but some things have changed since it was first written. - Updates of this document are planned for the future. The reader - is encouraged to also read the - <seealso marker="erl_driver">erl_driver</seealso>, and the - <seealso marker="erl_driver">driver_entry</seealso> documentation. + interesting since it explains important concepts, but it was + written for an older driver interface so the examples does not + work anymore. The reader is encouraged to read + <seealso marker="erl_driver">erl_driver</seealso> and the + <seealso marker="driver_entry">driver_entry</seealso> documentation. </p></note> <section> diff --git a/erts/doc/src/driver_entry.xml b/erts/doc/src/driver_entry.xml index 8bdd154cb9..a2efdf3ebc 100644 --- a/erts/doc/src/driver_entry.xml +++ b/erts/doc/src/driver_entry.xml @@ -34,18 +34,22 @@ <lib>driver_entry</lib> <libsummary>The driver-entry structure used by erlang drivers.</libsummary> <description> - <p>As of erts version 5.5.3 the driver interface has been extended - (see <seealso marker="driver_entry#extended_marker">extended marker</seealso>). - The extended interface introduces - <seealso marker="erl_driver#version_management">version management</seealso>, - the possibility to pass capability flags - (see <seealso marker="driver_entry#driver_flags">driver flags</seealso>) - to the runtime system at driver initialization, and some new - driver API functions. </p> + <p> + As of erts version 5.9 (OTP release R15B) the driver interface + has been changed with larger types for the callbacks + <seealso marker="#output">output</seealso>, + <seealso marker="#control">control</seealso> and + <seealso marker="#call">call</seealso>. + See driver <seealso marker="erl_driver#version_management"> + version management</seealso> in + <seealso marker="erl_driver">erl_driver</seealso>. + </p> <note> <p>Old drivers (compiled with an <c>erl_driver.h</c> from an - earlier erts version than 5.5.3) have to be recompiled - (but do not have to use the extended interface).</p> + earlier erts version than 5.9) have to be updated and have + to use the extended interface (with + <seealso marker="erl_driver#version_management">version management + </seealso>).</p> </note> <p>The <c>driver_entry</c> structure is a C struct that all erlang drivers define. It contains entry points for the erlang driver @@ -53,7 +57,7 @@ the driver.</p> <p> <marker id="emulator"></marker> - The <seealso marker="driver_entry">erl_driver</seealso> driver + The <seealso marker="erl_driver">erl_driver</seealso> driver API functions need a port handle that identifies the driver instance (and the port in the emulator). This is only passed to the <c>start</c> function, but @@ -84,7 +88,7 @@ the emulator, the driver is <em>not</em> allowed to modify the <c>driver_entry</c>.</p> <note> - <p>Do <em>not</em> declare the <c>driver_entry</c><c>const</c>. This since the emulator needs to + <p>Do <em>not</em> declare the <c>driver_entry</c> <c>const</c>. This since the emulator needs to modify the <c>handle</c>, and the <c>handle2</c> fields. A statically allocated, and <c>const</c> declared <c>driver_entry</c> may be located in @@ -116,7 +120,7 @@ typedef struct erl_drv_entry { void (*stop)(ErlDrvData drv_data); /* called when port is closed, and when the emulator is halted. */ - void (*output)(ErlDrvData drv_data, char *buf, int len); + void (*output)(ErlDrvData drv_data, char *buf, ErlDrvSizeT len); /* called when we have output from erlang to the port */ void (*ready_input)(ErlDrvData drv_data, ErlDrvEvent event); @@ -130,8 +134,9 @@ typedef struct erl_drv_entry { void (*finish)(void); /* called before unloading the driver - DYNAMIC DRIVERS ONLY */ void *handle; /* Reserved -- Used by emulator internally */ - int (*control)(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen); + ErlDrvSSizeT (*control)(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen); /* "ioctl" for drivers - invoked by port_control/3 */ void (*timeout)(ErlDrvData drv_data); /* Handling of timeout in driver */ @@ -144,8 +149,9 @@ typedef struct erl_drv_entry { closed, and there is data in the driver queue that needs to be flushed before 'stop' can be called */ - int (*call)(ErlDrvData drv_data, unsigned int command, char *buf, - int len, char **rbuf, int rlen, unsigned int *flags); + ErlDrvSSizeT (*call)(ErlDrvData drv_data, unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen, unsigned int *flags); /* Works mostly like 'control', a synchronous call into the driver. */ void (*event)(ErlDrvData drv_data, ErlDrvEvent event, @@ -192,7 +198,7 @@ typedef struct erl_drv_entry { <c>start</c>, then <c>stop</c> is the place to deallocate that memory.</p> </item> - <tag><marker id="output"/>void (*output)(ErlDrvData drv_data, char *buf, int len)</tag> + <tag><marker id="output"/>void (*output)(ErlDrvData drv_data, char *buf, ErlDrvSizeT len)</tag> <item> <p>This is called when an erlang process has sent data to the port. The data is pointed to by <c>buf</c>, and is @@ -243,7 +249,7 @@ typedef struct erl_drv_entry { emulator will modify this field; therefore, it is important that the <c>driver_entry</c> isn't declared <c>const</c>.</p> </item> - <tag><marker id="control"></marker>int (*control)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen)</tag> + <tag><marker id="control"></marker>ErlDrvSSizeT (*control)(ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen)</tag> <item> <p>This is a special routine invoked with the erlang function <c>port_control/3</c>. It works a little like an "ioctl" for @@ -316,7 +322,7 @@ typedef struct erl_drv_entry { opposed to the asynchronous function, which is called in some thread (if multithreading is enabled).</p> </item> - <tag><marker id="call"/>int (*call)(ErlDrvData drv_data, unsigned int command, char *buf, int len, char **rbuf, int rlen, unsigned int *flags)</tag> + <tag><marker id="call"/>ErlDrvSSizeT (*call)(ErlDrvData drv_data, unsigned int command, char *buf, ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen, unsigned int *flags)</tag> <item> <p>This function is called from <c>erlang:port_call/3</c>. It works a lot like the <c>control</c> call-back, but uses the @@ -452,7 +458,7 @@ typedef struct erl_drv_entry { <title>SEE ALSO</title> <p><seealso marker="erl_driver">erl_driver(3)</seealso>, <seealso marker="kernel:erl_ddll">erl_ddll(3)</seealso>, - <seealso marker="erts:erlang">erlang(3)</seealso>, + <seealso marker="erlang">erlang(3)</seealso>, kernel(3)</p> </section> </cref> diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml index 8e18dd6657..b5df4ca0c8 100644 --- a/erts/doc/src/erl_driver.xml +++ b/erts/doc/src/erl_driver.xml @@ -37,15 +37,18 @@ <p>As of erts version 5.5.3 the driver interface has been extended (see <seealso marker="driver_entry#extended_marker">extended marker</seealso>). The extended interface introduce - <seealso marker="erl_driver#version_management">version management</seealso>, + <seealso marker="#version_management">version management</seealso>, the possibility to pass capability flags (see <seealso marker="driver_entry#driver_flags">driver flags</seealso>) to the runtime system at driver initialization, and some new driver API functions. </p> <note> - <p>Old drivers (compiled with an <c>erl_driver.h</c> from an - earlier erts version than 5.5.3) have to be recompiled - (but does not have to use the extended interface).</p> + <p>As of erts version 5.9 old drivers has to be recompiled + and has to use the extended interface. They also has to be + adjusted to the + <seealso marker="#rewrites_for_64_bits">64-bit capable driver interface. + </seealso> + </p> </note> <p>The driver calls back to the emulator, using the API functions declared in <c>erl_driver.h</c>. They are used for @@ -242,9 +245,9 @@ </p> </item> <tag>Adding / removing drivers</tag> - <item>A driver can add and later remove drivers.</item> + <item><p>A driver can add and later remove drivers.</p></item> <tag>Monitoring processes</tag> - <item>A driver can monitor a process that does not own a port.</item> + <item><p>A driver can monitor a process that does not own a port.</p></item> <tag><marker id="version_management">Version management</marker></tag> <item> <p>Version management is enabled for drivers that have set the @@ -268,15 +271,203 @@ versions differ, or if the major versions are equal and the minor version used by the driver is greater than the one used by the runtime system.</p> - <p>The emulator tries to check that a driver that doesn't use the - extended driver interface isn't incompatible when loading it. - It can, however, not make sure that it isn't incompatible. Therefore, - when loading a driver that doesn't use the extended driver - interface, there is a risk that it will be loaded also when - the driver is incompatible. When the driver uses the extended driver - interface, the emulator can verify that it isn't of an incompatible - driver version. You are therefore advised to use the extended driver - interface.</p> + <p>The emulator will refuse to load a driver that does not use + the extended driver interface since, + to allow for 64-bit capable drivers, + incompatible type changes for the callbacks + <seealso marker="driver_entry#output">output</seealso>, + <seealso marker="driver_entry#control">control</seealso> and + <seealso marker="driver_entry#call">call</seealso> + were introduced in release R15B. A driver written + with the old types would compile with warnings and when + called return garbage sizes to the emulator causing it + to read random memory and create huge incorrect result blobs.</p> + <p>Therefore it is not enough to just recompile drivers written with + version management for pre-R15B types; the types has to be changed + in the driver suggesting other rewrites especially regarding + size variables. Investigate all warnings when recompiling!</p> + <p>Also, the API driver functions <c>driver_output*</c>, + <c>driver_vec_to_buf</c>, <c>driver_alloc/realloc*</c> + and the <c>driver_*</c> queue functions were changed to have + larger length arguments and return values. This is a + lesser problem since code that passes smaller types + will get them auto converted in the calls and as long as + the driver does not handle sizes that overflow an <c>int</c> + all will work as before.</p> + </item> + </taglist> + </section> + + <section> + <marker id="rewrites_for_64_bits"/> + <title> + REWRITES FOR 64-BIT DRIVER INTERFACE + </title> + <p> + For erts-5.9 two new integer types + <seealso marker="#ErlDrvSizeT">ErlDrvSizeT</seealso> and + <seealso marker="#ErlDrvSSizeT">ErlDrvSSizeT</seealso> + were introduced that can hold 64-bit sizes if necessary. + </p> + <p> + To not update a driver and just recompile it probably works + when building for a 32-bit machine creating a false sense of security. + Hopefully that will generate many important warnings. + But when recompiling the same driver later on for a 64-bit machine + there <em>will</em> be warnings and almost certainly crashes. + So it is a BAD idea to postpone updating the driver and + not fixing the warnings! + </p> + <p> + When recompiling with <c>gcc</c> use the <c>-Wstrict-prototypes</c> + flag to get better warnings. Try to find a similar flag if you + are using some other compiler. + </p> + <p> + Here follows a checklist for rewriting a pre erts-5.9 driver, + most important first. + </p> + <taglist> + <tag>Return types for driver callbacks</tag> + <item> + <p> + Rewrite driver callback + <c><seealso marker="driver_entry#control">control</seealso></c> + to use return type <c>ErlDrvSSizeT</c> instead of <c>int</c>. + </p> + <p> + Rewrite driver callback + <c><seealso marker="driver_entry#call">call</seealso></c> + to use return type <c>ErlDrvSSizeT</c> instead of <c>int</c>. + </p> + <note> + <p> + These changes are essential to not crash the emulator + or worse cause malfunction. + Without them a driver may return garbage in the high 32 bits + to the emulator causing it to build a huge result from random + bytes either crashing on memory allocation or succeeding with + a random result from the driver call. + </p> + </note> + </item> + <tag>Arguments to driver callbacks</tag> + <item> + <p> + Driver callback + <c><seealso marker="driver_entry#output">output</seealso></c> + now gets <c>ErlDrvSizeT</c> as 3:rd argument instead + of previously <c>int</c>. + </p> + <p> + Driver callback + <c><seealso marker="driver_entry#control">control</seealso></c> + now gets <c>ErlDrvSizeT</c> as 4:th and 6:th arguments instead + of previously <c>int</c>. + </p> + <p> + Driver callback + <c><seealso marker="driver_entry#call">call</seealso></c> + now gets <c>ErlDrvSizeT</c> as 4:th and 6:th arguments instead + of previously <c>int</c>. + </p> + <p> + Sane compiler's calling conventions probably make these changes + necessary only for a driver to handle data chunks that require + 64-bit size fields (mostly larger than 2 GB since that is what + an <c>int</c> of 32 bits can hold). But it is possible to think + of non-sane calling conventions that would make the driver + callbacks mix up the arguments causing malfunction. + </p> + <note> + <p> + The argument type change is from signed to unsigned which + may cause problems for e.g. loop termination conditions or + error conditions if you just change the types all over the place. + </p> + </note> + </item> + <tag>Larger <c>size</c> field in <c>ErlIOVec</c></tag> + <item> + <p> + The <c>size</c> field in + <seealso marker="#ErlIOVec"><c>ErlIOVec</c></seealso> + has been changed to <c>ErlDrvSizeT</c> from <c>int</c>. + Check all code that use that field. + </p> + <p> + Automatic type casting probably makes these changes necessary only + for a driver that encounters sizes larger than 32 bits. + </p> + <note> + <p> + The <c>size</c> field changed from signed to unsigned which + may cause problems for e.g. loop termination conditions or + error conditions if you just change the types all over the place. + </p> + </note> + </item> + <tag>Arguments and return values in the driver API</tag> + <item> + <p> + Many driver API functions has changed argument type + and/or return value to <c>ErlDrvSizeT</c> from mostly <c>int</c>. + Automatic type casting probably makes these changes necessary only + for a driver that encounters sizes larger than 32 bits. + </p> + <taglist> + <tag><seealso marker="#driver_output">driver_output</seealso></tag> + <item>3:rd argument</item> + <tag><seealso marker="#driver_output2">driver_output2</seealso></tag> + <item>3:rd and 5:th arguments</item> + <tag> + <seealso marker="#driver_output_binary">driver_output_binary</seealso> + </tag> + <item>3:rd 5:th and 6:th arguments</item> + <tag><seealso marker="#driver_outputv">driver_outputv</seealso></tag> + <item>3:rd and 5:th arguments</item> + <tag> + <seealso marker="#driver_vec_to_buf">driver_vec_to_buf</seealso> + </tag> + <item>3:rd argument and return value</item> + <tag><seealso marker="#driver_alloc">driver_alloc</seealso></tag> + <item>1:st argument</item> + <tag><seealso marker="#driver_realloc">driver_realloc</seealso></tag> + <item>2:nd argument</item> + <tag> + <seealso marker="#driver_alloc_binary">driver_alloc_binary</seealso> + </tag> + <item>1:st argument</item> + <tag> + <seealso marker="#driver_realloc_binary">driver_realloc_binary</seealso> + </tag> + <item>2:nd argument</item> + <tag><seealso marker="#driver_enq">driver_enq</seealso></tag> + <item>3:rd argument</item> + <tag><seealso marker="#driver_pushq">driver_pushq</seealso></tag> + <item>3:rd argument</item> + <tag><seealso marker="#driver_deq">driver_deq</seealso></tag> + <item>2:nd argument and return value</item> + <tag><seealso marker="#driver_sizeq">driver_sizeq</seealso></tag> + <item>return value</item> + <tag><seealso marker="#driver_enq_bin">driver_enq_bin</seealso></tag> + <item>3:rd and 4:th argument</item> + <tag><seealso marker="#driver_pushq_bin">driver_pushq_bin</seealso></tag> + <item>3:rd and 4:th argument</item> + <tag><seealso marker="#driver_enqv">driver_enqv</seealso></tag> + <item>3:rd argument</item> + <tag><seealso marker="#driver_pushqv">driver_pushqv</seealso></tag> + <item>3:rd argument</item> + <tag><seealso marker="#driver_peekqv">driver_peekqv</seealso></tag> + <item>return value</item> + </taglist> + <note> + <p> + This is a change from signed to unsigned which + may cause problems for e.g. loop termination conditions and + error conditions if you just change the types all over the place. + </p> + </note> </item> </taglist> </section> @@ -285,7 +476,11 @@ <title>DATA TYPES</title> <taglist> - <tag><marker id="ErlDrvSysInfo"/>ErlDrvSysInfo</tag> + <tag><marker id="ErlDrvSizeT"/>ErlDrvSizeT</tag> + <item><p>An unsigned integer type to be used as <c>size_t</c></p></item> + <tag><marker id="ErlDrvSSizeT"/>ErlDrvSSizeT</tag> + <item><p>A signed integer type the size of <c>ErlDrvSizeT</c></p></item> + <tag><marker id="ErlDrvSysInfo"/>ErlDrvSysInfo</tag> <item> <p/> <code type="none"> @@ -332,12 +527,12 @@ typedef struct ErlDrvSysInfo { <tag><c>erts_version</c></tag> <item>A string containing the version number of the runtime system (the same as returned by - <seealso marker="erts:erlang#system_info_version">erlang:system_info(version)</seealso>). + <seealso marker="erlang#system_info_version">erlang:system_info(version)</seealso>). </item> <tag><c>otp_release</c></tag> <item>A string containing the OTP release number (the same as returned by - <seealso marker="erts:erlang#system_info_otp_release">erlang:system_info(otp_release)</seealso>). + <seealso marker="erlang#system_info_otp_release">erlang:system_info(otp_release)</seealso>). </item> <tag><c>thread_support</c></tag> <item>A value <c>!= 0</c> if the runtime system has thread support; @@ -351,12 +546,12 @@ typedef struct ErlDrvSysInfo { <item>The number of async threads in the async thread pool used by <seealso marker="#driver_async">driver_async()</seealso> (the same as returned by - <seealso marker="erts:erlang#system_info_thread_pool_size">erlang:system_info(thread_pool_size)</seealso>). + <seealso marker="erlang#system_info_thread_pool_size">erlang:system_info(thread_pool_size)</seealso>). </item> <tag><c>scheduler_threads</c></tag> <item>The number of scheduler threads used by the runtime system (the same as returned by - <seealso marker="erts:erlang#system_info_schedulers">erlang:system_info(schedulers)</seealso>). + <seealso marker="erlang#system_info_schedulers">erlang:system_info(schedulers)</seealso>). </item> <tag><c>nif_major_version</c></tag> <item>The value of <c>ERL_NIF_MAJOR_VERSION</c> when the runtime system was compiled. @@ -371,7 +566,7 @@ typedef struct ErlDrvSysInfo { <p/> <code type="none"> typedef struct ErlDrvBinary { - int orig_size; + ErlDrvSint orig_size; char orig_bytes[]; } ErlDrvBinary; </code> @@ -423,7 +618,7 @@ typedef struct ErlDrvBinary { <item> <p>The <c>ErlDrvData</c> is a handle to driver-specific data, passed to the driver call-backs. It is a pointer, and is - most often casted to a specific pointer in the driver.</p> + most often type casted to a specific pointer in the driver.</p> </item> <tag>SysIOVec</tag> <item> @@ -437,7 +632,7 @@ typedef struct ErlDrvBinary { <code type="none"> typedef struct ErlIOVec { int vsize; - int size; + ErlDrvSizeT size; SysIOVec* iov; ErlDrvBinary** binv; } ErlIOVec; @@ -630,7 +825,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_output(ErlDrvPort port, char *buf, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_output(ErlDrvPort port, char *buf, ErlDrvSizeT len)</nametext></name> <fsummary>Send data from driver to port owner</fsummary> <desc> <marker id="driver_output"></marker> @@ -650,7 +845,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_output2(ErlDrvPort port, char *hbuf, int hlen, char *buf, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_output2(ErlDrvPort port, char *hbuf, ErlDrvSizeT hlen, char *buf, ErlDrvSizeT len)</nametext></name> <fsummary>Send data and binary data to port owner</fsummary> <desc> <marker id="driver_output2"></marker> @@ -665,7 +860,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_output_binary(ErlDrvPort port, char *hbuf, int hlen, ErlDrvBinary* bin, int offset, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_output_binary(ErlDrvPort port, char *hbuf, ErlDrvSizeT hlen, ErlDrvBinary* bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext></name> <fsummary>Send data from a driver binary to port owner</fsummary> <desc> <marker id="driver_output_binary"></marker> @@ -688,7 +883,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_outputv(ErlDrvPort port, char* hbuf, int hlen, ErlIOVec *ev, int skip)</nametext></name> + <name><ret>int</ret><nametext>driver_outputv(ErlDrvPort port, char* hbuf, ErlDrvSizeT hlen, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> <fsummary>Send vectorized data to port owner</fsummary> <desc> <marker id="driver_outputv"></marker> @@ -711,7 +906,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_vec_to_buf(ErlIOVec *ev, char *buf, int len)</nametext></name> + <name><ret>ErlDrvSizeT</ret><nametext>driver_vec_to_buf(ErlIOVec *ev, char *buf, ErlDrvSizeT len)</nametext></name> <fsummary>Collect data segments into a buffer</fsummary> <desc> <marker id="driver_vec_to_buf"></marker> @@ -738,7 +933,7 @@ typedef struct ErlIOVec { <c>time</c> parameter is the time in milliseconds before the timer expires.</p> <p>When the timer reaches 0 and expires, the driver entry - function <seealso marker="driver_entry#emulator">timeout</seealso> is called.</p> + function <seealso marker="driver_entry#timeout">timeout</seealso> is called.</p> <p>Note that there is only one timer on each driver instance; setting a new timer will replace an older one.</p> <p>Return value is 0 (-1 only when the <c>timeout</c> driver @@ -832,7 +1027,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>void *</ret><nametext>driver_alloc(size_t size)</nametext></name> + <name><ret>void *</ret><nametext>driver_alloc(ErlDrvSizeT size)</nametext></name> <fsummary>Allocate memory</fsummary> <desc> <marker id="driver_alloc"></marker> @@ -846,7 +1041,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>void *</ret><nametext>driver_realloc(void *ptr, size_t size)</nametext></name> + <name><ret>void *</ret><nametext>driver_realloc(void *ptr, ErlDrvSizeT size)</nametext></name> <fsummary>Resize an allocated memory block</fsummary> <desc> <marker id="driver_realloc"></marker> @@ -872,7 +1067,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>ErlDrvBinary*</ret><nametext>driver_alloc_binary(int size)</nametext></name> + <name><ret>ErlDrvBinary*</ret><nametext>driver_alloc_binary(ErlDrvSizeT size)</nametext></name> <fsummary>Allocate a driver binary</fsummary> <desc> <marker id="driver_alloc_binary"></marker> @@ -892,7 +1087,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>ErlDrvBinary*</ret><nametext>driver_realloc_binary(ErlDrvBinary *bin, int size)</nametext></name> + <name><ret>ErlDrvBinary*</ret><nametext>driver_realloc_binary(ErlDrvBinary *bin, ErlDrvSizeT size)</nametext></name> <fsummary>Resize a driver binary</fsummary> <desc> <marker id="driver_realloc_binary"></marker> @@ -958,7 +1153,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_enq(ErlDrvPort port, char* buf, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_enq(ErlDrvPort port, char* buf, ErlDrvSizeT len)</nametext></name> <fsummary>Enqueue data in the driver queue</fsummary> <desc> <marker id="driver_enq"></marker> @@ -982,7 +1177,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_pushq(ErlDrvPort port, char* buf, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_pushq(ErlDrvPort port, char* buf, ErlDrvSizeT len)</nametext></name> <fsummary>Push data at the head of the driver queue</fsummary> <desc> <marker id="driver_pushq"></marker> @@ -997,7 +1192,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_deq(ErlDrvPort port, int size)</nametext></name> + <name><ret>ErlDrvSizeT</ret><nametext>driver_deq(ErlDrvPort port, ErlDrvSizeT size)</nametext></name> <fsummary>Dequeue data from the head of the driver queue</fsummary> <desc> <marker id="driver_deq"></marker> @@ -1013,7 +1208,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_sizeq(ErlDrvPort port)</nametext></name> + <name><ret>ErlDrvSizeT</ret><nametext>driver_sizeq(ErlDrvPort port)</nametext></name> <fsummary>Return the size of the driver queue</fsummary> <desc> <marker id="driver_sizeq"></marker> @@ -1026,7 +1221,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_enq_bin(ErlDrvPort port, ErlDrvBinary *bin, int offset, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_enq_bin(ErlDrvPort port, ErlDrvBinary *bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext></name> <fsummary>Enqueue binary in the driver queue</fsummary> <desc> <marker id="driver_enq_bin"></marker> @@ -1043,7 +1238,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_pushq_bin(ErlDrvPort port, ErlDrvBinary *bin, int offset, int len)</nametext></name> + <name><ret>int</ret><nametext>driver_pushq_bin(ErlDrvPort port, ErlDrvBinary *bin, ErlDrvSizeT offset, ErlDrvSizeT len)</nametext></name> <fsummary>Push binary at the head of the driver queue</fsummary> <desc> <marker id="driver_pushq_bin"></marker> @@ -1060,13 +1255,35 @@ typedef struct ErlIOVec { </desc> </func> <func> + <name><ret>ErlDrvSizeT</ret><nametext>driver_peekqv(ErlDrvPort port, ErlIOVec *ev)</nametext></name> + <fsummary>Get the driver queue as an IO vector</fsummary> + <desc> + <marker id="driver_peekqv"></marker> + <p> + This function retrieves the driver queue into a supplied + <c>ErlIOVec</c> <c>ev</c>. It also returns the queue size. + This is one of two ways to get data out of the queue. + </p> + <p> + If <c>ev</c> is <c>NULL</c> all ones i.e. <c>-1</c> type cast to + <c>ErlDrvSizeT</c> is returned. + </p> + <p>Nothing is removed from the queue by this function, that must be done + with <c>driver_deq</c>.</p> + <p>This function can be called from an arbitrary thread if a + <seealso marker="#ErlDrvPDL">port data lock</seealso> + associated with the <c>port</c> is locked by the calling + thread during the call.</p> + </desc> + </func> + <func> <name><ret>SysIOVec*</ret><nametext>driver_peekq(ErlDrvPort port, int *vlen)</nametext></name> <fsummary>Get the driver queue as a vector</fsummary> <desc> <marker id="driver_peekq"></marker> <p>This function retrieves the driver queue as a pointer to an array of <c>SysIOVec</c>s. It also returns the number of - elements in <c>vlen</c>. This is the only way to get data + elements in <c>vlen</c>. This is one of two ways to get data out of the queue.</p> <p>Nothing is removed from the queue by this function, that must be done with <c>driver_deq</c>.</p> @@ -1079,7 +1296,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_enqv(ErlDrvPort port, ErlIOVec *ev, int skip)</nametext></name> + <name><ret>int</ret><nametext>driver_enqv(ErlDrvPort port, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> <fsummary>Enqueue vector in the driver queue</fsummary> <desc> <marker id="driver_enqv"></marker> @@ -1095,7 +1312,7 @@ typedef struct ErlIOVec { </desc> </func> <func> - <name><ret>int</ret><nametext>driver_pushqv(ErlDrvPort port, ErlIOVec *ev, int skip)</nametext></name> + <name><ret>int</ret><nametext>driver_pushqv(ErlDrvPort port, ErlIOVec *ev, ErlDrvSizeT skip)</nametext></name> <fsummary>Push vector at the head of the driver queue</fsummary> <desc> <marker id="driver_pushqv"></marker> @@ -1494,7 +1711,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len term encoded with the <seealso marker="erl_ext_dist">external format</seealso>, i.e., a term that has been encoded by - <seealso marker="erts:erlang#term_to_binary/2">erlang:term_to_binary</seealso>, + <seealso marker="erlang#term_to_binary/2">erlang:term_to_binary</seealso>, <seealso marker="erl_interface:ei">erl_interface</seealso>, etc. For example, if <c>binp</c> is a pointer to an <c>ErlDrvBinary</c> that contains the term <c>{17, 4711}</c> encoded with the @@ -1694,7 +1911,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len The driver defined handle is normally created in the <seealso marker="driver_entry#start">driver start call-back</seealso> when a port is created via - <seealso marker="erts:erlang#open_port/2">erlang:open_port/2</seealso>. </item> + <seealso marker="erlang#open_port/2">erlang:open_port/2</seealso>. </item> </taglist> <p>The caller of <c>driver_create_port()</c> is allowed to manipulate the newly created port when <c>driver_create_port()</c> @@ -2462,7 +2679,7 @@ ERL_DRV_EXT2TERM char *buf, ErlDrvUInt len <title>SEE ALSO</title> <p><seealso marker="driver_entry">driver_entry(3)</seealso>, <seealso marker="kernel:erl_ddll">erl_ddll(3)</seealso>, - <seealso marker="erts:erlang">erlang(3)</seealso></p> + <seealso marker="erlang">erlang(3)</seealso></p> <p>An Alternative Distribution Driver (ERTS User's Guide Ch. 3)</p> </section> diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index a603d5c2b8..fbe7b36163 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -215,9 +215,9 @@ representation of <c>Atom</c>. If <c>Encoding</c> is <c>latin1</c>, there will be one byte for each character in the text representation. If <c>Encoding</c> is <c>utf8</c> or - <c>unicode</c>, the characters will encoded using UTF-8 + <c>unicode</c>, the characters will be encoded using UTF-8 (meaning that characters from 16#80 up to 0xFF will be - encode in two bytes).</p> + encoded in two bytes).</p> <note><p>Currently, <c>atom_to_binary(Atom, latin1)</c> can never fail because the text representation of an atom can only contain @@ -268,7 +268,7 @@ <p>If <c>PosLen</c> in any way references outside the binary, a <c>badarg</c> exception is raised.</p> - <p><c>Start</c> is zero-based, i.e:</p> + <p><c>Start</c> is zero-based, i.e.:</p> <code> 1> Bin = <<1,2,3>> 2> binary_part(Bin,{0,2}). @@ -773,9 +773,9 @@ false</pre> turned off, nothing happens.</p> <p>Once <c>demonitor(MonitorRef)</c> has returned it is guaranteed that no <c>{'DOWN', MonitorRef, _, _, _}</c> message - due to the monitor will be placed in the callers message queue + due to the monitor will be placed in the caller's message queue in the future. A <c>{'DOWN', MonitorRef, _, _, _}</c> message - might have been placed in the callers message queue prior to + might have been placed in the caller's message queue prior to the call, though. Therefore, in most cases, it is advisable to remove such a <c>'DOWN'</c> message from the message queue after monitoring has been stopped. @@ -818,7 +818,7 @@ false</pre> <tag><c>flush</c></tag> <item> <p>Remove (one) <c>{_, MonitorRef, _, _, _}</c> message, - if there is one, from the callers message queue after + if there is one, from the caller's message queue after monitoring has been stopped.</p> <p>Calling <c>demonitor(MonitorRef, [flush])</c> is equivalent to the following, but more efficient:</p> @@ -847,7 +847,7 @@ false</pre> <item><p>The monitor was not found and could not be removed. This probably because someone already has placed a <c>'DOWN'</c> message corresponding to this monitor - in the callers message queue. + in the caller's message queue. </p> </item> </taglist> @@ -3909,7 +3909,7 @@ os_prompt%</pre> <item> <p>Return the current call stack back-trace (<em>stacktrace</em>) of the process. The stack has the same format as returned by - <seealso marker="#get_stacktrace/1">erlang:get_stacktrace/0</seealso>. + <seealso marker="#get_stacktrace/0">erlang:get_stacktrace/0</seealso>. </p> </item> <tag><c>{dictionary, Dictionary}</c></tag> @@ -4933,6 +4933,21 @@ true</pre> threads in the Erlang run-time system and may therefore be greater than the wall-clock time.</p> </item> + <tag><marker id="statistics_scheduler_wall_time"><c>scheduler_wall_time</c></marker></tag> + <item> + <p>Returns + <c>[{Scheduler_Id, Scheduler_Worked_Time, Scheduler_Total_Time}]</c>, time lapses are since the + the system flag <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso> + was set to true. + Returns <c>undefined</c> if the system flag <seealso marker="#system_flag_scheduler_wall_time"> + scheduler_wall_time</seealso> is set to false. + </p> + <p>The list of scheduler information is unsorted and may come in different order + between calls. The time unit is undefined and may be changed and should only be used + to calculate relative utilization. + </p> + </item> + <tag><c>wall_clock</c></tag> <item> <p>Returns @@ -5305,6 +5320,14 @@ true</pre> flags. </p> </item> + <tag><marker id="system_flag_scheduler_wall_time"><c>erlang:system_flag(scheduler_wall_time, Boolean)</c></marker></tag> + <item> + <p>Turns on/off scheduler wall time measurements. </p> + <p>For more information see, + <seealso marker="#statistics_scheduler_wall_time">erlang:statistics(scheduler_wall_time)</seealso>. + </p> + </item> + <tag><marker id="system_flag_schedulers_online"><c>erlang:system_flag(schedulers_online, SchedulersOnline)</c></marker></tag> <item> <p>Sets the amount of schedulers online. Valid range is @@ -5316,6 +5339,7 @@ true</pre> <seealso marker="#system_info_schedulers_online">erlang:system_info(schedulers_online)</seealso>. </p> </item> + <tag><c>erlang:system_flag(trace_control_word, TCW)</c></tag> <item> <p>Sets the value of the node's trace control word to @@ -7090,7 +7114,7 @@ true</pre> <c>Id</c> has no effect on the caller in the future (unless the link is setup again). If caller is trapping exits, an <c>{'EXIT', Id, _}</c> message due to the link might have - been placed in the callers message queue prior to the call, + been placed in the caller's message queue prior to the call, though. Note, the <c>{'EXIT', Id, _}</c> message can be the result of the link, but can also be the result of <c>Id</c> calling <c>exit/2</c>. Therefore, it <em>may</em> be diff --git a/erts/doc/src/match_spec.xml b/erts/doc/src/match_spec.xml index f0390c9db8..cd2b3abc1e 100644 --- a/erts/doc/src/match_spec.xml +++ b/erts/doc/src/match_spec.xml @@ -75,7 +75,7 @@ <item>MatchCondition ::= { GuardFunction } | { GuardFunction, ConditionExpression, ... } </item> - <item>BoolFunction ::= <c><![CDATA[is_atom]]></c> | <c><![CDATA[is_constant]]></c> | + <item>BoolFunction ::= <c><![CDATA[is_atom]]></c> | <c><![CDATA[is_float]]></c> | <c><![CDATA[is_integer]]></c> | <c><![CDATA[is_list]]></c> | <c><![CDATA[is_number]]></c> | <c><![CDATA[is_pid]]></c> | <c><![CDATA[is_port]]></c> | <c><![CDATA[is_reference]]></c> | <c><![CDATA[is_tuple]]></c> | <c><![CDATA[is_binary]]></c> | @@ -133,7 +133,7 @@ <item>MatchCondition ::= { GuardFunction } | { GuardFunction, ConditionExpression, ... } </item> - <item>BoolFunction ::= <c><![CDATA[is_atom]]></c> | <c><![CDATA[is_constant]]></c> | + <item>BoolFunction ::= <c><![CDATA[is_atom]]></c> | <c><![CDATA[is_float]]></c> | <c><![CDATA[is_integer]]></c> | <c><![CDATA[is_list]]></c> | <c><![CDATA[is_number]]></c> | <c><![CDATA[is_pid]]></c> | <c><![CDATA[is_port]]></c> | <c><![CDATA[is_reference]]></c> | <c><![CDATA[is_tuple]]></c> | <c><![CDATA[is_binary]]></c> | @@ -172,7 +172,7 @@ <title>Functions allowed in all types of match specifications</title> <p>The different functions allowed in <c><![CDATA[match_spec]]></c> work like this: </p> - <p><em>is_atom, is_constant, is_float, is_integer, is_list, is_number, is_pid, is_port, is_reference, is_tuple, is_binary, is_function: </em> Like the corresponding guard tests in + <p><em>is_atom, is_float, is_integer, is_list, is_number, is_pid, is_port, is_reference, is_tuple, is_binary, is_function: </em> Like the corresponding guard tests in Erlang, return <c><![CDATA[true]]></c> or <c><![CDATA[false]]></c>. </p> <p><em>is_record: </em>Takes an additional parameter, which SHALL diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index 4cef9669dd..d7967212b1 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -30,6 +30,507 @@ </header> <p>This document describes the changes made to the ERTS application.</p> +<section><title>Erts 5.9.0.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + A feature test for the <c>lwsync</c> instruction + performed on PowerPC hardware at runtime system startup + got into an eternal loop if the instruction was not + supported. This bug was introduced in erts-5.9/OTP-R15B.</p> + <p> + Own Id: OTP-9843</p> + </item> + <item> + <p> + I/O events could potentially be delayed for ever when + enabling kernel-poll on a non-SMP runtime system + executing on Solaris. When also combined with + async-threads the runtime system hung before completing + the boot phase. This bug was introduced in + erts-5.9/OTP-R15B.</p> + <p> + Own Id: OTP-9844</p> + </item> + </list> + </section> + +</section> + +<section><title>Erts 5.9</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Honor option <c>packet_size</c> for http packet parsing + by both TCP socket and <c>erlang:decode_packet</c>. This + gives the ability to accept HTTP headers larger than the + default setting, but also avoid DoS attacks by accepting + lines only up to whatever length you wish to allow. For + consistency, packet type <c>line</c> also honor option + <c>packet_size</c>. (Thanks to Steve Vinoski)</p> + <p> + Own Id: OTP-9389</p> + </item> + <item> + <p> A few contracts in the <c>lists</c> module have been + corrected. </p> + <p> + Own Id: OTP-9616</p> + </item> + <item> + <p> + The Unicode noncharacter code points 16#FFFE and 16#FFFE + were not allowed to be encoded or decoded using the + <c>unicode</c> module or bit syntax. That was + inconsistent with the other noncharacters 16#FDD0 to + 16#FDEF that could be encoded/decoded. To resolve the + inconsistency, 16#FFFE and 16#FFFE can now be encoded and + decoded. (Thanks to Alisdair Sullivan.)</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9624</p> + </item> + <item> + <p> + Make epp search directory of current file first when + including another file This completes a partial fix in + R11 that only worked for include_lib(). (Thanks to + Richard Carlsson)</p> + <p> + Own Id: OTP-9645</p> + </item> + <item> + <p> + Fixed memory leak in + <c>enif_inspect_io_list_as_binary</c> when applied on a + process independent environment.</p> + <p> + Own Id: OTP-9668</p> + </item> + <item> + <p>The number of beam catches allowed in code are no + longer statically defined and will grow according to its + need.</p> + <p> + Own Id: OTP-9692</p> + </item> + <item> + <p> + Add missing parenthesis in heart doc.</p> + <p> + Add missing spaces in the Reference Manual distributed + section.</p> + <p> + In the HTML version of the doc those spaces are necessary + to separate those words.</p> + <p> + Own Id: OTP-9693</p> + </item> + <item> + <p> + Fixes module erlang doc style: option description (Thanks + to Ricardo Catalinas Jim�nez)</p> + <p> + Own Id: OTP-9697</p> + </item> + <item> + <p> + Specifying a scope to binary:match/3 when using multiple + searchstrings resulted in faulty return values. This is + now corrected.</p> + <p> + Own Id: OTP-9701</p> + </item> + <item> + <p> + The runtime system crashed if more than one thread tried + to exit the runtime system at the same time.</p> + <p> + Own Id: OTP-9705</p> + </item> + <item> + <p> + Fix documentation for erlang:process_flag/2</p> + <p> + For the subsection about process_flag(save_calls, N) + there's an unrelated paragraph about process priorities + which was copied from the preceeding subsection regarding + process_flag(priority, Level). (Thanks to Filipe David + Manana)</p> + <p> + Own Id: OTP-9714</p> + </item> + <item> + <p> + Calls to <c>erlang:system_flag(schedulers_online, N)</c> + and/or <c>erlang:system_flag(multi_scheduling, + block|unblock)</c> could cause internal data used by this + functionality to get into an inconsistent state. When + this happened various problems occurred. This bug was + quite hard to trigger, so hopefully no-one has been + effected by it.</p> + <p> + A spinlock used by the run-queue management sometimes got + heavily contended. This code has now been rewritten, and + the spinlock has been removed.</p> + <p> + Own Id: OTP-9727</p> + </item> + <item> + <p> + Use libdlpi to get physical address (Thanks to Trond + Norbye)</p> + <p> + Own Id: OTP-9818</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> An option list argument can now be passed to + <c>file:read_file_info/2, file:read_link_info/2</c> and + <c>file:write_file_info/3</c> and set time type + information in the call. Valid options are <c>{time, + local}, {time, universal}</c> and <c>{time, posix}</c>. + In the case of <c>posix</c> time no conversions are made + which makes the operation a bit faster. </p> + <p> + Own Id: OTP-7687</p> + </item> + <item> + <p>A number of memory allocation optimizations have been + implemented. Most optimizations reduce contention caused + by synchronization between threads during allocation and + deallocation of memory. Most notably:</p> <list> <item> + Synchronization of memory management in scheduler + specific allocator instances has been rewritten to use + lock-free synchronization. </item> <item> Synchronization + of memory management in scheduler specific pre-allocators + has been rewritten to use lock-free synchronization. + </item> <item> The 'mseg_alloc' memory segment allocator + now use scheduler specific instances instead of one + instance. Apart from reducing contention this also + ensures that memory allocators always create memory + segments on the local NUMA node on a NUMA system. </item> + </list> + <p> + Own Id: OTP-7775</p> + </item> + <item> + <p> + The ethread atomic memory operations API used by the + runtime system has been extended and improved.</p> + <p> + The ethread library now also performs runtime tests for + presence of hardware features, such as for example SSE2 + instructions, instead of requiring this to be determined + at compile time.</p> + <p> + All uses of the old deprecated atomic API in the runtime + system have been replaced with the use of the new atomic + API. In a lot of places this change imply a relaxation of + memory barriers used.</p> + <p> + Own Id: OTP-9014</p> + </item> + <item> + <p>gen_sctp:open/0-2 may now return + {error,eprotonosupport} if SCTP is not supported</p> + <p>gen_sctp:peeloff/1 has been implemented and creates a + one-to-one socket which also are supported now</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9239</p> + </item> + <item> + <p> + Sendfile has been added to the file module's API. + sendfile/2 is used to read data from a file and send it + to a tcp socket using a zero copying mechanism if + available on that OS.</p> + <p> + Thanks to Tuncer Ayaz and Steve Vinovski for original + implementation</p> + <p> + Own Id: OTP-9240</p> + </item> + <item> + <p> + enif_get_reverse_list function added to nif API. This + function should be used to reverse small lists which are + deep within other structures making it impractical to do + the reverse in Erlang.</p> + <p> + Own Id: OTP-9392</p> + </item> + <item> + <p> + The deprecated concat_binary/1 BIF has been removed. Use + <c>list_to_binary</c> or <c>iolist_to_binary/1</c> + instead.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9421</p> + </item> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + <item> + <p>Line number and filename information are now included + in exception backtraces as a fourth element in the MFA + tuple. The information will be pretty-printed by the + shell and used by <c>common_test</c> to provide better + indication of where a test case.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9468</p> + </item> + <item> + <p>All binary constants used to be handled as heap + binaries (i.e. the entire binary would be copied when + sent to another process). Binary constants larger than 64 + bytes are now refc binaries (i.e. the actual data in the + binary will not be copied when sent to another + process).</p> + <p> + Own Id: OTP-9486</p> + </item> + <item> + <p> + If a float and an integer is compared, the integer is + only converted to a float if the float datatype can + contain it. Otherwise the float is converted to an + integer.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9497</p> + </item> + <item> + <p> + Add NIF function enif_is_number</p> + <p> + This function allows for easily determining if a term + represents or not a number (integer, float, small or + big).(Thanks to Filipe David Manana)</p> + <p> + Own Id: OTP-9629</p> + </item> + <item> + <p> + The ERTS internal system block functionality has been + replaced by new functionality for blocking the system. + The old system block functionality had contention issues + and complexity issues. The new functionality piggy-backs + on thread progress tracking functionality needed by newly + introduced lock-free synchronization in the runtime + system. When the functionality for blocking the system + isn't used, there is more or less no overhead at all. + This since the functionality for tracking thread progress + is there and needed anyway.</p> + <p> + Own Id: OTP-9631</p> + </item> + <item> + <p> + An ERTS internal, generic, many to one, lock-free queue + for communication between threads has been introduced. + The many to one scenario is very common in ERTS, so it + can be used in a lot of places in the future. Currently + it is used by scheduling of certain jobs, and the async + thread pool, but more uses are planned for the future.</p> + <p> + Drivers using the driver_async functionality are not + automatically locked to the system anymore, and can be + unloaded as any dynamically linked in driver.</p> + <p> + Scheduling of ready async jobs is now also interleaved in + between other jobs. Previously all ready async jobs were + performed at once.</p> + <p> + Own Id: OTP-9632</p> + </item> + <item> + <p> + Tuple funs (a two-element tuple with a module name and a + function) are now officially deprecated and will be + removed in R16. Use '<c>fun M:F/A</c>' instead. To make + you aware that your system uses tuple funs, the very + first time a tuple fun is applied, a warning will be sent + to the error logger.</p> + <p> + Own Id: OTP-9649</p> + </item> + <item> + <p> + Changed the internal BIF calling convention. Will make + simpler faster code and allow BIFs with an arbitrary + arity.</p> + <p> + Own Id: OTP-9662</p> + </item> + <item> + <p> + Windows native critical sections are now used internally + in the runtime system on Windows as mutex implementation. + This since they perform better under extreme contention + than our own implementation.</p> + <p> + Own Id: OTP-9671</p> + </item> + <item> + <p> + Convert some erl_nif macros into inline functions. Allow + for better compile time type checking. (Thanks to Tuncer + Ayaz)</p> + <p> + Own Id: OTP-9675</p> + </item> + <item> + <p> + The <c>+scl</c> command line flag has been added. It can + be used for disabling compaction of scheduler load. For + more information see the <c>erl(1)</c> documentation.</p> + <p> + Own Id: OTP-9695</p> + </item> + <item> + <p>The build system has been updated so that Erlang/OTP + can be built on Mac OS X Lion systems without a GCC + compiler. The INSTALL guide has been updated with + instructions on how to install a GCC compiler and build + Erlang/OTP with it, in order to get a run-time system + with better performance.</p> + <p> + Own Id: OTP-9712</p> + </item> + <item> + <p> + When loading a module, the system use to run on a single + scheduler during the entire loading process. This has + been changed to only take down the system just before + inserting the loaded code into the system tables, + resulting in a much shorter disruption if a module is + loaded in a busy system. (Suggested by Bob Ippolito.)</p> + <p> + Own Id: OTP-9720</p> + </item> + <item> + <p> + Possible to run HiPE without floating point exceptions + (FPE). Useful on platforms that lack reliable FPE. Slower + float operations compared to HiPE with FPE.</p> + <p> + Own Id: OTP-9724</p> + </item> + <item> + <p> + As of ERTS version 5.9 (OTP-R15B) the runtime system will + by default <em>not</em> bind schedulers to logical + processors.</p> + <p> + If the Erlang runtime system is the only operating system + process that binds threads to logical processors, this + improves the performance of the runtime system. However, + if other operating system processes (as for example + another Erlang runtime system) also bind threads to + logical processors, there might be a performance penalty + instead. In some cases this performance penalty might be + severe. Due to this, we change the default so that the + user must make an active decision in order to bind + schedulers.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9726</p> + </item> + <item> + <p> + The use of <c>erlang:system_flag(scheduler_bind_type, + _)</c> and <c>erlang:system_flag(cpu_topology, _)</c> + have been deprecated and scheduled for removal in + erts-5.10/OTP-R16. For more information see the + documentation of <c>erlang:system_flag/2</c>.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9749</p> + </item> + <item> + <p> + An ancient workaround for a Windows bug was removed from + the open_port code, open_port({spawn,...}...) is now + faster. Thanks to Daniel Goertzen.</p> + <p> + Own Id: OTP-9766</p> + </item> + <item> + <p> + The use of deprecated 32bit time_t on 32bit Windows is + removed.</p> + <p> + Own Id: OTP-9767</p> + </item> + <item> + <p> + The NIF <c>reload</c> mechanism is deprecated. Do not use + it as an upgrade method for live production systems. It + might be removed in future releases. It can still serve + as a development feature but a warning message will be + logged each time it is used.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9771</p> + </item> + <item> + <p>The driver interface has been changed to enable 64-bit + aware drivers. Most importantly the return types for + ErlDrvEntry callbacks 'call' and 'control' has ben + enlarged which require drivers to be changed or they will + cause emulator crashes. See <seealso + marker="erl_driver#rewrites_for_64_bits"> Rewrites for + 64-bit driver interface </seealso> in the driver manual. + </p> + <p>Due to this driver <seealso + marker="erl_driver#version_management">version + management</seealso> is now mandatory. A driver that is + not written with version management or a driver that was + compiled with the wrong major version will be not be + loaded by the emulator.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9795</p> + </item> + <item> + <p> + Eliminate use of deprecated regexp module</p> + <p> + Own Id: OTP-9810</p> + </item> + </list> + </section> + +</section> + <section><title>Erts 5.8.5</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index a5d8217545..2bd7297231 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2011. All Rights Reserved. +# Copyright Ericsson AB 1996-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -28,21 +28,26 @@ Z_LIB=@Z_LIB@ NO_INLINE_FUNCTIONS=false OPCODE_TABLES = $(ERL_TOP)/lib/compiler/src/genop.tab beam/ops.tab +DEBUG_CFLAGS = @DEBUG_CFLAGS@ +CONFIGURE_CFLAGS = @CFLAGS@ + # # Run this make file with TYPE set to the type of emulator you want. # Different versions of the emulator for different uses. The default # is "debug". For a normal version use "opt". # +DEFS=@DEFS@ THR_DEFS=@EMU_THR_DEFS@ M4FLAGS= CREATE_DIRS= LDFLAGS=@LDFLAGS@ +ARFLAGS=rc ifeq ($(TYPE),debug) PURIFY = TYPEMARKER = .debug -TYPE_FLAGS = @DEBUG_CFLAGS@ -DDEBUG +TYPE_FLAGS = $(DEBUG_CFLAGS) -DDEBUG ENABLE_ALLOC_TYPE_VARS += debug ifeq ($(TARGET),win32) TYPE_FLAGS += -DNO_JUMP_TABLE @@ -53,7 +58,7 @@ else ifeq ($(TYPE),purify) PURIFY = purify $(PURIFY_BUILD_OPTIONS) TYPEMARKER = .purify -TYPE_FLAGS = @DEBUG_CFLAGS@ -DPURIFY -DNO_JUMP_TABLE -DERTS_MSEG_FAKE_SEGMENTS +TYPE_FLAGS = $(DEBUG_CFLAGS) -DPURIFY -DNO_JUMP_TABLE -DERTS_MSEG_FAKE_SEGMENTS ENABLE_ALLOC_TYPE_VARS += purify else @@ -67,14 +72,14 @@ else ifeq ($(TYPE),purecov) PURIFY = purecov --follow-child-processes=yes $(PURECOV_BUILD_OPTIONS) TYPEMARKER = .purecov -TYPE_FLAGS = @DEBUG_CFLAGS@ -DPURECOV -DNO_JUMP_TABLE +TYPE_FLAGS = $(DEBUG_CFLAGS) -DPURECOV -DNO_JUMP_TABLE ENABLE_ALLOC_TYPE_VARS += purecov else ifeq ($(TYPE),gcov) PURIFY = TYPEMARKER = .gcov -TYPE_FLAGS = @DEBUG_CFLAGS@ -DERTS_GCOV -DNO_JUMP_TABLE -fprofile-arcs -ftest-coverage -O0 -DERTS_CAN_INLINE=0 -DERTS_INLINE= +TYPE_FLAGS = $(DEBUG_CFLAGS) -DERTS_GCOV -DNO_JUMP_TABLE -fprofile-arcs -ftest-coverage -O0 -DERTS_CAN_INLINE=0 -DERTS_INLINE= ifneq ($(findstring solaris,$(TARGET)),solaris) LIBS += -lgcov endif @@ -84,7 +89,7 @@ else ifeq ($(TYPE),valgrind) PURIFY = TYPEMARKER = .valgrind -TYPE_FLAGS = @DEBUG_CFLAGS@ -DVALGRIND -DNO_JUMP_TABLE -DERTS_MSEG_FAKE_SEGMENTS +TYPE_FLAGS = $(DEBUG_CFLAGS) -DVALGRIND -DNO_JUMP_TABLE -DERTS_MSEG_FAKE_SEGMENTS ENABLE_ALLOC_TYPE_VARS += valgrind else @@ -147,6 +152,15 @@ endif TF_MARKER=$(TYPEMARKER)$(FLAVOR_MARKER) +ifeq ($(FLAVOR)-@ERTS_BUILD_SMP_EMU@,smp-no) +VOID_EMULATOR = '*** SMP emulator disabled by configure' +else +ifeq ($(TYPE)-@HAVE_VALGRIND@,valgrind-no) +VOID_EMULATOR = '*** valgrind emulator disabled by configure' +else +VOID_EMULATOR = +endif +endif OPSYS=@OPSYS@ sol2CFLAGS= @@ -187,7 +201,7 @@ else EMU_CC = @EMU_CC@ endif WFLAGS = @WFLAGS@ -CFLAGS = @STATIC_CFLAGS@ $(TYPE_FLAGS) $(FLAVOR_FLAGS) @DEFS@ $(WFLAGS) $(THR_DEFS) $(ARCHCFLAGS) +CFLAGS = @STATIC_CFLAGS@ $(TYPE_FLAGS) $(FLAVOR_FLAGS) $(DEFS) $(WFLAGS) $(THR_DEFS) $(ARCHCFLAGS) HCC = @HCC@ LD = @LD@ DEXPORT = @DEXPORT@ @@ -263,30 +277,29 @@ CS_PURIFY = CS_TYPE_FLAGS = $(subst QUANTIFY,FAKE_QUANTIFY, \ $(subst PURIFY,FAKE_PURIFY, $(TYPE_FLAGS))) endif -CS_CFLAGS_ = $(CS_TYPE_FLAGS) @DEFS@ $(WFLAGS) +CS_CFLAGS_ = $(CS_TYPE_FLAGS) $(DEFS) $(WFLAGS) ifeq ($(GCC),yes) CS_CFLAGS = $(subst -O2, $(GEN_OPT_FLGS) $(UNROLL_FLG), $(CS_CFLAGS_)) else CS_CFLAGS = $(CS_CFLAGS_) endif CS_LDFLAGS = $(LDFLAGS) -CS_LIBS = -L../lib/internal/$(TARGET) -lerts_internal @ERTS_INTERNAL_X_LIBS@ +CS_LIBS = -L../lib/internal/$(TARGET) -lerts_internal$(TYPEMARKER) @ERTS_INTERNAL_X_LIBS@ LIBS += @TERMCAP_LIB@ -L../lib/internal/$(TARGET) @ERTS_INTERNAL_X_LIBS@ ifdef Z_LIB # Use shared zlib library LIBS += $(Z_LIB) +DEPLIBS = else +DEPLIBS=$(ZLIB_LIBRARY) ifeq ($(TARGET),win32) -LIBS += -L$(ERL_TOP)/erts/emulator/zlib/obj/$(TARGET)/$(TYPE) -lz -DEPLIBS = $(ERL_TOP)/erts/emulator/zlib/obj/$(TARGET)/$(TYPE)/z.lib +LIBS += -L$(ZLIB_OBJDIR) -lz else # Build on darwin fails if -lz is used -LIBS += $(ERL_TOP)/erts/emulator/zlib/obj/$(TARGET)/$(TYPE)/libz.a -DEPLIBS = $(ERL_TOP)/erts/emulator/zlib/obj/$(TARGET)/$(TYPE)/libz.a +LIBS += $(ZLIB_LIBRARY) endif - endif ifeq ($(TARGET),win32) @@ -313,12 +326,9 @@ LIBSCTP = @LIBSCTP@ ORG_THR_LIBS=@EMU_THR_LIBS@ THR_LIB_NAME=@EMU_THR_LIB_NAME@ -ifneq ($(strip $(THR_LIB_NAME)),) -DEPLIBS += $(ERL_TOP)/erts/lib/internal/$(TARGET)/$(LIB_PREFIX)erts_internal_r$(TYPEMARKER)$(LIB_SUFFIX) \ - $(ERL_TOP)/erts/lib/internal/$(TARGET)/$(LIB_PREFIX)ethread$(TYPEMARKER)$(LIB_SUFFIX) -else -DEPLIBS += $(ERL_TOP)/erts/lib/internal/$(TARGET)/$(LIB_PREFIX)erts_internal$(TYPEMARKER)$(LIB_SUFFIX) -endif +ERTS_LIB_DIR = $(ERL_TOP)/erts/lib_src +ERTS_LIB = $(ERTS_LIB_DIR)/obj/$(TARGET)/$(TYPE)/MADE +DEPLIBS += $(ERTS_LIB) THR_LIBS=$(subst -l$(THR_LIB_NAME),-l$(THR_LIB_NAME)$(TYPEMARKER), \ $(subst -lerts_internal_r,-lerts_internal_r$(TYPEMARKER),$(ORG_THR_LIBS))) @@ -354,8 +364,7 @@ OBJDIR = obj/$(TTF_DIR) CREATE_DIRS += $(OBJDIR) \ pcre/obj/$(TARGET)/$(TYPE) \ - zlib/obj/$(TARGET)/$(TYPE) - + $(ZLIB_OBJDIR) BINDIR = $(ERL_TOP)/bin/$(TARGET) @@ -378,15 +387,12 @@ else UNIX_ONLY_BUILDS = endif -ifeq ($(TYPE)-@HAVE_VALGRIND@,valgrind-no) -all: - @echo '*** valgrind not found by configure' -else -ifeq ($(FLAVOR)-@ERTS_BUILD_SMP_EMU@,smp-no) +.PHONY: all +ifdef VOID_EMULATOR all: - @echo '*** Omitted build of emulator with smp support' + @echo $(VOID_EMULATOR)' - omitted target all' else -all: generate erts_lib zlib $(BINDIR)/$(EMULATOR_EXECUTABLE) $(UNIX_ONLY_BUILDS) +all: $(BINDIR)/$(EMULATOR_EXECUTABLE) $(UNIX_ONLY_BUILDS) ifeq ($(OMIT_OMIT_FP),yes) @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' @@ -397,37 +403,25 @@ ifeq ($(OMIT_OMIT_FP),yes) @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' endif endif -endif - -ifdef Z_LIB -zlib: - @echo 'Skip zlib directory, use shared library' -else -zlib: - @set -e ; cd zlib && $(MAKE) TYPE=$(TYPE) $(TYPE) -endif - +include zlib/zlib.mk include pcre/pcre.mk -erts_lib: - cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE) +$(ERTS_LIB): + cd $(ERTS_LIB_DIR) && $(MAKE) $(TYPE) +.PHONY: clean clean: -ifeq ($(TARGET),win32) - $(RM) -f $(TARGET)/beams.rc -endif - $(RM) -f $(TARGET)/*.c $(TARGET)/*.h $(TARGET)/depend.mk - $(RM) -f $(TARGET)/*/*/*.c $(TARGET)/*/*/*.h $(TARGET)/*/*/*.S - $(RM) -f $(ERL_TOP)/erts/emulator/obj/$(TARGET)/*/*/*.o - $(RM) -f $(BINDIR)/beam $(BINDIR)/beam.* - $(RM) -rf $(BINDIR)/child_setup $(BINDIR)/child_setup.* - $(RM) -f $(BINDIR)/hipe_mkliterals $(BINDIR)/hipe_mkliterals.* - @set -e ; cd zlib && $(MAKE) clean - rm -f $(OBJS) $(OBJDIR)/libepcre.a - -.PHONY: all zlib clean - + $(RM) -f $(GENERATE) + $(RM) -rf $(TARGET)/*.c $(TARGET)/*.h $(TARGET)/*-GENERATED + $(RM) -rf $(TARGET)/*/* + $(RM) -rf obj/$(TARGET) + $(RM) -rf pcre/obj/$(TARGET) $(PCRE_GENINC) + $(RM) -rf zlib/obj/$(TARGET) + $(RM) -rf bin/$(TARGET) + cd $(ERTS_LIB_DIR) && $(MAKE) clean + +.PHONY: docs docs: # ---------------------------------------------------------------------- @@ -440,13 +434,11 @@ ifeq ($(TARGET),win32) RELEASE_INCLUDES += sys/$(ERLANG_OSTYPE)/erl_win_dyn_driver.h endif -ifeq ($(TYPE)-@HAVE_VALGRIND@,valgrind-no) -release_spec: - @echo '*** valgrind not found by configure' -else -ifeq ($(FLAVOR)-@ERTS_BUILD_SMP_EMU@,smp-no) + +.PHONY: release_spec +ifdef VOID_EMULATOR release_spec: - @echo '*** No emulator with smp support to install' + @echo $(VOID_EMULATOR)' - omitted target release_spec (install)' else release_spec: all $(INSTALL_DIR) $(RELSYSDIR) @@ -463,8 +455,8 @@ ifeq ($(ERLANG_OSTYPE), unix) $(INSTALL_PROGRAM) $(BINDIR)/$(CS_EXECUTABLE) $(RELSYSDIR)/bin endif endif -endif +.PHONY: release_docs_spec release_docs_spec: # ---------------------------------------------------------------------- @@ -473,48 +465,41 @@ release_docs_spec: _create_dirs := $(shell mkdir -p $(CREATE_DIRS)) -.PHONY : generate - -GENERATE= $(TTF_DIR)/beam_opcodes.h \ - $(TARGET)/erl_bif_table.c \ - $(TARGET)/erl_version.h \ - $(TTF_DIR)/driver_tab.c \ - $(TTF_DIR)/erl_alloc_types.h - -ifeq ($(TARGET),win32) -GENERATE += $(TARGET)/beams.rc -else -GENERATE += $(TARGET)/preload.c -endif +GENERATE = +HIPE_ASM = ifeq ($(findstring vxworks,$(TARGET)),vxworks) else ifdef HIPE_ENABLED -GENERATE += $(TTF_DIR)/hipe_x86_asm.h \ +HIPE_ASM += $(TTF_DIR)/hipe_x86_asm.h \ $(TTF_DIR)/hipe_amd64_asm.h \ $(TTF_DIR)/hipe_sparc_asm.h \ $(TTF_DIR)/hipe_ppc_asm.h \ - $(TTF_DIR)/hipe_arm_asm.h \ + $(TTF_DIR)/hipe_arm_asm.h + +GENERATE += $(HIPE_ASM) \ $(TTF_DIR)/hipe_literals.h \ $(BINDIR)/hipe_mkliterals$(TF_MARKER) endif endif -ifeq ($(FLAVOR)-@ERTS_BUILD_SMP_EMU@,smp-no) -GENERATE= -endif - -generate: $(GENERATE) - ifdef HIPE_ENABLED OPCODE_TABLES += hipe/hipe_ops.tab endif -$(TTF_DIR)/beam_opcodes.h $(TTF_DIR)/beam_opcodes.c: $(OPCODE_TABLES) utils/beam_makeops +$(TTF_DIR)/beam_cold.h \ +$(TTF_DIR)/beam_hot.h \ +$(TTF_DIR)/beam_opcodes.c \ +$(TTF_DIR)/beam_opcodes.h \ +$(TTF_DIR)/beam_pred_funcs.h \ +$(TTF_DIR)/beam_tr_funcs.h \ + : $(TTF_DIR)/OPCODES-GENERATED +$(TTF_DIR)/OPCODES-GENERATED: $(OPCODE_TABLES) utils/beam_makeops LANG=C $(PERL) utils/beam_makeops \ -wordsize @EXTERNAL_WORD_SIZE@ \ -outdir $(TTF_DIR) \ - -emulator $(OPCODE_TABLES) + -emulator $(OPCODE_TABLES) && echo $? >$(TTF_DIR)/OPCODES-GENERATED +GENERATE += $(TTF_DIR)/OPCODES-GENERATED # bif and atom table ATOMS= beam/atom.names @@ -534,25 +519,32 @@ BIFS += hipe/hipe_perfctr.tab endif endif -TABLES= $(TARGET)/erl_bif_table.c $(TARGET)/erl_bif_table.h \ - $(TARGET)/erl_bif_wrap.c $(TARGET)/erl_bif_list.h \ - $(TARGET)/erl_atom_table.c $(TARGET)/erl_atom_table.h \ - $(TARGET)/erl_pbifs.c - -$(TABLES): $(ATOMS) $(BIFS) utils/make_tables +$(TARGET)/erl_bif_table.c \ +$(TARGET)/erl_bif_table.h \ +$(TARGET)/erl_bif_wrap.c \ +$(TARGET)/erl_bif_list.h \ +$(TARGET)/erl_atom_table.c \ +$(TARGET)/erl_atom_table.h \ +$(TARGET)/erl_pbifs.c \ + : $(TARGET)/TABLES-GENERATED +$(TARGET)/TABLES-GENERATED: $(ATOMS) $(BIFS) utils/make_tables LANG=C $(PERL) utils/make_tables -src $(TARGET) -include $(TARGET)\ - $(ATOMS) $(BIFS) + $(ATOMS) $(BIFS) && echo $? >$(TARGET)/TABLES-GENERATED +GENERATE += $(TARGET)/TABLES-GENERATED $(TTF_DIR)/erl_alloc_types.h: beam/erl_alloc.types utils/make_alloc_types LANG=C $(PERL) utils/make_alloc_types -src $< -dst $@ $(ENABLE_ALLOC_TYPE_VARS) +GENERATE += $(TTF_DIR)/erl_alloc_types.h # version include file $(TARGET)/erl_version.h: ../vsn.mk LANG=C $(PERL) utils/make_version -o $@ $(SYSTEM_VSN) $(VSN)$(SERIALNO) $(TARGET) +GENERATE += $(TARGET)/erl_version.h # driver table $(TTF_DIR)/driver_tab.c: Makefile.in LANG=C $(PERL) utils/make_driver_tab -o $@ $(DRV_OBJS) +GENERATE += $(TTF_DIR)/driver_tab.c # Preloaded code. # @@ -568,6 +560,7 @@ $(TARGET)/beams.rc: $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \ $(ERL_TOP)/erts/preloaded/ebin/erl_prim_loader.beam \ $(ERL_TOP)/erts/preloaded/ebin/erlang.beam LANG=C $(PERL) utils/make_preload $(MAKE_PRELOAD_EXTRA) -rc $^ > $@ +GENERATE += $(TARGET)/beams.rc else $(TARGET)/preload.c: $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \ $(ERL_TOP)/erts/preloaded/ebin/init.beam \ @@ -578,6 +571,17 @@ $(TARGET)/preload.c: $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \ $(ERL_TOP)/erts/preloaded/ebin/erl_prim_loader.beam \ $(ERL_TOP)/erts/preloaded/ebin/erlang.beam LANG=C $(PERL) utils/make_preload -old $^ > $@ +GENERATE += $(TARGET)/preload.c +endif + +.PHONY : generate +ifdef VOID_EMULATOR +generate: + @echo $(VOID_EMULATOR)' - omitted target generate' +else +generate: $(TTF_DIR)/GENERATED +$(TTF_DIR)/GENERATED: $(GENERATE) + echo $? >$(TTF_DIR)/GENERATED endif # ---------------------------------------------------------------------- @@ -656,7 +660,7 @@ endif # CS_SRC = sys/$(ERLANG_OSTYPE)/erl_child_setup.c -$(BINDIR)/$(CS_EXECUTABLE): $(CS_SRC) +$(BINDIR)/$(CS_EXECUTABLE): $(TTF_DIR)/GENERATED $(CS_SRC) $(ERTS_LIB) $(CS_PURIFY) $(CC) $(CS_LDFLAGS) -o $(BINDIR)/$(CS_EXECUTABLE) \ $(CS_CFLAGS) $(COMMON_INCLUDES) $(CS_SRC) $(CS_LIBS) @@ -834,6 +838,9 @@ BASE_OBJS = $(RUN_OBJS) $(EMU_OBJS) $(OS_OBJS) $(EXTRA_BASE_OBJS) OBJS = $(BASE_OBJS) $(DRV_OBJS) +$(INIT_OBJS): $(TTF_DIR)/GENERATED +$(OBJS): $(TTF_DIR)/GENERATED + ######################################## # HiPE section @@ -857,30 +864,49 @@ $(OBJDIR)/%.o: hipe/%.c $(BINDIR)/hipe_mkliterals$(TF_MARKER): $(OBJDIR)/hipe_mkliterals.o $(CC) $(CFLAGS) $(INCLUDES) -o $@ $< -$(OBJDIR)/hipe_mkliterals.o: $(TTF_DIR)/hipe_x86_asm.h $(TTF_DIR)/hipe_ppc_asm.h $(TTF_DIR)/beam_opcodes.h +$(OBJDIR)/hipe_mkliterals.o: $(HIPE_ASM) $(TTF_DIR)/erl_alloc_types.h \ + $(TTF_DIR)/OPCODES-GENERATED $(TARGET)/TABLES-GENERATED $(TTF_DIR)/hipe_literals.h: $(BINDIR)/hipe_mkliterals$(TF_MARKER) $(BINDIR)/hipe_mkliterals$(TF_MARKER) -c > $@ -$(OBJDIR)/hipe_x86_glue.o: hipe/hipe_x86_glue.S $(TTF_DIR)/hipe_x86_asm.h $(TTF_DIR)/hipe_literals.h hipe/hipe_mode_switch.h -$(TTF_DIR)/hipe_x86_bifs.S: hipe/hipe_x86_bifs.m4 hipe/hipe_x86_asm.m4 hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h -$(OBJDIR)/hipe_x86_bifs.o: $(TTF_DIR)/hipe_x86_bifs.S $(TTF_DIR)/hipe_literals.h - -$(OBJDIR)/hipe_amd64_glue.o: hipe/hipe_amd64_glue.S $(TTF_DIR)/hipe_amd64_asm.h $(TTF_DIR)/hipe_literals.h hipe/hipe_mode_switch.h -$(TTF_DIR)/hipe_amd64_bifs.S: hipe/hipe_amd64_bifs.m4 hipe/hipe_amd64_asm.m4 hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h -$(OBJDIR)/hipe_amd64_bifs.o: $(TTF_DIR)/hipe_amd64_bifs.S $(TTF_DIR)/hipe_literals.h - -$(OBJDIR)/hipe_sparc_glue.o: hipe/hipe_sparc_glue.S $(TTF_DIR)/hipe_sparc_asm.h hipe/hipe_mode_switch.h $(TTF_DIR)/hipe_literals.h -$(TTF_DIR)/hipe_sparc_bifs.S: hipe/hipe_sparc_bifs.m4 hipe/hipe_sparc_asm.m4 hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h -$(OBJDIR)/hipe_sparc_bifs.o: $(TTF_DIR)/hipe_sparc_bifs.S $(TTF_DIR)/hipe_literals.h - -$(OBJDIR)/hipe_ppc_glue.o: hipe/hipe_ppc_glue.S $(TTF_DIR)/hipe_ppc_asm.h hipe/hipe_mode_switch.h $(TTF_DIR)/hipe_literals.h -$(TTF_DIR)/hipe_ppc_bifs.S: hipe/hipe_ppc_bifs.m4 hipe/hipe_ppc_asm.m4 hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h -$(OBJDIR)/hipe_ppc_bifs.o: $(TTF_DIR)/hipe_ppc_bifs.S $(TTF_DIR)/hipe_literals.h - -$(OBJDIR)/hipe_arm_glue.o: hipe/hipe_arm_glue.S $(TTF_DIR)/hipe_arm_asm.h hipe/hipe_mode_switch.h $(TTF_DIR)/hipe_literals.h -$(TTF_DIR)/hipe_arm_bifs.S: hipe/hipe_arm_bifs.m4 hipe/hipe_arm_asm.m4 hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h -$(OBJDIR)/hipe_arm_bifs.o: $(TTF_DIR)/hipe_arm_bifs.S $(TTF_DIR)/hipe_literals.h +$(OBJDIR)/hipe_x86_glue.o: hipe/hipe_x86_glue.S \ + $(TTF_DIR)/hipe_x86_asm.h $(TTF_DIR)/hipe_literals.h \ + hipe/hipe_mode_switch.h +$(TTF_DIR)/hipe_x86_bifs.S: hipe/hipe_x86_bifs.m4 hipe/hipe_x86_asm.m4 \ + hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h +$(OBJDIR)/hipe_x86_bifs.o: $(TTF_DIR)/hipe_x86_bifs.S \ + $(TTF_DIR)/hipe_literals.h + +$(OBJDIR)/hipe_amd64_glue.o: hipe/hipe_amd64_glue.S \ + $(TTF_DIR)/hipe_amd64_asm.h $(TTF_DIR)/hipe_literals.h \ + hipe/hipe_mode_switch.h +$(TTF_DIR)/hipe_amd64_bifs.S: hipe/hipe_amd64_bifs.m4 hipe/hipe_amd64_asm.m4 \ + hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h +$(OBJDIR)/hipe_amd64_bifs.o: $(TTF_DIR)/hipe_amd64_bifs.S \ + $(TTF_DIR)/hipe_literals.h + +$(OBJDIR)/hipe_sparc_glue.o: hipe/hipe_sparc_glue.S \ + $(TTF_DIR)/hipe_sparc_asm.h hipe/hipe_mode_switch.h \ + $(TTF_DIR)/hipe_literals.h +$(TTF_DIR)/hipe_sparc_bifs.S: hipe/hipe_sparc_bifs.m4 hipe/hipe_sparc_asm.m4 \ + hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h +$(OBJDIR)/hipe_sparc_bifs.o: $(TTF_DIR)/hipe_sparc_bifs.S \ + $(TTF_DIR)/hipe_literals.h + +$(OBJDIR)/hipe_ppc_glue.o: hipe/hipe_ppc_glue.S $(TTF_DIR)/hipe_ppc_asm.h \ + hipe/hipe_mode_switch.h $(TTF_DIR)/hipe_literals.h +$(TTF_DIR)/hipe_ppc_bifs.S: hipe/hipe_ppc_bifs.m4 hipe/hipe_ppc_asm.m4 \ + hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h +$(OBJDIR)/hipe_ppc_bifs.o: $(TTF_DIR)/hipe_ppc_bifs.S \ + $(TTF_DIR)/hipe_literals.h + +$(OBJDIR)/hipe_arm_glue.o: hipe/hipe_arm_glue.S $(TTF_DIR)/hipe_arm_asm.h \ + hipe/hipe_mode_switch.h $(TTF_DIR)/hipe_literals.h +$(TTF_DIR)/hipe_arm_bifs.S: hipe/hipe_arm_bifs.m4 hipe/hipe_arm_asm.m4 \ + hipe/hipe_bif_list.m4 $(TARGET)/erl_bif_list.h hipe/hipe_gbif_list.h +$(OBJDIR)/hipe_arm_bifs.o: $(TTF_DIR)/hipe_arm_bifs.S \ + $(TTF_DIR)/hipe_literals.h # end of HiPE section ######################################## @@ -927,13 +953,6 @@ $(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS) endif -# -# Create directories -# - -$(CREATE_DIRS): - $(MKDIR) -p $@ - # ---------------------------------------------------------------------- # Dependencies # @@ -945,6 +964,7 @@ $(TARGET)/Makefile: Makefile.in #SED_REPL_WIN_DRIVE=s|\([ ]\)\([A-Za-z]\):|\1/cygdrive/\2|g;s|^\([A-Za-z]\):|/cygdrive/\1|g SED_REPL_O=s|^\([^:]*:\)|$$(OBJDIR)/\1|g +SED_REPL_O_ZLIB=s|^\([^:]*:\)|$$(ZLIB_OBJDIR)/\1|g SED_REPL_TTF_DIR=s|$(TTF_DIR)/|$$(TTF_DIR)/|g SED_REPL_ERL_TOP=s|\([ ]\)$(ERL_TOP)/|\1$$(ERL_TOP)/|g;s|^$(ERL_TOP)/|$$(ERL_TOP)/|g SED_REPL_POLL=s|$$(OBJDIR)/erl_poll.o|$$(OBJDIR)/erl_poll.kp.o $$(OBJDIR)/erl_poll.nkp.o|g @@ -964,6 +984,7 @@ SED_SUFFIX= endif SED_DEPEND=sed '$(SED_PREFIX)$(SED_REPL_O);$(SED_REPL_TTF_DIR);$(SED_REPL_ERL_TOP)$(SED_SUFFIX)' +SED_DEPEND_ZLIB=sed '$(SED_PREFIX)$(SED_REPL_O_ZLIB)' ifdef HIPE_ENABLED HIPE_SRC=$(wildcard hipe/*.c) @@ -1008,22 +1029,36 @@ DEP_FLAGS=-MM $(MG_FLAG) $(CFLAGS) $(INCLUDES) -Idrivers/common -Idrivers/$(ERLA SYS_SRC=$(ALL_SYS_SRC) endif +.PHONY: depend +ifdef VOID_EMULATOR depend: + @echo $(VOID_EMULATOR)' - omitted target depend' +else +depend: $(TTF_DIR)/depend.mk +$(TTF_DIR)/depend.mk: $(TTF_DIR)/GENERATED $(DEP_CC) $(DEP_FLAGS) $(BEAM_SRC) \ - | $(SED_DEPEND) > $(TARGET)/depend.mk + | $(SED_DEPEND) > $(TTF_DIR)/depend.mk $(DEP_CC) $(DEP_FLAGS) -DLIBSCTP=$(LIBSCTP) $(DRV_COMMON_SRC) \ - | $(SED_DEPEND) >> $(TARGET)/depend.mk + | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk $(DEP_CC) $(DEP_FLAGS) -I../etc/$(ERLANG_OSTYPE) $(DRV_OSTYPE_SRC) \ - | $(SED_DEPEND) >> $(TARGET)/depend.mk + | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk $(DEP_CC) $(DEP_FLAGS) $(SYS_SRC) \ - | $(SED_DEPEND) >> $(TARGET)/depend.mk + | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk $(DEP_CC) $(DEP_FLAGS) $(TARGET_SRC) \ - | $(SED_DEPEND) >> $(TARGET)/depend.mk + | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk + $(DEP_CC) $(DEP_FLAGS) $(ZLIB_SRC) \ + | $(SED_DEPEND_ZLIB) >> $(TTF_DIR)/depend.mk ifdef HIPE_ENABLED $(DEP_CC) $(DEP_FLAGS) $(HIPE_SRC) \ - | $(SED_DEPEND) >> $(TARGET)/depend.mk + | $(SED_DEPEND) >> $(TTF_DIR)/depend.mk +endif + cd $(ERTS_LIB_DIR) && $(MAKE) depend endif --include $(TARGET)/depend.mk - - +ifneq ($(MAKECMDGOALS),clean) +ifneq ($(MAKECMDGOALS),generate) +ifndef VOID_EMULATOR +-include $(TTF_DIR)/depend.mk +endif +endif +endif diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 71454b3e57..7be40976f6 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -95,6 +95,7 @@ atom atom atom atom_used atom attributes atom await_proc_exit +atom await_sched_wall_time_modifications atom awaiting_load atom awaiting_unload atom backtrace backtrace_depth @@ -239,6 +240,7 @@ atom generational atom get_seq_token atom get_tcw atom getenv +atom gather_sched_wall_time_result atom getting_linked atom getting_unlinked atom global @@ -554,6 +556,7 @@ atom waiting atom wall_clock atom warning atom warning_msg +atom scheduler_wall_time atom wordsize atom write_concurrency atom xor diff --git a/erts/emulator/beam/beam_bp.c b/erts/emulator/beam/beam_bp.c index 692fa61fe8..dd13cd179a 100644 --- a/erts/emulator/beam/beam_bp.c +++ b/erts/emulator/beam/beam_bp.c @@ -1329,10 +1329,14 @@ static BpData *get_break(Process *p, BeamInstr *pc, BeamInstr break_op) { } static BpData *is_break(BeamInstr *pc, BeamInstr break_op) { - BpData **rs = (BpData **) pc[-4]; + BpData **rs; BpData *bd = NULL, *ebd = NULL; ASSERT(pc[-5] == (BeamInstr) BeamOp(op_i_func_info_IaaI)); + if (erts_is_native_break(pc)) { + return NULL; + } + rs = (BpData **) pc[-4]; if (! rs) { return NULL; } diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index 55f4798892..f8305944a4 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -43,6 +43,9 @@ static Export* set_cpu_topology_trap = NULL; static Export* await_proc_exit_trap = NULL; Export* erts_format_cpu_topology_trap = NULL; +static Export *await_sched_wall_time_mod_trap; +static erts_smp_atomic32_t sched_wall_time; + #define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1) /* @@ -4160,6 +4163,18 @@ BIF_RETTYPE system_flag_2(BIF_ALIST_2) erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); BIF_RET(am_true); + } else if (BIF_ARG_1 == am_scheduler_wall_time) { + if (BIF_ARG_2 == am_true || BIF_ARG_2 == am_false) { + erts_aint32_t new = BIF_ARG_2 == am_true ? 1 : 0; + erts_aint32_t old = erts_smp_atomic32_xchg_nob(&sched_wall_time, + new); + Eterm ref = erts_sched_wall_time_request(BIF_P, 1, new); + ASSERT(is_value(ref)); + BIF_TRAP2(await_sched_wall_time_mod_trap, + BIF_P, + ref, + old ? am_true : am_false); + } } else if (ERTS_IS_ATOM_STR("scheduling_statistics", BIF_ARG_1)) { int what; if (ERTS_IS_ATOM_STR("disable", BIF_ARG_2)) @@ -4457,6 +4472,9 @@ void erts_init_bif(void) am_format_cpu_topology, 1); await_proc_exit_trap = erts_export_put(am_erlang,am_await_proc_exit,3); + await_sched_wall_time_mod_trap + = erts_export_put(am_erlang, am_await_sched_wall_time_modifications, 2); + erts_smp_atomic32_init_nob(&sched_wall_time, 0); } #ifdef HARDDEBUG diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index 1e75afe6f6..4d02a67d54 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -1095,7 +1095,7 @@ get_kb_value(char *param_end, char** argv, int* ip) char *param = argv[*ip]+1; char *value = get_value(param_end, argv, ip); errno = 0; - tmp = (Sint) strtol(value, &rest, 10); + tmp = (Sint) ErtsStrToSint(value, &rest, 10); if (errno != 0 || rest == value || tmp < 0 || max < ((Uint) tmp)) bad_value(param, param_end, value); if (max == (Uint) tmp) @@ -1112,7 +1112,7 @@ get_byte_value(char *param_end, char** argv, int* ip) char *param = argv[*ip]+1; char *value = get_value(param_end, argv, ip); errno = 0; - tmp = (Sint) strtol(value, &rest, 10); + tmp = (Sint) ErtsStrToSint(value, &rest, 10); if (errno != 0 || rest == value || tmp < 0) bad_value(param, param_end, value); return (Uint) tmp; @@ -1126,7 +1126,7 @@ get_amount_value(char *param_end, char** argv, int* ip) char *param = argv[*ip]+1; char *value = get_value(param_end, argv, ip); errno = 0; - tmp = (Sint) strtol(value, &rest, 10); + tmp = (Sint) ErtsStrToSint(value, &rest, 10); if (errno != 0 || rest == value || tmp < 0) bad_value(param, param_end, value); return (Uint) tmp; diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index 962db8b831..90a6c0cbee 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -367,6 +367,7 @@ type EXPORT LONG_LIVED_LOW CODE export_entry type MONITOR_SH STANDARD_LOW PROCESSES monitor_sh type NLINK_SH STANDARD_LOW PROCESSES nlink_sh type AINFO_REQ STANDARD_LOW SYSTEM alloc_info_request +type SCHED_WTIME_REQ STANDARD_LOW SYSTEM sched_wall_time_request +else # "fullword" @@ -383,6 +384,7 @@ type EXPORT LONG_LIVED CODE export_entry type MONITOR_SH FIXED_SIZE PROCESSES monitor_sh type NLINK_SH FIXED_SIZE PROCESSES nlink_sh type AINFO_REQ SHORT_LIVED SYSTEM alloc_info_request +type SCHED_WTIME_REQ SHORT_LIVED SYSTEM sched_wall_time_request +endif diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c index c32938bdff..2e1a92f61d 100644 --- a/erts/emulator/beam/erl_alloc_util.c +++ b/erts/emulator/beam/erl_alloc_util.c @@ -3956,7 +3956,8 @@ realloc_thr_pref(ErtsAlcType_t type, void *extra, void *p, Uint size, if (used_allctr->thread_safe && (!force_move || used_allctr != pref_allctr)) erts_mtx_lock(&used_allctr->mutex); - ERTS_SMP_LC_ASSERT(erts_lc_mtx_is_locked(&used_allctr->mutex)); + ERTS_SMP_LC_ASSERT(!used_allctr->thread_safe || + erts_lc_mtx_is_locked(&used_allctr->mutex)); cpy_size = BLK_SZ(blk); if (used_allctr->thread_safe && (!force_move || used_allctr != pref_allctr)) diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 5a806777fe..ebd475f73a 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -57,6 +57,8 @@ static Export* alloc_info_trap = NULL; static Export* alloc_sizes_trap = NULL; +static Export *gather_sched_wall_time_res_trap; + #define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1) /* Keep erts_system_version as a global variable for easy access from a core */ @@ -3180,7 +3182,12 @@ BIF_RETTYPE statistics_1(BIF_ALIST_1) Eterm res; Eterm* hp; - if (BIF_ARG_1 == am_context_switches) { + if (BIF_ARG_1 == am_scheduler_wall_time) { + res = erts_sched_wall_time_request(BIF_P, 0, 0); + if (is_non_value(res)) + BIF_RET(am_undefined); + BIF_TRAP1(gather_sched_wall_time_res_trap, BIF_P, res); + } else if (BIF_ARG_1 == am_context_switches) { Eterm cs = erts_make_integer(erts_get_total_context_switches(), BIF_P); hp = HAlloc(BIF_P, 3); res = TUPLE2(hp, cs, SMALL_ZERO); @@ -4160,6 +4167,8 @@ erts_bif_info_init(void) alloc_info_trap = erts_export_put(am_erlang, am_alloc_info, 1); alloc_sizes_trap = erts_export_put(am_erlang, am_alloc_sizes, 1); + gather_sched_wall_time_res_trap + = erts_export_put(am_erlang, am_gather_sched_wall_time_result, 1); process_info_init(); os_info_init(); } diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h index e80eae0b86..7510f6b724 100644 --- a/erts/emulator/beam/erl_driver.h +++ b/erts/emulator/beam/erl_driver.h @@ -371,11 +371,17 @@ typedef struct erl_drv_entry { #ifndef ERL_DRIVER_TYPES_ONLY #if defined(VXWORKS) -# define DRIVER_INIT(DRIVER_NAME) ErlDrvEntry* DRIVER_NAME ## _init(void) +# define DRIVER_INIT(DRIVER_NAME) \ + ErlDrvEntry* DRIVER_NAME ## _init(void); \ + ErlDrvEntry* DRIVER_NAME ## _init(void) #elif defined(__WIN32__) -# define DRIVER_INIT(DRIVER_NAME) __declspec(dllexport) ErlDrvEntry* driver_init(void) +# define DRIVER_INIT(DRIVER_NAME) \ + __declspec(dllexport) ErlDrvEntry* driver_init(void); \ + __declspec(dllexport) ErlDrvEntry* driver_init(void) #else -# define DRIVER_INIT(DRIVER_NAME) ErlDrvEntry* driver_init(void) +# define DRIVER_INIT(DRIVER_NAME) \ + ErlDrvEntry* driver_init(void); \ + ErlDrvEntry* driver_init(void) #endif /* diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index eb2b945877..bde87b8346 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -357,10 +357,11 @@ erts_garbage_collect(Process* p, int need, Eterm* objv, int nobj) erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS); p->gcstatus = p->status; p->status = P_GARBING; + erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); + if (erts_system_monitor_long_gc != 0) { get_now(&ms1, &s1, &us1); } - erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS); ERTS_CHK_OFFHEAP(p); @@ -910,7 +911,18 @@ minor_collection(Process* p, int need, Eterm* objv, int nobj, Uint *recl) * XXX: WARNING: If HiPE starts storing other non-Erlang values on the * nstack, such as floats, then this will have to be changed. */ -#define offset_nstack(p,offs,area,area_size) offset_heap_ptr(hipe_nstack_start((p)),hipe_nstack_used((p)),(offs),(area),(area_size)) +static ERTS_INLINE void offset_nstack(Process* p, Sint offs, + char* area, Uint area_size) +{ + if (p->hipe.nstack) { + ASSERT(p->hipe.nsp && p->hipe.nstend); + offset_heap_ptr(hipe_nstack_start(p), hipe_nstack_used(p), + offs, area, area_size); + } + else { + ASSERT(!p->hipe.nsp && !p->hipe.nstend); + } +} #else /* !HIPE */ diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index 2b5e65b11a..a2b08fcf56 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -731,7 +731,6 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) int reds = ERTS_PORT_REDS_EXECUTE; erts_aint_t io_tasks_executed = 0; int fpe_was_unmasked; - ErtsPortTaskExeBlockData blk_data = {runq, NULL}; ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); @@ -965,8 +964,6 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) #endif done: - blk_data.resp = &res; - ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); ERTS_PORT_REDUCTIONS_EXECUTED(runq, reds); diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index b8c6b64fc0..eedbb35486 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -228,7 +228,6 @@ static Uint last_reductions; static Uint last_exact_reductions; Uint erts_default_process_flags; Eterm erts_system_monitor; -Eterm erts_system_monitor_msg_queue_len; Eterm erts_system_monitor_long_gc; Eterm erts_system_monitor_large_heap; struct erts_system_monitor_flags_t erts_system_monitor_flags; @@ -537,6 +536,209 @@ erts_late_init_process(void) } +static void +init_sched_wall_time(ErtsSchedWallTime *swtp) +{ + swtp->enabled = 0; + swtp->start = 0; + swtp->working.total = 0; + swtp->working.start = 0; + swtp->working.currently = 0; +} + +static ERTS_INLINE Uint64 +sched_wall_time_ts(void) +{ +#ifdef HAVE_GETHRTIME + return (Uint64) sys_gethrtime(); +#else + Uint64 res; + SysTimeval tv; + sys_gettimeofday(&tv); + res = (Uint64) tv.tv_sec*1000000; + res += (Uint64) tv.tv_usec; + return res; +#endif +} + +static ERTS_INLINE void +sched_wall_time_change(ErtsSchedulerData *esdp, int working) +{ + if (esdp->sched_wall_time.enabled) { + Uint64 ts = sched_wall_time_ts(); + if (working) { +#ifdef DEBUG + ASSERT(!esdp->sched_wall_time.working.currently); + esdp->sched_wall_time.working.currently = 1; +#endif + ts -= esdp->sched_wall_time.start; + esdp->sched_wall_time.working.start = ts; + } + else { +#ifdef DEBUG + ASSERT(esdp->sched_wall_time.working.currently); + esdp->sched_wall_time.working.currently = 0; +#endif + ts -= esdp->sched_wall_time.start; + ts -= esdp->sched_wall_time.working.start; + esdp->sched_wall_time.working.total += ts; + } + } +} + +typedef struct { + int set; + int enable; + Process *proc; + Eterm ref; + Eterm ref_heap[REF_THING_SIZE]; + Uint req_sched; + erts_smp_atomic32_t refc; +} ErtsSchedWallTimeReq; + +#if !HALFWORD_HEAP +ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(swtreq, + ErtsSchedWallTimeReq, + 5, + ERTS_ALC_T_SCHED_WTIME_REQ) +#else +static ERTS_INLINE ErtsSchedWallTimeReq * +swtreq_alloc(void) +{ + return erts_alloc(ERTS_ALC_T_SCHED_WTIME_REQ, + sizeof(ErtsSchedWallTimeReq)); +} + +static ERTS_INLINE void +swtreq_free(ErtsSchedWallTimeReq *ptr) +{ + erts_free(ERTS_ALC_T_SCHED_WTIME_REQ, ptr); +} +#endif + +static void +reply_sched_wall_time(void *vswtrp) +{ + Uint64 working = 0, total = 0; + ErtsSchedulerData *esdp = erts_get_scheduler_data(); + ErtsSchedWallTimeReq *swtrp = (ErtsSchedWallTimeReq *) vswtrp; + ErtsProcLocks rp_locks = (swtrp->req_sched == esdp->no + ? ERTS_PROC_LOCK_MAIN + : 0); + Process *rp = swtrp->proc; + Eterm ref_copy = NIL, msg; + Eterm *hp = NULL; + Eterm **hpp; + Uint sz, *szp; + ErlOffHeap *ohp = NULL; + ErlHeapFragment *bp = NULL; + + ASSERT(esdp); + + if (swtrp->set) { + if (!swtrp->enable && esdp->sched_wall_time.enabled) + esdp->sched_wall_time.enabled = 0; + else if (swtrp->enable && !esdp->sched_wall_time.enabled) { + Uint64 ts = sched_wall_time_ts(); + esdp->sched_wall_time.enabled = 1; + esdp->sched_wall_time.start = ts; + esdp->sched_wall_time.working.total = 0; + esdp->sched_wall_time.working.start = 0; + esdp->sched_wall_time.working.currently = 1; + } + } + + if (esdp->sched_wall_time.enabled) { + Uint64 ts = sched_wall_time_ts(); + ASSERT(esdp->sched_wall_time.working.currently); + ts -= esdp->sched_wall_time.start; + total = ts; + ts -= esdp->sched_wall_time.working.start; + working = esdp->sched_wall_time.working.total + ts; + } + + sz = 0; + hpp = NULL; + szp = &sz; + + while (1) { + if (hpp) + ref_copy = STORE_NC(hpp, ohp, swtrp->ref); + else + *szp += REF_THING_SIZE; + + if (swtrp->set) + msg = ref_copy; + else { + msg = (!esdp->sched_wall_time.enabled + ? am_notsup + : erts_bld_tuple(hpp, szp, 3, + make_small(esdp->no), + erts_bld_uint64(hpp, szp, working), + erts_bld_uint64(hpp, szp, total))); + + msg = erts_bld_tuple(hpp, szp, 2, ref_copy, msg); + } + if (hpp) + break; + + hp = erts_alloc_message_heap(sz, &bp, &ohp, rp, &rp_locks); + szp = NULL; + hpp = &hp; + } + + erts_queue_message(rp, &rp_locks, bp, msg, NIL); + + if (swtrp->req_sched == esdp->no) + rp_locks &= ~ERTS_PROC_LOCK_MAIN; + + if (rp_locks) + erts_smp_proc_unlock(rp, rp_locks); + + erts_smp_proc_dec_refc(rp); + + if (erts_smp_atomic32_dec_read_nob(&swtrp->refc) == 0) + swtreq_free(vswtrp); +} + +Eterm +erts_sched_wall_time_request(Process *c_p, int set, int enable) +{ + ErtsSchedulerData *esdp = ERTS_PROC_GET_SCHDATA(c_p); + Eterm ref; + ErtsSchedWallTimeReq *swtrp; + Eterm *hp; + + if (!set && !esdp->sched_wall_time.enabled) + return THE_NON_VALUE; + + swtrp = swtreq_alloc(); + ref = erts_make_ref(c_p); + hp = &swtrp->ref_heap[0]; + + swtrp->set = set; + swtrp->enable = enable; + swtrp->proc = c_p; + swtrp->ref = STORE_NC(&hp, NULL, ref); + swtrp->req_sched = esdp->no; + erts_smp_atomic32_init_nob(&swtrp->refc, + (erts_aint32_t) erts_no_schedulers); + + erts_smp_proc_add_refc(c_p, (Sint32) erts_no_schedulers); + +#ifdef ERTS_SMP + if (erts_no_schedulers > 1) + erts_schedule_multi_misc_aux_work(1, + erts_no_schedulers, + reply_sched_wall_time, + (void *) swtrp); +#endif + + reply_sched_wall_time((void *) swtrp); + + return ref; +} + static ERTS_INLINE ErtsProcList * proclist_create(Process *p) { @@ -1707,6 +1909,7 @@ aux_thread(void *unused) static void scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) { + int working = 1; ErtsSchedulerSleepInfo *ssi = esdp->ssi; int spincount; erts_aint32_t aux_work = 0; @@ -1737,12 +1940,17 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) tse_wait: + if (thr_prgr_active != working) + sched_wall_time_change(esdp, thr_prgr_active); + while (1) { aux_work = erts_atomic32_read_acqb(&ssi->aux_work); if (aux_work) { - if (!thr_prgr_active) + if (!thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 1); + sched_wall_time_change(esdp, 1); + } aux_work = handle_aux_work(&esdp->aux_work_data, aux_work); if (aux_work && erts_thr_progress_update(esdp)) erts_thr_progress_leader_update(esdp); @@ -1751,8 +1959,10 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) if (aux_work) flgs = erts_smp_atomic32_read_acqb(&ssi->flags); else { - if (thr_prgr_active) + if (thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 0); + sched_wall_time_change(esdp, 0); + } erts_thr_progress_prepare_wait(esdp); flgs = sched_spin_wait(ssi, spincount); @@ -1789,8 +1999,10 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) if (flgs & ~ERTS_SSI_FLG_SUSPENDED) erts_smp_atomic32_read_band_nob(&ssi->flags, ERTS_SSI_FLG_SUSPENDED); - if (!thr_prgr_active) + if (!thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 1); + sched_wall_time_change(esdp, 1); + } erts_smp_runq_lock(rq); sched_active(esdp->no, rq); @@ -1806,14 +2018,21 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) sched_waiting_sys(esdp->no, rq); + erts_smp_runq_unlock(rq); + ASSERT(working); + sched_wall_time_change(esdp, working = 0); + spincount = ERTS_SCHED_SYS_SLEEP_SPINCOUNT; while (spincount-- > 0) { sys_poll_aux_work: + if (working) + sched_wall_time_change(esdp, working = 0); + ASSERT(!erts_port_task_have_outstanding_io_tasks()); erl_sys_schedule(1); /* Might give us something to do */ @@ -1828,6 +2047,8 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) aux_work = erts_atomic32_read_acqb(&ssi->aux_work); if (aux_work) { + if (!working) + sched_wall_time_change(esdp, working = 1); #ifdef ERTS_SMP if (!thr_prgr_active) erts_thr_progress_active(esdp, thr_prgr_active = 1); @@ -1920,6 +2141,9 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) erts_smp_runq_unlock(rq); + if (working) + sched_wall_time_change(esdp, working = 0); + #ifdef ERTS_SMP if (thr_prgr_active) erts_thr_progress_active(esdp, thr_prgr_active = 0); @@ -1955,6 +2179,8 @@ scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq) if (flgs & ~ERTS_SSI_FLG_SUSPENDED) erts_smp_atomic32_read_band_nob(&ssi->flags, ERTS_SSI_FLG_SUSPENDED); #endif + if (!working) + sched_wall_time_change(esdp, working = 1); sched_active_sys(esdp->no, rq); } @@ -3430,9 +3656,14 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online) esdp->run_queue->scheduler = esdp; init_aux_work_data(&esdp->aux_work_data, esdp); + init_sched_wall_time(&esdp->sched_wall_time); } init_misc_aux_work(); +#if !HALFWORD_HEAP + init_swtreq_alloc(); +#endif + #ifdef ERTS_SMP @@ -3755,6 +3986,8 @@ suspend_scheduler(ErtsSchedulerData *esdp) if (erts_system_profile_flags.scheduler) profile_scheduler(make_small(esdp->no), am_inactive); + sched_wall_time_change(esdp, 0); + erts_smp_mtx_lock(&schdlr_sspnd.mtx); flgs = sched_prep_spin_suspended(ssi, ERTS_SSI_FLG_SUSPENDED); @@ -3813,16 +4046,20 @@ suspend_scheduler(ErtsSchedulerData *esdp) aux_work = erts_atomic32_read_acqb(&ssi->aux_work); if (aux_work) { - if (!thr_prgr_active) + if (!thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 1); + sched_wall_time_change(esdp, 1); + } aux_work = handle_aux_work(&esdp->aux_work_data, aux_work); if (aux_work && erts_thr_progress_update(esdp)) erts_thr_progress_leader_update(esdp); } if (!aux_work) { - if (thr_prgr_active) + if (thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 0); + sched_wall_time_change(esdp, 0); + } erts_thr_progress_prepare_wait(esdp); flgs = sched_spin_suspended(ssi, ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT); @@ -3877,8 +4114,10 @@ suspend_scheduler(ErtsSchedulerData *esdp) if (erts_system_profile_flags.scheduler) profile_scheduler(make_small(esdp->no), am_active); - if (!thr_prgr_active) + if (!thr_prgr_active) { erts_thr_progress_active(esdp, thr_prgr_active = 1); + sched_wall_time_change(esdp, 1); + } erts_smp_runq_lock(esdp->run_queue); non_empty_runq(esdp->run_queue); @@ -7980,15 +8219,6 @@ static void doit_exit_link(ErtsLink *lnk, void *vpcontext) if (rlnk) erts_destroy_link(rlnk); erts_deref_dist_entry(dep); - } else { -#ifndef ERTS_SMP - /* XXX Is this possible? Shouldn't this link - previously have been removed if the node - had previously been disconnected. */ - ASSERT(0); -#endif - /* This is possible when smp support has been enabled, - and dist port and process exits simultaneously. */ } break; diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index a51b380bb0..173b7df69d 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -394,6 +394,16 @@ do { \ } while (0) typedef struct { + int enabled; + Uint64 start; + struct { + Uint64 total; + Uint64 start; + int currently; + } working; +} ErtsSchedWallTime; + +typedef struct { int sched_id; ErtsSchedulerData *esdp; ErtsSchedulerSleepInfo *ssi; @@ -457,6 +467,8 @@ struct ErtsSchedulerData_ { ErtsSchedAllocData alloc_data; + ErtsSchedWallTime sched_wall_time; + #ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC erts_alloc_verify_func_t verify_unused_temp_alloc; Allctr_t *verify_unused_temp_alloc_data; @@ -1064,6 +1076,8 @@ void erts_late_init_process(void); void erts_early_init_scheduling(int); void erts_init_scheduling(int, int); +Eterm erts_sched_wall_time_request(Process *c_p, int set, int enable); + ErtsProcList *erts_proclist_create(Process *); void erts_proclist_destroy(ErtsProcList *); int erts_proclist_same(ErtsProcList *, Process *); diff --git a/erts/emulator/beam/erl_thr_progress.c b/erts/emulator/beam/erl_thr_progress.c index 02f36fc75e..75f8209c3b 100644 --- a/erts/emulator/beam/erl_thr_progress.c +++ b/erts/emulator/beam/erl_thr_progress.c @@ -915,7 +915,7 @@ has_reached_wakeup(ErtsThrPrgrVal wakeup) if (limit == ERTS_THR_PRGR_VAL_WAITING) limit = 0; else if (limit < current) /* Wrapped */ - limit + 1; + limit += 1; if (!erts_thr_progress_has_passed__(limit, wakeup)) erl_exit(ERTS_ABORT_EXIT, diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index b487dbf054..b1d1e1d9b0 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -544,7 +544,7 @@ send_to_port(Process *c_p, Eterm message, */ static void -profile_send(Eterm message) { +profile_send(Eterm from, Eterm message) { Uint sz = 0; ErlHeapFragment *bp = NULL; Uint *hp = NULL; @@ -554,6 +554,9 @@ profile_send(Eterm message) { Eterm profiler = erts_get_system_profile(); + /* do not profile profiler pid */ + if (from == profiler) return; + if (is_internal_port(profiler)) { Port *profiler_port = NULL; @@ -2617,7 +2620,7 @@ profile_scheduler(Eterm scheduler_id, Eterm state) { make_small(active_sched), timestamp); hp += 7; #ifndef ERTS_SMP - profile_send(msg); + profile_send(NIL, msg); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE #else @@ -2652,7 +2655,7 @@ profile_scheduler_q(Eterm scheduler_id, Eterm state, Eterm no_schedulers, Uint M timestamp = TUPLE3(hp, make_small(Ms), make_small(s), make_small(us)); hp += 4; msg = TUPLE6(hp, am_profile, am_scheduler, scheduler_id, state, no_schedulers, timestamp); hp += 7; #ifndef ERTS_SMP - profile_send(msg); + profile_send(NIL, msg); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE #else @@ -2919,11 +2922,11 @@ profile_runnable_port(Port *p, Eterm status) { msg = TUPLE5(hp, am_profile, p->id, status, count, timestamp); hp += 6; #ifndef ERTS_SMP - profile_send(msg); + profile_send(p->id, msg); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE #else - enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, NIL, NIL, msg, bp); + enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, p->id, NIL, msg, bp); #endif erts_smp_mtx_unlock(&smq_mtx); } @@ -2972,11 +2975,11 @@ profile_runnable_proc(Process *p, Eterm status){ timestamp = TUPLE3(hp, make_small(Ms), make_small(s), make_small(us)); hp += 4; msg = TUPLE5(hp, am_profile, p->id, status, where, timestamp); hp += 6; #ifndef ERTS_SMP - profile_send(msg); + profile_send(p->id, msg); UnUseTmpHeapNoproc(LOCAL_HEAP_SIZE); #undef LOCAL_HEAP_SIZE #else - enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, NIL, NIL, msg, bp); + enqueue_sys_msg_unlocked(SYS_MSG_TYPE_SYSPROF, p->id, NIL, msg, bp); #endif erts_smp_mtx_unlock(&smq_mtx); } diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 49cd0e5f53..b23b1f628d 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2011. All Rights Reserved. + * Copyright Ericsson AB 1996-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -818,6 +818,11 @@ erts_smp_xports_unlock(Port *prt) #define SET_VEC(iov, bv, bin, ptr, len, vlen) do { \ (iov)->iov_base = (ptr); \ (iov)->iov_len = (len); \ + if (sizeof((iov)->iov_len) < sizeof(len) \ + /* Check if (len) overflowed (iov)->iov_len */ \ + && ((len) >> (sizeof((iov)->iov_len)*CHAR_BIT)) != 0) { \ + goto L_overflow; \ + } \ *(bv)++ = (bin); \ (iov)++; \ (vlen)++; \ @@ -1146,11 +1151,21 @@ int erts_write_to_port(Eterm caller_id, Port *p, Eterm list) ivp[0].iov_len = 0; bvp[0] = NULL; ev.vsize = io_list_to_vec(list, ivp+1, bvp+1, cbin, blimit); + if (ev.vsize < 0) { + if (ivp != iv) { + erts_free(ERTS_ALC_T_TMP, (void *) ivp); + } + if (bvp != bv) { + erts_free(ERTS_ALC_T_TMP, (void *) bvp); + } + driver_free_binary(cbin); + goto bad_value; + } ev.vsize++; #if 0 /* This assertion may say something useful, but it can be falsified during the emulator test suites. */ - ASSERT((ev.vsize >= 0) && (ev.vsize == vsize)); + ASSERT(ev.vsize == vsize); #endif ev.size = size; /* total size */ ev.iov = ivp; @@ -3912,7 +3927,7 @@ int driver_pushqv(ErlDrvPort ix, ErlIOVec* vec, ErlDrvSizeT skip) ErlDrvSizeT driver_deq(ErlDrvPort ix, ErlDrvSizeT size) { ErlIOQueue* q = drvport2ioq(ix); - int len; + ErlDrvSizeT len; if ((q == NULL) || (q->size < size)) return -1; diff --git a/erts/emulator/beam/register.h b/erts/emulator/beam/register.h index 97bab3ab71..bf15e63554 100644 --- a/erts/emulator/beam/register.h +++ b/erts/emulator/beam/register.h @@ -41,7 +41,7 @@ struct port; typedef struct reg_proc { HashBucket bucket; /* MUST BE LOCATED AT TOP OF STRUCT!!! */ - Process *p; /* The process registerd (only one of this and + Process *p; /* The process registered (only one of this and 'pt' is non-NULL */ struct port *pt; /* The port registered */ Eterm name; /* Atom name */ diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index 6b4b382caa..eb6f2f8516 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -256,6 +256,7 @@ typedef unsigned int Eterm; typedef unsigned int Uint; typedef int Sint; #define ERTS_SIZEOF_ETERM SIZEOF_INT +#define ErtsStrToSint strtol #else #error Found no appropriate type to use for 'Eterm', 'Uint' and 'Sint' #endif @@ -288,6 +289,7 @@ typedef long Sint; #define SWORD_CONSTANT(Const) Const##L #define UWORD_CONSTANT(Const) Const##UL #define ERTS_SIZEOF_ETERM SIZEOF_LONG +#define ErtsStrToSint strtol #elif SIZEOF_VOID_P == SIZEOF_INT typedef unsigned int Eterm; typedef unsigned int Uint; @@ -295,6 +297,7 @@ typedef int Sint; #define SWORD_CONSTANT(Const) Const #define UWORD_CONSTANT(Const) Const##U #define ERTS_SIZEOF_ETERM SIZEOF_INT +#define ErtsStrToSint strtol #elif SIZEOF_VOID_P == SIZEOF_LONG_LONG typedef unsigned long long Eterm; typedef unsigned long long Uint; @@ -302,6 +305,11 @@ typedef long long Sint; #define SWORD_CONSTANT(Const) Const##LL #define UWORD_CONSTANT(Const) Const##ULL #define ERTS_SIZEOF_ETERM SIZEOF_LONG_LONG +#if defined(__WIN32__) +#define ErtsStrToSint _strtoi64 +#else +#define ErtsStrToSint strtoll +#endif #else #error Found no appropriate type to use for 'Eterm', 'Uint' and 'Sint' #endif diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index b132991a3b..36ed108b76 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -1385,7 +1385,11 @@ static void invoke_writev(void *data) { size = d->c.writev.size; } - /* Copy the io vector to avoid locking the port que while writing */ + /* Copy the io vector to avoid locking the port que while writing, + * also, both we and efile_writev might/will change the SysIOVec + * when segmenting or due to partial write and we do not want to + * tamper with the actual queue that we get from driver_peekq + */ MUTEX_LOCK(d->c.writev.q_mtx); /* Lock before accessing the port queue */ iov0 = driver_peekq(d->c.writev.port, &iovlen); @@ -1424,7 +1428,7 @@ static void invoke_writev(void *data) { } else { d->result_ok = efile_writev(&d->errInfo, d->flags, (int) d->fd, - iov, iovcnt, size); + iov, iovcnt); } } else if (iovlen == 0) { d->result_ok = 1; diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h index 3868b38137..69ad02633c 100644 --- a/erts/emulator/drivers/common/erl_efile.h +++ b/erts/emulator/drivers/common/erl_efile.h @@ -162,7 +162,7 @@ int efile_write_info(Efile_error* errInfo, Efile_info* pInfo, char *name); int efile_write(Efile_error* errInfo, int flags, int fd, char* buf, size_t count); int efile_writev(Efile_error* errInfo, int flags, int fd, - SysIOVec* iov, int iovcnt, size_t size); + SysIOVec* iov, int iovcnt); int efile_read(Efile_error* errInfo, int flags, int fd, char* buf, size_t count, size_t* pBytesRead); int efile_seek(Efile_error* errInfo, int fd, diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index eeaa4d24ea..47a99fdbe6 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -6194,6 +6194,7 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) type = SCTP_DEFAULT_SEND_PARAM; arg_ptr = (char*) (&arg.sri); arg_sz = sizeof ( arg.sri); + VALGRIND_MAKE_MEM_DEFINED(arg_ptr, arg_sz); /*suppress "uninitialised bytes"*/ break; } case SCTP_OPT_EVENTS: @@ -10299,7 +10300,6 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) cmsg.hdr.cmsg_level = IPPROTO_SCTP; cmsg.hdr.cmsg_type = SCTP_SNDRCV; cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(*sri)); - VALGRIND_MAKE_MEM_DEFINED(&cmsg, (char*)sri - (char*)&cmsg); /*suppress padding as "uninitialised bytes"*/ data_len = (buf + len) - ptr; /* The whole msg. @@ -10313,6 +10313,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) mhdr.msg_iovlen = 1; mhdr.msg_control = cmsg.ancd; /* For ancilary data */ mhdr.msg_controllen = cmsg.hdr.cmsg_len; + VALGRIND_MAKE_MEM_DEFINED(mhdr.msg_control, mhdr.msg_controllen); /*suppress "uninitialised bytes"*/ mhdr.msg_flags = 0; /* Not used with "sendmsg" */ /* Now do the actual sending. NB: "flags" in "sendmsg" itself are NOT diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 7cf0a712ce..796843a735 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -1004,13 +1004,11 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ * opened */ int fd, /* File descriptor to write to */ SysIOVec* iov, /* Vector of buffer structs. - * The structs are unchanged - * after the call */ - int iovcnt, /* Number of structs in vector */ - size_t size) /* Number of bytes to write */ + * The structs may be changed i.e. + * due to incomplete writes */ + int iovcnt) /* Number of structs in vector */ { int cnt = 0; /* Buffers so far written */ - int p = 0; /* Position in next buffer */ ASSERT(iovcnt >= 0); @@ -1021,66 +1019,47 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ #endif while (cnt < iovcnt) { + if ((! iov[cnt].iov_base) || (iov[cnt].iov_len <= 0)) { + /* Empty buffer - skip */ + cnt++; + } else { /* Non-empty buffer */ + ssize_t w; /* Bytes written in this call */ #ifdef HAVE_WRITEV - int w; /* Bytes written in this call */ - int b = iovcnt - cnt; /* Buffers to write */ - if (b > MAXIOV) - b = MAXIOV; - if (iov[cnt].iov_base && iov[cnt].iov_len > 0) { - if (b == 1) { - /* Degenerated io vector */ - do { - w = write(fd, iov[cnt].iov_base + p, iov[cnt].iov_len - p); - } while (w < 0 && errno == EINTR); - } else { - /* Non-empty vector first. - * Adjust pos in first buffer in case of - * previous incomplete writev */ - iov[cnt].iov_base += p; - iov[cnt].iov_len -= p; + int b = iovcnt - cnt; /* Buffers to write */ + /* Use as many buffers as MAXIOV allows */ + if (b > MAXIOV) + b = MAXIOV; + if (b > 1) { do { w = writev(fd, &iov[cnt], b); } while (w < 0 && errno == EINTR); - iov[cnt].iov_base -= p; - iov[cnt].iov_len += p; - } - if (w < 0) - return check_error(-1, errInfo); - } else { - /* Empty vector first - skip */ - cnt++; - continue; - } - ASSERT(w >= 0); - /* Move forward to next vector to write */ - for (; cnt < iovcnt; cnt++) { - if (iov[cnt].iov_base && iov[cnt].iov_len > 0) { - if (w < iov[cnt].iov_len) - break; - else - w -= iov[cnt].iov_len; - } - } - ASSERT(w >= 0); - p = w > 0 ? w : 0; /* Skip p bytes next writev */ -#else /* #ifdef HAVE_WRITEV */ - if (iov[cnt].iov_base && iov[cnt].iov_len > 0) { - /* Non-empty vector */ - int w; /* Bytes written in this call */ - while (p < iov[cnt].iov_len) { - do { - w = write(fd, iov[cnt].iov_base + p, iov[cnt].iov_len - p); - } while (w < 0 && errno == EINTR); - if (w < 0) - return check_error(-1, errInfo); - p += w; + } else + /* Degenerated io vector - use regular write */ +#endif + { + do { + w = write(fd, iov[cnt].iov_base, iov[cnt].iov_len); + } while (w < 0 && errno == EINTR); + ASSERT(w <= iov[cnt].iov_len); + } + if (w < 0) return check_error(-1, errInfo); + /* Move forward to next buffer to write */ + for (; cnt < iovcnt && w > 0; cnt++) { + if (iov[cnt].iov_base && iov[cnt].iov_len > 0) { + if (w < iov[cnt].iov_len) { + /* Adjust the buffer for next write */ + iov[cnt].iov_len -= w; + iov[cnt].iov_base += w; + w = 0; + break; + } else { + w -= iov[cnt].iov_len; + } + } } - } - cnt++; - p = 0; -#endif /* #ifdef HAVE_WRITEV */ + ASSERT(w == 0); + } /* else Non-empty buffer */ } /* while (cnt< iovcnt) */ - size = 0; /* Avoid compiler warning */ return 1; } @@ -1427,10 +1406,9 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset, } #ifdef HAVE_SENDFILE - // For some reason the maximum size_t cannot be used as the max size // 3GB seems to work on all platforms -#define SENDFILE_CHUNK_SIZE ((1 << 30) -1) +#define SENDFILE_CHUNK_SIZE ((1UL << 30) -1) /* * sendfile: The implementation of the sendfile system call varies @@ -1467,7 +1445,7 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd, written += retval; *nbytes -= retval; } - } while (retval != -1 && retval == SENDFILE_CHUNK_SIZE); + } while (retval == SENDFILE_CHUNK_SIZE); *nbytes = written; return check_error(retval == -1 ? -1 : 0, errInfo); #elif defined(__sun) && defined(__SVR4) && defined(HAVE_SENDFILEV) diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index 0d3d334154..606fa1d7de 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -1115,8 +1115,7 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ SysIOVec* iov, /* Vector of buffer structs. * The structs are unchanged * after the call */ - int iovcnt, /* Number of structs in vector */ - size_t size) /* Number of bytes to write */ + int iovcnt) /* Number of structs in vector */ { int cnt; /* Buffers so far written */ OVERLAPPED overlapped; diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index cec22b3836..28e4382835 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -174,8 +174,13 @@ static inline unsigned char *bytearray_lvalue(Eterm bin, Eterm idx) { Sint i; unsigned char *bytes; +#ifndef DEBUG + ERTS_DECLARE_DUMMY(Uint bitoffs); + ERTS_DECLARE_DUMMY(Uint bitsize); +#else Uint bitoffs; Uint bitsize; +#endif if (is_not_binary(bin) || is_not_small(idx) || @@ -235,9 +240,15 @@ BIF_RETTYPE hipe_bifs_bitarray_2(BIF_ALIST_2) BIF_RETTYPE hipe_bifs_bitarray_update_3(BIF_ALIST_3) { unsigned char *bytes, bytemask; - Uint bitoffs, bitsize; Uint bitnr, bytenr; int set; +#ifndef DEBUG + ERTS_DECLARE_DUMMY(Uint bitoffs); + ERTS_DECLARE_DUMMY(Uint bitsize); +#else + Uint bitoffs; + Uint bitsize; +#endif if (is_not_binary(BIF_ARG_1)) BIF_ERROR(BIF_P, BADARG); @@ -267,8 +278,15 @@ BIF_RETTYPE hipe_bifs_bitarray_update_3(BIF_ALIST_3) BIF_RETTYPE hipe_bifs_bitarray_sub_2(BIF_ALIST_2) { unsigned char *bytes, bytemask; - Uint bitoffs, bitsize; Uint bitnr, bytenr; +#ifndef DEBUG + ERTS_DECLARE_DUMMY(Uint bitoffs); + ERTS_DECLARE_DUMMY(Uint bitsize); +#else + Uint bitoffs; + Uint bitsize; +#endif + if (is_not_binary(BIF_ARG_1)) BIF_ERROR(BIF_P, BADARG); @@ -397,10 +415,15 @@ BIF_RETTYPE hipe_bifs_enter_code_2(BIF_ALIST_2) Uint nrbytes; void *bytes; void *address; - Uint bitoffs; - Uint bitsize; Eterm trampolines; Eterm *hp; +#ifndef DEBUG + ERTS_DECLARE_DUMMY(Uint bitoffs); + ERTS_DECLARE_DUMMY(Uint bitsize); +#else + Uint bitoffs; + Uint bitsize; +#endif if (is_not_binary(BIF_ARG_1)) BIF_ERROR(BIF_P, BADARG); diff --git a/erts/emulator/hipe/hipe_gc.c b/erts/emulator/hipe/hipe_gc.c index 0199dea99e..e0575c35ff 100644 --- a/erts/emulator/hipe/hipe_gc.c +++ b/erts/emulator/hipe/hipe_gc.c @@ -46,9 +46,14 @@ Eterm *fullsweep_nstack(Process *p, Eterm *n_htop) char *src, *oh; Uint src_size, oh_size; + if (!p->hipe.nstack) { + ASSERT(!p->hipe.nsp && !p->hipe.nstend); + return n_htop; + } if (!nstack_walk_init_check(p)) return n_htop; + ASSERT(p->hipe.nsp && p->hipe.nstend); nsp = nstack_walk_nsp_begin(p); nsp_end = p->hipe.nstgraylim; if (nsp_end) @@ -136,9 +141,14 @@ void gensweep_nstack(Process *p, Eterm **ptr_old_htop, Eterm **ptr_n_htop) char *heap; Uint heap_size, mature_size; + if (!p->hipe.nstack) { + ASSERT(!p->hipe.nsp && !p->hipe.nstend); + return; + } if (!nstack_walk_init_check(p)) return; + ASSERT(p->hipe.nsp && p->hipe.nstend); nsp = nstack_walk_nsp_begin(p); nsp_end = p->hipe.nstgraylim; if (nsp_end) { diff --git a/erts/emulator/pcre/pcre.mk b/erts/emulator/pcre/pcre.mk index b752c11459..352137b341 100644 --- a/erts/emulator/pcre/pcre.mk +++ b/erts/emulator/pcre/pcre.mk @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2011. All Rights Reserved. +# Copyright Ericsson AB 2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -17,8 +17,6 @@ # %CopyrightEnd% # -ARFLAGS = rc - PCRE_O = \ pcre_latin_1_table.o \ pcre_compile.o \ @@ -43,7 +41,7 @@ pcre_xclass.o PCRE_OBJS = $(PCRE_O:%=$(PCRE_OBJDIR)/%) -GENINC = pcre/pcre_exec_loop_break_cases.inc +PCRE_GENINC = $(ERL_TOP)/erts/emulator/pcre/pcre_exec_loop_break_cases.inc PCRE_OBJDIR = $(ERL_TOP)/erts/emulator/pcre/obj/$(TARGET)/$(TYPE) @@ -61,12 +59,12 @@ endif $(PCRE_OBJDIR)/%.o: pcre/%.c $(CC) -c $(PCRE_CFLAGS) -o $@ $< -$(GENINC): pcre/pcre_exec.c +$(PCRE_GENINC): pcre/pcre_exec.c for x in `grep -n COST_CHK pcre/pcre_exec.c | grep -v 'COST_CHK(N)' | awk -F: '{print $$1}'`; \ do \ N=`expr $$x + 100`; \ echo "case $$N: goto L_LOOP_COUNT_$${x};"; \ - done > $(GENINC) + done > $(PCRE_GENINC) # Dependencies. @@ -79,7 +77,7 @@ $(PCRE_OBJDIR)/pcre_config.o: pcre/pcre_config.c pcre/pcre_internal.h \ $(PCRE_OBJDIR)/pcre_dfa_exec.o: pcre/pcre_dfa_exec.c pcre/pcre_internal.h \ pcre/local_config.h pcre/pcre.h pcre/ucp.h $(PCRE_OBJDIR)/pcre_exec.o: pcre/pcre_exec.c pcre/pcre_internal.h \ - pcre/local_config.h pcre/pcre.h pcre/ucp.h $(GENINC) + pcre/local_config.h pcre/pcre.h pcre/ucp.h $(PCRE_GENINC) $(PCRE_OBJDIR)/pcre_fullinfo.o: pcre/pcre_fullinfo.c pcre/pcre_internal.h \ pcre/local_config.h pcre/pcre.h pcre/ucp.h $(PCRE_OBJDIR)/pcre_get.o: pcre/pcre_get.c pcre/pcre_internal.h \ diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c index b6cb271f17..3817b1e4d5 100644 --- a/erts/emulator/sys/common/erl_poll.c +++ b/erts/emulator/sys/common/erl_poll.c @@ -1949,7 +1949,7 @@ check_fd_events(ErtsPollSet ps, SysTimeval *tv, int max_res) */ struct dvpoll poll_res; int nfds = (int) erts_smp_atomic_read_nob(&ps->no_of_user_fds); -#ifdef ERTS_SMP +#if ERTS_POLL_USE_WAKEUP_PIPE nfds++; /* Wakeup pipe */ #endif if (timeout > INT_MAX) @@ -2487,7 +2487,7 @@ ERTS_POLL_EXPORT(erts_poll_info)(ErtsPollSet ps, ErtsPollInfo *pip) pip->memory_size = size; pip->poll_set_size = (int) erts_smp_atomic_read_nob(&ps->no_of_user_fds); -#ifdef ERTS_SMP +#if ERTS_POLL_USE_WAKEUP_PIPE pip->poll_set_size++; /* Wakeup pipe */ #endif diff --git a/erts/emulator/test/Makefile b/erts/emulator/test/Makefile index 08d2066da3..a3dcbc4cf3 100644 --- a/erts/emulator/test/Makefile +++ b/erts/emulator/test/Makefile @@ -88,6 +88,7 @@ MODULES= \ send_term_SUITE \ sensitive_SUITE \ signal_SUITE \ + smoke_test_SUITE \ statistics_SUITE \ system_info_SUITE \ system_profile_SUITE \ diff --git a/erts/emulator/test/call_trace_SUITE.erl b/erts/emulator/test/call_trace_SUITE.erl index 3e2bee06d1..7030ebed3f 100644 --- a/erts/emulator/test/call_trace_SUITE.erl +++ b/erts/emulator/test/call_trace_SUITE.erl @@ -165,10 +165,14 @@ worker_loop() -> worker_foo(_Arg) -> ok. -basic(doc) -> - "Basic test of the call tracing (we trace one process)."; -basic(suite) -> []; -basic(Config) when is_list(Config) -> +%% Basic test of the call tracing (we trace one process). +basic(_Config) -> + case test_server:is_native(lists) of + true -> {skip,"lists is native"}; + false -> basic() + end. + +basic() -> ?line start_tracer(), ?line trace_info(self(), flags), ?line trace_info(self(), tracer), @@ -263,9 +267,15 @@ foo() -> foo0. foo(X) -> X+1. foo(X, Y) -> X+Y. -flags(doc) -> "Test flags (arity, timestamp) for call_trace/3. " - "Also, test the '{tracer,Pid}' option."; -flags(Config) when is_list(Config) -> +%% Test flags (arity, timestamp) for call_trace/3. +%% Also, test the '{tracer,Pid}' option. +flags(_Config) -> + case test_server:is_native(filename) of + true -> {skip,"filename is native"}; + false -> flags() + end. + +flags() -> ?line Tracer = start_tracer_loop(), ?line trace_pid(self(), true, [call,{tracer,Tracer}]), @@ -428,9 +438,14 @@ pam_foo(A, B) -> {ok,A,B}. -change_pam(doc) -> "Test changing PAM programs for a function."; -change_pam(suite) -> []; -change_pam(Config) when is_list(Config) -> +%% Test changing PAM programs for a function. +change_pam(_Config) -> + case test_server:is_native(lists) of + true -> {skip,"lists is native"}; + false -> change_pam() + end. + +change_pam() -> ?line start_tracer(), ?line Self = self(), @@ -468,10 +483,11 @@ change_pam_trace(Prog) -> {match_spec,Prog} = trace_info({erlang,process_info,2}, match_spec), ok. -return_trace(doc) -> "Test the new return trace."; -return_trace(suite) -> []; -return_trace(Config) when is_list(Config) -> - return_trace(). +return_trace(_Config) -> + case test_server:is_native(lists) of + true -> {skip,"lists is native"}; + false -> return_trace() + end. return_trace() -> X = {save,me}, @@ -521,7 +537,7 @@ return_trace() -> ?line {match_spec,Prog2} = trace_info({erlang,atom_to_list,1}, match_spec), ?line lists:seq(2, 7), - ?line atom_to_list(non_literal(nisse)), + ?line _ = atom_to_list(non_literal(nisse)), ?line expect({trace,Self,return_from,{lists,seq,2},[2,3,4,5,6,7]}), ?line expect({trace,Self,return_from,{erlang,atom_to_list,1},"nisse"}), @@ -539,10 +555,11 @@ return_trace() -> nasty() -> exit(good_bye). -exception_trace(doc) -> "Test the new exception trace."; -exception_trace(suite) -> []; -exception_trace(Config) when is_list(Config) -> - exception_trace(). +exception_trace(_Config) -> + case test_server:is_native(lists) of + true -> {skip,"lists is native"}; + false -> exception_trace() + end. exception_trace() -> X = {save,me}, @@ -600,7 +617,7 @@ exception_trace() -> trace_info({erlang,atom_to_list,1}, match_spec), ?line lists:seq(2, 7), - ?line atom_to_list(non_literal(nisse)), + ?line _ = atom_to_list(non_literal(nisse)), ?line expect({trace,Self,return_from,{lists,seq,2},[2,3,4,5,6,7]}), ?line expect({trace,Self,return_from,{erlang,atom_to_list,1},"nisse"}), diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index 370363bf9e..6bd7361612 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -859,7 +859,13 @@ resource_holder(Pid,Reply,List) -> threading(doc) -> ["Test the threading API functions (reuse tests from driver API)"]; -threading(Config) when is_list(Config) -> +threading(Config) when is_list(Config) -> + case erlang:system_info(threads) of + true -> threading_do(Config); + false -> {skipped,"No thread support"} + end. + +threading_do(Config) -> ?line Data = ?config(data_dir, Config), ?line File = filename:join(Data, "tester"), ?line {ok,tester,ModBin} = compile:file(File, [binary,return_errors]), diff --git a/erts/emulator/test/nif_SUITE_data/tester.c b/erts/emulator/test/nif_SUITE_data/tester.c index 08466d0f18..257b116322 100644 --- a/erts/emulator/test/nif_SUITE_data/tester.c +++ b/erts/emulator/test/nif_SUITE_data/tester.c @@ -61,6 +61,7 @@ static int reload(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) static ERL_NIF_TERM run(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { testcase_run(NULL); + testcase_cleanup(NULL); return enif_make_atom(env, "ok"); } diff --git a/erts/emulator/test/smoke_test_SUITE.erl b/erts/emulator/test/smoke_test_SUITE.erl new file mode 100644 index 0000000000..98f1cf1ad5 --- /dev/null +++ b/erts/emulator/test/smoke_test_SUITE.erl @@ -0,0 +1,139 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(smoke_test_SUITE). + +-include_lib("test_server/include/test_server.hrl"). + +%-compile(export_all). +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_group/2,end_per_group/2, + init_per_testcase/2, end_per_testcase/2]). + +-export([boot_combo/1]). + +-define(DEFAULT_TIMEOUT, ?t:minutes(2)). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [boot_combo]. + +groups() -> + []. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +init_per_testcase(Case, Config) when is_list(Config) -> + Dog = ?t:timetrap(?DEFAULT_TIMEOUT), + [{testcase, Case},{watchdog, Dog}|Config]. + +end_per_testcase(_Case, Config) when is_list(Config) -> + Dog = ?config(watchdog, Config), + ?t:timetrap_cancel(Dog), + ok. + +%%% +%%% The test cases ------------------------------------------------------------- +%%% + +boot_combo(Config) when is_list(Config) -> + ZFlags = os:getenv("ERL_ZFLAGS"), + NOOP = fun () -> ok end, + A42 = fun () -> + case erlang:system_info(threads) of + true -> + 42 = erlang:system_info(thread_pool_size); + false -> + ok + end + end, + SMPDisable = fun () -> false = erlang:system_info(smp_support) end, + try + chk_boot(Config, "+Ktrue", NOOP), + chk_boot(Config, "+A42", A42), + chk_boot(Config, "-smp disable", SMPDisable), + chk_boot(Config, "+Ktrue +A42", A42), + chk_boot(Config, "-smp disable +A42", + fun () -> SMPDisable(), A42() end), + chk_boot(Config, "-smp disable +Ktrue", SMPDisable), + chk_boot(Config, "-smp disable +Ktrue +A42", + fun () -> SMPDisable(), A42() end), + %% A lot more combos could be implemented... + ok + after + os:putenv("ERL_ZFLAGS", case ZFlags of + false -> ""; + _ -> ZFlags + end) + end. + +%%% +%%% Aux functions -------------------------------------------------------------- +%%% + +chk_boot(Config, Args, Fun) -> + true = os:putenv("ERL_ZFLAGS", Args), + Success = make_ref(), + Parent = self(), + ?t:format("--- Testing ~s~n", [Args]), + {ok, Node} = start_node(Config), + Pid = spawn_link(Node, fun () -> + Fun(), + Parent ! {self(), Success} + end), + receive + {Pid, Success} -> + Node = node(Pid), + stop_node(Node), + ?t:format("--- Success!~n", []), + ok + end. + +start_node(Config) -> + start_node(Config, ""). + +start_node(Config, Args) when is_list(Config) -> + ?line Pa = filename:dirname(code:which(?MODULE)), + ?line {A, B, C} = now(), + ?line Name = list_to_atom(atom_to_list(?MODULE) + ++ "-" + ++ atom_to_list(?config(testcase, Config)) + ++ "-" + ++ integer_to_list(A) + ++ "-" + ++ integer_to_list(B) + ++ "-" + ++ integer_to_list(C)), + ?line ?t:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]). + +stop_node(Node) -> + ?t:stop_node(Node). + diff --git a/erts/emulator/test/statistics_SUITE.erl b/erts/emulator/test/statistics_SUITE.erl index 0392312a6f..a93dd309c1 100644 --- a/erts/emulator/test/statistics_SUITE.erl +++ b/erts/emulator/test/statistics_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -29,6 +29,7 @@ runtime_zero_diff/1, runtime_update/1, runtime_diff/1, run_queue_one/1, + scheduler_wall_time/1, reductions/1, reductions_big/1, garbage_collection/1, io/1, badarg/1]). @@ -51,8 +52,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [{group, wall_clock}, {group, runtime}, reductions, - reductions_big, {group, run_queue}, garbage_collection, - io, badarg]. + reductions_big, {group, run_queue}, scheduler_wall_time, + garbage_collection, io, badarg]. groups() -> [{wall_clock, [], @@ -266,11 +267,10 @@ run_queue_one(Config) when is_list(Config) -> run_queue_one_test(Config) when is_list(Config) -> - ?line Hog = spawn_link(?MODULE, hog, [self()]), + ?line _Hog = spawn_link(?MODULE, hog, [self()]), ?line receive - hog_started -> - Hog ! go - end, + hog_started -> ok + end, ?line receive after 100 -> ok end, % Give hog a head start. ?line case statistics(run_queue) of N when N >= 1 -> ok; @@ -280,18 +280,88 @@ run_queue_one_test(Config) when is_list(Config) -> %% CPU-bound process, going at low priority. It will always be ready %% to run. - + hog(Pid) -> ?line process_flag(priority, low), ?line Pid ! hog_started, - ?line receive - go -> hog_iter(0) + ?line Mon = erlang:monitor(process, Pid), + ?line hog_iter(0, Mon). + +hog_iter(N, Mon) when N > 0 -> + receive + {'DOWN', Mon, _, _, _} -> ok + after 0 -> + ?line hog_iter(N-1, Mon) + end; +hog_iter(0, Mon) -> + ?line hog_iter(10000, Mon). + +%%% Tests of statistics(scheduler_wall_time). + +scheduler_wall_time(doc) -> + "Tests that statistics(scheduler_wall_time) works as intended"; +scheduler_wall_time(Config) when is_list(Config) -> + %% Should return undefined if system_flag is not turned on yet + undefined = statistics(scheduler_wall_time), + %% Turn on statistics + false = erlang:system_flag(scheduler_wall_time, true), + try + Schedulers = erlang:system_info(schedulers_online), + %% Let testserver and everyone else finish their work + timer:sleep(500), + %% Empty load + EmptyLoad = get_load(), + {false, _} = {lists:any(fun(Load) -> Load > 50 end, EmptyLoad),EmptyLoad}, + MeMySelfAndI = self(), + StartHog = fun() -> + Pid = spawn(?MODULE, hog, [self()]), + receive hog_started -> MeMySelfAndI ! go end, + Pid + end, + P1 = StartHog(), + %% Max on one, the other schedulers empty (hopefully) + %% Be generous the process can jump between schedulers + %% which is ok and we don't want the test to fail for wrong reasons + _L1 = [S1Load|EmptyScheds1] = get_load(), + {true,_} = {S1Load > 50,S1Load}, + {false,_} = {lists:any(fun(Load) -> Load > 50 end, EmptyScheds1),EmptyScheds1}, + {true,_} = {lists:sum(EmptyScheds1) < 60,EmptyScheds1}, + + %% 50% load + HalfHogs = [StartHog() || _ <- lists:seq(1, (Schedulers-1) div 2)], + HalfLoad = lists:sum(get_load()) div Schedulers, + if Schedulers < 2, HalfLoad > 80 -> ok; %% Ok only one scheduler online and one hog + %% We want roughly 50% load + HalfLoad > 40, HalfLoad < 60 -> ok; + true -> exit({halfload, HalfLoad}) + end, + + %% 100% load + LastHogs = [StartHog() || _ <- lists:seq(1, Schedulers div 2)], + FullScheds = get_load(), + {false,_} = {lists:any(fun(Load) -> Load < 80 end, FullScheds),FullScheds}, + FullLoad = lists:sum(FullScheds) div Schedulers, + if FullLoad > 90 -> ok; + true -> exit({fullload, FullLoad}) + end, + + [exit(Pid, kill) || Pid <- [P1|HalfHogs++LastHogs]], + AfterLoad = get_load(), + {false,_} = {lists:any(fun(Load) -> Load > 5 end, AfterLoad),AfterLoad}, + true = erlang:system_flag(scheduler_wall_time, false) + after + erlang:system_flag(scheduler_wall_time, false) end. -hog_iter(N) when N > 0 -> - ?line hog_iter(N-1); -hog_iter(0) -> - ?line hog_iter(10000). +get_load() -> + Start = erlang:statistics(scheduler_wall_time), + timer:sleep(500), + End = erlang:statistics(scheduler_wall_time), + lists:reverse(lists:sort(load_percentage(lists:sort(Start),lists:sort(End)))). + +load_percentage([{Id, WN, TN}|Ss], [{Id, WP, TP}|Ps]) -> + [100*(WN-WP) div (TN-TP)|load_percentage(Ss, Ps)]; +load_percentage([], []) -> []. garbage_collection(doc) -> diff --git a/erts/emulator/test/system_profile_SUITE.erl b/erts/emulator/test/system_profile_SUITE.erl index 32089e8872..659e43f81d 100644 --- a/erts/emulator/test/system_profile_SUITE.erl +++ b/erts/emulator/test/system_profile_SUITE.erl @@ -27,6 +27,7 @@ system_profile_on_and_off/1, runnable_procs/1, runnable_ports/1, + dont_profile_profiler/1, scheduler/1 ]). @@ -40,7 +41,7 @@ -define(default_timeout, ?t:minutes(1)). init_per_testcase(_Case, Config) -> - ?line Dog=?t:timetrap(?default_timeout), + Dog=?t:timetrap(?default_timeout), [{watchdog, Dog}|Config]. end_per_testcase(_Case, Config) -> Dog=?config(watchdog, Config), @@ -51,7 +52,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [system_profile_on_and_off, runnable_procs, - runnable_ports, scheduler]. + runnable_ports, scheduler, dont_profile_profiler]. groups() -> []. @@ -77,31 +78,31 @@ system_profile_on_and_off(suite) -> system_profile_on_and_off(doc) -> ["Tests switching system_profiling on and off."]; system_profile_on_and_off(Config) when is_list(Config) -> - ?line Pid = start_profiler_process(), + Pid = start_profiler_process(), % Test runnable_ports on and off - ?line undefined = erlang:system_profile(Pid, [runnable_ports]), - ?line {Pid, [runnable_ports]} = erlang:system_profile(), - ?line {Pid, [runnable_ports]} = erlang:system_profile(undefined, []), + undefined = erlang:system_profile(Pid, [runnable_ports]), + {Pid, [runnable_ports]} = erlang:system_profile(), + {Pid, [runnable_ports]} = erlang:system_profile(undefined, []), % Test runnable_procs on and off - ?line undefined = erlang:system_profile(Pid, [runnable_procs]), - ?line {Pid, [runnable_procs]} = erlang:system_profile(), - ?line {Pid, [runnable_procs]} = erlang:system_profile(undefined, []), + undefined = erlang:system_profile(Pid, [runnable_procs]), + {Pid, [runnable_procs]} = erlang:system_profile(), + {Pid, [runnable_procs]} = erlang:system_profile(undefined, []), % Test scheduler on and off - ?line undefined = erlang:system_profile(Pid, [scheduler]), - ?line {Pid, [scheduler]} = erlang:system_profile(), - ?line {Pid, [scheduler]} = erlang:system_profile(undefined, []), + undefined = erlang:system_profile(Pid, [scheduler]), + {Pid, [scheduler]} = erlang:system_profile(), + {Pid, [scheduler]} = erlang:system_profile(undefined, []), % Test combined runnable_ports, runnable_procs, scheduler; on and off - ?line undefined = erlang:system_profile(Pid, [scheduler, runnable_procs, runnable_ports]), - ?line {Pid, [scheduler,runnable_procs,runnable_ports]} = erlang:system_profile(), - ?line {Pid, [scheduler,runnable_procs,runnable_ports]} = erlang:system_profile(undefined, []), + undefined = erlang:system_profile(Pid, [scheduler, runnable_procs, runnable_ports]), + {Pid, [scheduler,runnable_procs,runnable_ports]} = erlang:system_profile(), + {Pid, [scheduler,runnable_procs,runnable_ports]} = erlang:system_profile(undefined, []), % Test turned off and kill process - ?line undefined = erlang:system_profile(), - ?line exit(Pid,kill), + undefined = erlang:system_profile(), + exit(Pid,kill), ok. %% Test runnable_procs @@ -111,25 +112,25 @@ runnable_procs(suite) -> runnable_procs(doc) -> ["Tests system_profiling with runnable_procs."]; runnable_procs(Config) when is_list(Config) -> - ?line Pid = start_profiler_process(), + Pid = start_profiler_process(), % start a ring of processes % FIXME: Set #laps and #nodes in config file Nodes = 10, Laps = 10, - ?line Master = ring(Nodes), - ?line undefined = erlang:system_profile(Pid, [runnable_procs]), + Master = ring(Nodes), + undefined = erlang:system_profile(Pid, [runnable_procs]), % loop a message - ?line ok = ring_message(Master, message, Laps), - ?line Events = get_profiler_events(), - ?line kill_em_all = kill_ring(Master), - ?line erlang:system_profile(undefined, []), + ok = ring_message(Master, message, Laps), + Events = get_profiler_events(), + kill_em_all = kill_ring(Master), + erlang:system_profile(undefined, []), put(master, Master), put(laps, Laps), - ?line true = has_runnable_event(Events), + true = has_runnable_event(Events), Pids = sort_events_by_pid(Events), - ?line ok = check_events(Pids), + ok = check_events(Pids), erase(), - ?line exit(Pid,kill), + exit(Pid,kill), ok. runnable_ports(suite) -> @@ -137,21 +138,21 @@ runnable_ports(suite) -> runnable_ports(doc) -> ["Tests system_profiling with runnable_port."]; runnable_ports(Config) when is_list(Config) -> - ?line Pid = start_profiler_process(), - ?line undefined = erlang:system_profile(Pid, [runnable_ports]), - ?line EchoPid = echo(Config), + Pid = start_profiler_process(), + undefined = erlang:system_profile(Pid, [runnable_ports]), + EchoPid = echo(Config), % FIXME: Set config to number_of_echos Laps = 10, put(laps, Laps), - ?line ok = echo_message(EchoPid, Laps, message), - ?line Events = get_profiler_events(), - ?line kill_em_all = kill_echo(EchoPid), - ?line erlang:system_profile(undefined, []), - ?line true = has_runnable_event(Events), + ok = echo_message(EchoPid, Laps, message), + Events = get_profiler_events(), + kill_em_all = kill_echo(EchoPid), + erlang:system_profile(undefined, []), + true = has_runnable_event(Events), Pids = sort_events_by_pid(Events), - ?line ok = check_events(Pids), + ok = check_events(Pids), erase(), - ?line exit(Pid,kill), + exit(Pid,kill), ok. scheduler(suite) -> @@ -160,46 +161,68 @@ scheduler(doc) -> ["Tests system_profiling with scheduler."]; scheduler(Config) when is_list(Config) -> case {erlang:system_info(smp_support), erlang:system_info(schedulers_online)} of - {false,_} -> ?line {skipped, "No need for scheduler test when smp support is disabled."}; - {_, 1} -> ?line {skipped, "No need for scheduler test when only one scheduler online."}; + {false,_} -> {skipped, "No need for scheduler test when smp support is disabled."}; + {_, 1} -> {skipped, "No need for scheduler test when only one scheduler online."}; _ -> Nodes = 10, - ?line ok = check_block_system(Nodes), - ?line ok = check_multi_scheduling_block(Nodes), - ok + ok = check_block_system(Nodes), + ok = check_multi_scheduling_block(Nodes) end. +% the profiler pid should not be profiled +dont_profile_profiler(suite) -> + []; +dont_profile_profiler(doc) -> + ["Ensure system profiler process is not profiled."]; +dont_profile_profiler(Config) when is_list(Config) -> + Pid = start_profiler_process(), + + Nodes = 10, + Laps = 10, + Master = ring(Nodes), + undefined = erlang:system_profile(Pid, [runnable_procs]), + % loop a message + ok = ring_message(Master, message, Laps), + erlang:system_profile(undefined, []), + kill_em_all = kill_ring(Master), + Events = get_profiler_events(), + false = has_profiler_pid_event(Events, Pid), + + exit(Pid,kill), + ok. + + %%% Check scheduler profiling check_multi_scheduling_block(Nodes) -> - ?line Pid = start_profiler_process(), - ?line undefined = erlang:system_profile(Pid, [scheduler]), - ?line {ok, Supervisor} = start_load(Nodes), - ?line erlang:system_flag(multi_scheduling, block), - ?line erlang:system_flag(multi_scheduling, unblock), - ?line {Pid, [scheduler]} = erlang:system_profile(undefined, []), - ?line Events = get_profiler_events(), - ?line true = has_scheduler_event(Events), + Pid = start_profiler_process(), + undefined = erlang:system_profile(Pid, [scheduler]), + {ok, Supervisor} = start_load(Nodes), + erlang:system_flag(multi_scheduling, block), + erlang:system_flag(multi_scheduling, unblock), + {Pid, [scheduler]} = erlang:system_profile(undefined, []), + Events = get_profiler_events(), + true = has_scheduler_event(Events), stop_load(Supervisor), - ?line exit(Pid,kill), + exit(Pid,kill), erase(), ok. check_block_system(Nodes) -> - ?line Dummy = spawn(?MODULE, profiler_process, [[]]), - ?line Pid = start_profiler_process(), - ?line undefined = erlang:system_profile(Pid, [scheduler]), - ?line {ok, Supervisor} = start_load(Nodes), + Dummy = spawn(?MODULE, profiler_process, [[]]), + Pid = start_profiler_process(), + undefined = erlang:system_profile(Pid, [scheduler]), + {ok, Supervisor} = start_load(Nodes), % FIXME: remove wait !! wait(300), - ?line undefined = erlang:system_monitor(Dummy, [busy_port]), - ?line {Dummy, [busy_port]} = erlang:system_monitor(undefined, []), - ?line {Pid, [scheduler]} = erlang:system_profile(undefined, []), - ?line Events = get_profiler_events(), - ?line true = has_scheduler_event(Events), + undefined = erlang:system_monitor(Dummy, [busy_port]), + {Dummy, [busy_port]} = erlang:system_monitor(undefined, []), + {Pid, [scheduler]} = erlang:system_profile(undefined, []), + Events = get_profiler_events(), + true = has_scheduler_event(Events), stop_load(Supervisor), - ?line exit(Pid,kill), - ?line exit(Dummy,kill), + exit(Pid,kill), + exit(Dummy,kill), erase(), ok. @@ -211,17 +234,17 @@ check_events([Pid | Pids]) -> Laps = get(laps), CheckPids = get(pids), {Events, N} = get_pid_events(Pid), - ?line ok = check_event_flow(Events), - ?line ok = check_event_ts(Events), + ok = check_event_flow(Events), + ok = check_event_ts(Events), IsMember = lists:member(Pid, CheckPids), case Pid of Master -> io:format("Expected ~p and got ~p profile events from ~p: ok~n", [Laps*2+2, N, Pid]), - ?line N = Laps*2 + 2, + N = Laps*2 + 2, check_events(Pids); Pid when IsMember == true -> io:format("Expected ~p and got ~p profile events from ~p: ok~n", [Laps*2, N, Pid]), - ?line N = Laps*2, + N = Laps*2, check_events(Pids); Pid -> check_events(Pids) @@ -448,6 +471,12 @@ has_runnable_event(Events) -> end end, Events). +has_profiler_pid_event([], _) -> false; +has_profiler_pid_event([{profile, Pid, _Activity, _MFA, _TS}|Events], Pid) -> true; +has_profiler_pid_event([_|Events], Pid) -> + has_profiler_pid_event(Events, Pid). + + wait(Time) -> receive after Time -> ok end. %%% diff --git a/erts/emulator/test/trace_port_SUITE.erl b/erts/emulator/test/trace_port_SUITE.erl index 0026da4979..b0ce6f81db 100644 --- a/erts/emulator/test/trace_port_SUITE.erl +++ b/erts/emulator/test/trace_port_SUITE.erl @@ -77,7 +77,8 @@ end_per_testcase(_Func, Config) -> call_trace(doc) -> "Test sending call trace messages to a port."; call_trace(Config) when is_list(Config) -> - case test_server:is_native(?MODULE) of + case test_server:is_native(?MODULE) orelse + test_server:is_native(lists) of true -> {skip,"Native code"}; false -> @@ -128,7 +129,8 @@ bs_sum_c(<<>>, Acc) -> Acc. return_trace(doc) -> "Test the new return trace."; return_trace(Config) when is_list(Config) -> - case test_server:is_native(?MODULE) of + case test_server:is_native(?MODULE) orelse + test_server:is_native(lists) of true -> {skip,"Native code"}; false -> diff --git a/erts/emulator/zlib/Makefile b/erts/emulator/zlib/Makefile deleted file mode 100644 index def8e1aa47..0000000000 --- a/erts/emulator/zlib/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2009. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# -# Invoke with GNU make or clearmake -C gnu. -# - -include $(ERL_TOP)/make/run_make.mk diff --git a/erts/emulator/zlib/Makefile.in b/erts/emulator/zlib/Makefile.in deleted file mode 100644 index b44a87551d..0000000000 --- a/erts/emulator/zlib/Makefile.in +++ /dev/null @@ -1,102 +0,0 @@ -# Makefile for zlib -# Copyright (C) 1995-1996 Jean-loup Gailly. -# For conditions of distribution and use, see copyright notice in zlib.h - -# %ExternalCopyright% - -# To compile and test, type: -# ./configure; make test -# The call of configure is optional if you don't have special requirements - -# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type: -# make install -# To install in $HOME instead of /usr/local, use: -# make install prefix=$HOME - -ARFLAGS = rc -CFLAGS = $(subst -O2, -O3, @CFLAGS@ @DEFS@ @EMU_THR_DEFS@) -#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 -#CFLAGS=-g -DDEBUG -#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ -# -Wstrict-prototypes -Wmissing-prototypes - -VER=1.0.4 - -O = adler32.o compress.o crc32.o uncompr.o deflate.o trees.o \ - zutil.o inflate.o inftrees.o inffast.o -OBJS = $(O:%=$(OBJDIR)/%) - - -#### Begin OTP targets - -include $(ERL_TOP)/make/target.mk - -ifeq ($(TYPE),gcov) -CFLAGS = -O0 -fprofile-arcs -ftest-coverage @DEBUG_CFLAGS@ @DEFS@ @EMU_THR_DEFS@ -else # gcov -ifeq ($(TYPE),debug) -CFLAGS = @DEBUG_CFLAGS@ @DEFS@ @EMU_THR_DEFS@ -endif # debug -endif # gcov - -# On windows we *need* a separate zlib during debug build -OBJDIR= $(ERL_TOP)/erts/emulator/zlib/obj/$(TARGET)/$(TYPE) - -include $(ERL_TOP)/make/$(TARGET)/otp.mk - -ifeq ($(TARGET), win32) -LIBRARY=$(OBJDIR)/z.lib -else -LIBRARY=$(OBJDIR)/libz.a -endif - -all: $(LIBRARY) - -# ---------------------------------------------------- -# Release Target -# ---------------------------------------------------- -include $(ERL_TOP)/make/otp_release_targets.mk - -release_spec: opt - -tests release_tests: - -docs release_docs release_docs_spec: - -clean: - rm -f $(OBJS) $(OBJDIR)/libz.a - -#### end OTP targets - -ifeq ($(TARGET), win32) -$(LIBRARY): $(OBJS) - $(AR) -out:$@ $(OBJS) -else -$(LIBRARY): $(OBJS) - $(AR) $(ARFLAGS) $@ $(OBJS) - -@ ($(RANLIB) $@ || true) 2>/dev/null -endif - -$(OBJDIR)/%.o: %.c - $(CC) -c $(CFLAGS) -o $@ $< - -# DO NOT DELETE THIS LINE -- make depend depends on it. - -adler32.o: zlib.h zconf.h -compress.o: zlib.h zconf.h -crc32.o: zlib.h zconf.h -deflate.o: deflate.h zutil.h zlib.h zconf.h -example.o: zlib.h zconf.h -gzio.o: zutil.h zlib.h zconf.h -infblock.o: infblock.h inftrees.h infcodes.h infutil.h zutil.h zlib.h zconf.h -infcodes.o: zutil.h zlib.h zconf.h -infcodes.o: inftrees.h infblock.h infcodes.h infutil.h inffast.h -inffast.o: zutil.h zlib.h zconf.h inftrees.h -inffast.o: infblock.h infcodes.h infutil.h inffast.h -inflate.o: zutil.h zlib.h zconf.h infblock.h -inftrees.o: zutil.h zlib.h zconf.h inftrees.h -infutil.o: zutil.h zlib.h zconf.h infblock.h inftrees.h infcodes.h infutil.h -minigzip.o: zlib.h zconf.h -trees.o: deflate.h zutil.h zlib.h zconf.h -uncompr.o: zlib.h zconf.h -zutil.o: zutil.h zlib.h zconf.h diff --git a/erts/emulator/zlib/zlib.mk b/erts/emulator/zlib/zlib.mk new file mode 100644 index 0000000000..fa1f159fae --- /dev/null +++ b/erts/emulator/zlib/zlib.mk @@ -0,0 +1,74 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode +# ---------------------------------------------------- +# Make include file for zlib +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2011-2012. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# ---------------------------------------------------- +# Copyright for zlib itself see copyright notice in zlib.h + +ZLIB_FILES = \ + adler32 \ + compress \ + crc32 \ + uncompr \ + deflate \ + trees \ + zutil \ + inflate \ + inftrees \ + inffast + +# On windows we *need* a separate zlib during debug build +ZLIB_OBJDIR = $(ERL_TOP)/erts/emulator/zlib/obj/$(TARGET)/$(TYPE) + +ZLIB_OBJS = $(ZLIB_FILES:%=$(ZLIB_OBJDIR)/%.o) +ZLIB_SRC = $(ZLIB_FILES:%=zlib/%.c) + +ifeq ($(TARGET), win32) +ZLIB_LIBRARY = $(ZLIB_OBJDIR)/z.lib +else +ZLIB_LIBRARY = $(ZLIB_OBJDIR)/libz.a +endif + + +ifeq ($(TYPE),gcov) +ZLIB_CFLAGS = -O0 -fprofile-arcs -ftest-coverage $(DEBUG_CFLAGS) $(DEFS) $(THR_DEFS) +else # gcov +ifeq ($(TYPE),debug) +ZLIB_CFLAGS = $(DEBUG_CFLAGS) $(DEFS) $(THR_DEFS) +else # debug +ZLIB_CFLAGS = $(subst -O2, -O3, $(CONFIGURE_CFLAGS) $(DEFS) $(THR_DEFS)) +#ZLIB_CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7 +#ZLIB_CFLAGS=-g -DDEBUG +#ZLIB_CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \ +# -Wstrict-prototypes -Wmissing-prototypes +endif # debug +endif # gcov + +ifeq ($(TARGET), win32) +$(ZLIB_LIBRARY): $(ZLIB_OBJS) + $(AR) -out:$@ $(ZLIB_OBJS) +else +$(ZLIB_LIBRARY): $(ZLIB_OBJS) + $(AR) $(ARFLAGS) $@ $(ZLIB_OBJS) + -@ ($(RANLIB) $@ || true) 2>/dev/null +endif + +$(ZLIB_OBJDIR)/%.o: zlib/%.c + $(CC) -c $(ZLIB_CFLAGS) -o $@ $< diff --git a/erts/epmd/src/Makefile.in b/erts/epmd/src/Makefile.in index 2f5296a5e8..5767edc346 100644 --- a/erts/epmd/src/Makefile.in +++ b/erts/epmd/src/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1998-2010. All Rights Reserved. +# Copyright Ericsson AB 1998-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -24,6 +24,7 @@ PURIFY = TYPEMARKER = .debug TYPE_FLAGS = -DDEBUG @DEBUG_FLAGS@ else + ifeq ($(TYPE),purify) PURIFY = purify TYPEMARKER = @@ -33,6 +34,8 @@ else TYPE_FLAGS = -O2 -DPURIFY endif else + +override TYPE = opt PURIFY = TYPEMARKER = ifeq ($(findstring ose,$(TARGET)),ose) @@ -65,6 +68,8 @@ ERTS_INTERNAL_LIBS=-L../../lib/internal/$(TARGET) -lerts_internal$(ERTS_LIB_TYPE endif endif +ERTS_LIB = $(ERL_TOP)/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE + CC = @CC@ WFLAGS = @WFLAGS@ CFLAGS = @CFLAGS@ @DEFS@ $(TYPE_FLAGS) $(WFLAGS) $(ERTS_INCL) @@ -106,7 +111,7 @@ EPMD_OBJS = $(OBJDIR)/epmd.o \ #--------------------------------- -all: erts_lib $(BINDIR)/$(EPMD) +all: $(BINDIR)/$(EPMD) docs: @@ -122,13 +127,13 @@ clean: # Objects & executables # -$(BINDIR)/$(EPMD): $(EPMD_OBJS) +$(BINDIR)/$(EPMD): $(EPMD_OBJS) $(ERTS_LIB) $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(EPMD_OBJS) $(LIBS) $(OBJDIR)/%.o: %.c epmd.h epmd_int.h $(CC) $(CFLAGS) $(EPMD_FLAGS) -o $@ -c $< -erts_lib: +$(ERTS_LIB): cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE) include $(ERL_TOP)/make/otp_release_targets.mk @@ -139,4 +144,3 @@ release_spec: all release_docs_spec: - diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in index c3c242b87c..28c5e5ccad 100644 --- a/erts/etc/common/Makefile.in +++ b/erts/etc/common/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2011. All Rights Reserved. +# Copyright Ericsson AB 1996-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -29,6 +29,7 @@ PURIFY = TYPEMARKER = .debug TYPE_FLAGS = -DDEBUG @DEBUG_FLAGS@ else + ifeq ($(TYPE),purify) PURIFY = purify TYPEMARKER = @@ -38,6 +39,8 @@ else TYPE_FLAGS = -g -O2 -DPURIFY endif else + +override TYPE=opt PURIFY = TYPEMARKER = ERTS_LIB_TYPEMARKER= @@ -101,6 +104,8 @@ else ERTS_INTERNAL_LIBS=-L../../lib/internal/$(TARGET) -lerts_internal$(ERTS_LIB_TYPEMARKER) @ERTS_INTERNAL_X_LIBS@ -lm endif +ERTS_LIB = $(ERL_TOP)/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE + # ---------------------------------------------------- # Release directory specification # ---------------------------------------------------- @@ -161,9 +166,8 @@ ERLSRV_OBJECTS= \ $(OBJDIR)/erlsrv_main.o \ $(OBJDIR)/erlsrv_util.o \ $(OBJDIR)/erlsrv_logmess.res -MC_OUTPUTS= \ - $(OBJDIR)/erlsrv_logmess.h $(OBJDIR)/erlsrv_logmess.rc - MT_FLAG="-MT" +MC_OUTPUTS=$(OBJDIR)/erlsrv_logmess.h $(OBJDIR)/erlsrv_logmess.rc +MT_FLAG="-MT" else ERLRES_OBJ=erl_res.o ERLSRV_OBJECTS= \ @@ -173,9 +177,8 @@ ERLSRV_OBJECTS= \ $(OBJDIR)/erlsrv_main.o \ $(OBJDIR)/erlsrv_util.o \ $(OBJDIR)/erlsrv_logmess.o -MC_OUTPUTS= \ - $(OBJDIR)/erlsrv_logmess.h $(OBJDIR)/erlsrv_logmess.res - MT_FLAG="-MD" +MC_OUTPUTS=$(OBJDIR)/erlsrv_logmess.h $(OBJDIR)/erlsrv_logmess.res +MT_FLAG="-MD" endif INET_GETHOST = $(BINDIR)/inet_gethost.exe INSTALL_EMBEDDED_PROGS += $(BINDIR)/typer.exe $(BINDIR)/dialyzer.exe $(BINDIR)/erlc.exe $(BINDIR)/start_erl.exe $(BINDIR)/escript.exe $(BINDIR)/ct_run.exe @@ -232,14 +235,17 @@ endif endif endif -etc: erts_lib $(ENTRY_OBJ) $(INSTALL_PROGS) $(INSTALL_LIBS) $(TEXTFILES) $(INSTALL_TOP_BIN) +.PHONY: etc +etc: $(ENTRY_OBJ) $(INSTALL_PROGS) $(INSTALL_LIBS) $(TEXTFILES) $(INSTALL_TOP_BIN) # erlexec needs the erts_internal library... -erts_lib: +$(ERTS_LIB): cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE) +.PHONY: docs docs: +.PHONY: clean clean: ifneq ($(INSTALL_PROGS),) rm -f $(INSTALL_PROGS) @@ -278,85 +284,9 @@ endif rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/vxcall.o rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/erl.o rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/werl.o + rm -f $(TEXTFILES) rm -f *~ core -# -# Objects & executables -# -#$(OBJDIR)/%.o: %.c -# $(CC) $(CFLAGS) -o $@ -c $< -# -#$(OBJDIR)/%.o: ../unix/%.c -# $(CC) $(CFLAGS) -o $@ -c $< -# -#$(BINDIR)/%: $(OBJDIR)/%.o -# $(PURIFY) $(LD) $(LDFLAGS) -o $@ $< $(LIBS) - -$(OBJDIR)/inet_gethost.o: inet_gethost.c - $(CC) $(CFLAGS) -o $@ -c inet_gethost.c - -$(BINDIR)/inet_gethost@EXEEXT@: $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) - $(PURIFY) $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(LIBS) $(ERTS_INTERNAL_LIBS) - -$(BINDIR)/run_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o - $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(LIBS) - -$(OBJDIR)/run_erl.o: ../unix/run_erl.c - $(CC) $(CFLAGS) -o $@ -c ../unix/run_erl.c - -$(BINDIR)/to_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o - $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o - -$(OBJDIR)/to_erl.o: ../unix/to_erl.c - $(CC) $(CFLAGS) -o $@ -c ../unix/to_erl.c - -$(BINDIR)/dyn_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o - $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o - -$(OBJDIR)/dyn_erl.o: ../unix/dyn_erl.c - $(CC) $(CFLAGS) -o $@ -c ../unix/dyn_erl.c - -$(OBJDIR)/safe_string.o: ../unix/safe_string.c - $(CC) $(CFLAGS) -o $@ -c ../unix/safe_string.c - -ifneq ($(TARGET),win32) -$(BINDIR)/$(ERLEXEC): $(OBJDIR)/$(ERLEXEC).o - $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/$(ERLEXEC).o $(ERTS_INTERNAL_LIBS) - -$(OBJDIR)/$(ERLEXEC).o: $(ERLEXECDIR)/$(ERLEXEC).c - $(CC) -I$(EMUDIR) $(CFLAGS) -o $@ -c $(ERLEXECDIR)/$(ERLEXEC).c -endif -$(BINDIR)/erlc@EXEEXT@: $(OBJDIR)/erlc.o - $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/erlc.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) - -$(OBJDIR)/erlc.o: erlc.c - $(CC) $(CFLAGS) -o $@ -c erlc.c - -$(BINDIR)/dialyzer@EXEEXT@: $(OBJDIR)/dialyzer.o - $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/dialyzer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) - -$(OBJDIR)/dialyzer.o: dialyzer.c - $(CC) $(CFLAGS) -o $@ -c dialyzer.c - -$(BINDIR)/typer@EXEEXT@: $(OBJDIR)/typer.o - $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/typer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) - -$(OBJDIR)/typer.o: typer.c - $(CC) $(CFLAGS) -o $@ -c typer.c - -$(BINDIR)/escript@EXEEXT@: $(OBJDIR)/escript.o - $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/escript.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) - -$(OBJDIR)/escript.o: escript.c - $(CC) $(CFLAGS) -o $@ -c escript.c - -$(BINDIR)/ct_run@EXEEXT@: $(OBJDIR)/ct_run.o - $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/ct_run.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) - -$(OBJDIR)/ct_run.o: ct_run.c - $(CC) $(CFLAGS) -o $@ -c ct_run.c - - #------------------------------------------------------------------------ # Windows specific targets # The windows platform is quite different from the others. erl/werl are small C programs @@ -367,7 +297,7 @@ $(OBJDIR)/ct_run.o: ct_run.c ifeq ($(TARGET),win32) -$(BINDIR)/$(ERLEXEC): $(OBJDIR)/erlexec.o $(OBJDIR)/win_erlexec.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) +$(BINDIR)/$(ERLEXEC): $(OBJDIR)/erlexec.o $(OBJDIR)/win_erlexec.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) $(ERTS_LIB) $(LD) -dll $(LDFLAGS) -o $@ $(OBJDIR)/erlexec.o $(OBJDIR)/win_erlexec.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) $(ERTS_INTERNAL_LIBS) $(BINDIR)/erl@EXEEXT@: $(OBJDIR)/erl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ) @@ -382,58 +312,75 @@ $(BINDIR)/start_erl@EXEEXT@: $(OBJDIR)/start_erl.o $(BINDIR)/Install@EXEEXT@: $(OBJDIR)/Install.o $(OBJDIR)/init_file.o $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/Install.o $(OBJDIR)/init_file.o +# The service expects to be compiled with $(MT_FLAG) flag. $(BINDIR)/erlsrv@EXEEXT@: $(ERLSRV_OBJECTS) $(LD) $(LDFLAGS) $(MT_FLAG) -o $@ $(ERLSRV_OBJECTS) -# The service expects to be compiled with $(MT_FLAG) flag. - -$(OBJDIR)/%.o: $(WINETC)/erlsrv/%.c $(ERLSRV_HEADERS) - $(CC) $(CFLAGS) $(MT_FLAG) -o $@ -c $< - -$(OBJDIR)/erlsrv_util.o: $(WINETC)/erlsrv/erlsrv_util.c $(ERLSRV_HEADERS) \ -$(OBJDIR)/erlsrv_logmess.h - $(CC) $(CFLAGS) -I$(OBJDIR) $(MT_FLAG) -o $@ -c $< +# To fix a spooky parallel make build problem on Windows there are some +# false dependencies on the $(MC), $(RC) and .o rules. The theory behind +# is that the $(MC) and/or $(RC) compilers seems to temporarily create and +# destroy a toplevel file vc100.pdb that simultaneous ordinary compilations +# (that have been by flags explicitly ordered to not use .pdb files) +# gets upset when that file vanishes from under their feet. +# +# The false dependencies are targeted to make make (pun intended) run +# the $(MC) and $(RC) compilations to completion before all others. + +LOGMESS_GENERATED = $(OBJDIR)/LOGMESS-GENERATED +$(MC_OUTPUTS): $(LOGMESS_GENERATED) +$(LOGMESS_GENERATED): $(WINETC)/erlsrv/erlsrv_logmess.mc + $(MC) -o $(OBJDIR) $(WINETC)/erlsrv/erlsrv_logmess.mc && \ + echo $? >$(LOGMESS_GENERATED) + +$(OBJDIR)/$(ERLRES_OBJ): $(WINETC)/erl.rc $(WINETC)/erlang.ico \ + $(WINETC)/erl_icon.ico $(WINETC)/hrl_icon.ico \ + $(WINETC)/beam_icon.ico $(LOGMESS_GENERATED) + $(RC) -o $@ -I$(WINETC) $(WINETC)/erl.rc ifeq ($(USING_VC), yes) -$(OBJDIR)/erlsrv_logmess.res: $(OBJDIR)/erlsrv_logmess.rc +RC_GENERATED = $(OBJDIR)/erlsrv_logmess.res +$(RC_GENERATED): $(OBJDIR)/erlsrv_logmess.rc $(OBJDIR)/$(ERLRES_OBJ) $(RC) -o $(OBJDIR)/erlsrv_logmess.res -I$(OBJDIR) $(OBJDIR)/erlsrv_logmess.rc else -$(OBJDIR)/erlsrv_logmess.o: $(OBJDIR)/erlsrv_logmess.res +RC_GENERATED = $(OBJDIR)/erlsrv_logmess.o +$(RC_GENERATED): $(OBJDIR)/erlsrv_logmess.res $(OBJDIR)/$(ERLRES_OBJ) $(RC) -o $(OBJDIR)/erlsrv_logmess.o -I$(OBJDIR) $(OBJDIR)/erlsrv_logmess.res endif -$(MC_OUTPUTS): $(WINETC)/erlsrv/erlsrv_logmess.mc - $(MC) -o $(OBJDIR) $(WINETC)/erlsrv/erlsrv_logmess.mc +# The service expects to be compiled with $(MT_FLAG) flag. +$(OBJDIR)/%.o: $(WINETC)/erlsrv/%.c $(ERLSRV_HEADERS) $(RC_GENERATED) + $(CC) $(CFLAGS) $(MT_FLAG) -o $@ -c $< -$(OBJDIR)/werl.o: $(WINETC)/erl.c +$(OBJDIR)/erlsrv_util.o: $(WINETC)/erlsrv/erlsrv_util.c $(ERLSRV_HEADERS) \ + $(OBJDIR)/erlsrv_logmess.h $(RC_GENERATED) + $(CC) $(CFLAGS) -I$(OBJDIR) $(MT_FLAG) -o $@ -c $< + +$(OBJDIR)/werl.o: $(WINETC)/erl.c $(WINETC)/init_file.h $(RC_GENERATED) $(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \ -DWIN32_WERL -o $@ -c $(WINETC)/erl.c -$(OBJDIR)/erl.o: $(WINETC)/erl.c +$(OBJDIR)/erl.o: $(WINETC)/erl.c $(WINETC)/init_file.h $(RC_GENERATED) $(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \ -o $@ -c $(WINETC)/erl.c -$(OBJDIR)/erlexec.o: $(ERLEXECDIR)/erlexec.c +$(OBJDIR)/erlexec.o: $(ERLEXECDIR)/erlexec.c $(RC_GENERATED) $(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \ -o $@ -c $(ERLEXECDIR)/erlexec.c -$(OBJDIR)/win_erlexec.o: $(WINETC)/win_erlexec.c +$(OBJDIR)/win_erlexec.o: $(WINETC)/win_erlexec.c $(RC_GENERATED) $(CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \ -o $@ -c $(WINETC)/win_erlexec.c -$(OBJDIR)/init_file.o: $(WINETC)/init_file.c $(WINETC)/init_file.h +$(OBJDIR)/init_file.o: $(WINETC)/init_file.c $(WINETC)/init_file.h $(RC_GENERATED) $(CC) $(CFLAGS) -o $@ -c $(WINETC)/init_file.c -$(OBJDIR)/Install.o: $(WINETC)/Install.c $(WINETC)/init_file.h +$(OBJDIR)/Install.o: $(WINETC)/Install.c $(WINETC)/init_file.h $(RC_GENERATED) $(CC) $(CFLAGS) -o $@ -c $(WINETC)/Install.c -$(OBJDIR)/$(ERLRES_OBJ): $(WINETC)/erl.rc $(WINETC)/erlang.ico $(WINETC)/erl_icon.ico $(WINETC)/hrl_icon.ico $(WINETC)/beam_icon.ico - $(RC) -o $@ -I$(WINETC) $(WINETC)/erl.rc - -$(OBJDIR)/start_erl.o: $(WINETC)/start_erl.c +$(OBJDIR)/start_erl.o: $(WINETC)/start_erl.c $(RC_GENERATED) $(CC) $(CFLAGS) -o $@ -c $(WINETC)/start_erl.c -$(ENTRY_OBJ): $(ENTRY_SRC) +$(ENTRY_OBJ): $(ENTRY_SRC) $(RC_GENERATED) $(CC) $(CFLAGS) -o $@ -c $(ENTRY_SRC) Install.ini: ../$(TARGET)/Install.src ../../vsn.mk $(TARGET)/Makefile @@ -442,6 +389,8 @@ Install.ini: ../$(TARGET)/Install.src ../../vsn.mk $(TARGET)/Makefile ../$(TARGET)/Install.src > Install.ini +else +RC_GENERATED = endif #--------------------------------------------------------- # End of windows specific targets. @@ -469,7 +418,7 @@ $(BINDIR)/heart@EXEEXT@: $(OBJDIR)/heart.o $(ENTRY_OBJ) $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/heart.o \ $(ENTRY_OBJ) $(WINDSOCK) -$(OBJDIR)/heart.o: heart.c +$(OBJDIR)/heart.o: heart.c $(RC_GENERATED) $(CC) $(CFLAGS) -o $@ -c heart.c endif @@ -497,6 +446,84 @@ $(OBJDIR)/vxcall.o: $(VXETC)/vxcall.c +# +# Objects & executables +# +#$(OBJDIR)/%.o: %.c +# $(CC) $(CFLAGS) -o $@ -c $< +# +#$(OBJDIR)/%.o: ../unix/%.c +# $(CC) $(CFLAGS) -o $@ -c $< +# +#$(BINDIR)/%: $(OBJDIR)/%.o +# $(PURIFY) $(LD) $(LDFLAGS) -o $@ $< $(LIBS) + +$(OBJDIR)/inet_gethost.o: inet_gethost.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c inet_gethost.c + +$(BINDIR)/inet_gethost@EXEEXT@: $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(LIBS) $(ERTS_INTERNAL_LIBS) + +$(BINDIR)/run_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o + $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(LIBS) + +$(OBJDIR)/run_erl.o: ../unix/run_erl.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c ../unix/run_erl.c + +$(BINDIR)/to_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o + $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o + +$(OBJDIR)/to_erl.o: ../unix/to_erl.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c ../unix/to_erl.c + +$(BINDIR)/dyn_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o + $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o + +$(OBJDIR)/dyn_erl.o: ../unix/dyn_erl.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c ../unix/dyn_erl.c + +$(OBJDIR)/safe_string.o: ../unix/safe_string.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c ../unix/safe_string.c + +ifneq ($(TARGET),win32) +$(BINDIR)/$(ERLEXEC): $(OBJDIR)/$(ERLEXEC).o $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/$(ERLEXEC).o $(ERTS_INTERNAL_LIBS) + +$(OBJDIR)/$(ERLEXEC).o: $(ERLEXECDIR)/$(ERLEXEC).c $(RC_GENERATED) + $(CC) -I$(EMUDIR) $(CFLAGS) -o $@ -c $(ERLEXECDIR)/$(ERLEXEC).c +endif +$(BINDIR)/erlc@EXEEXT@: $(OBJDIR)/erlc.o $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/erlc.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) + +$(OBJDIR)/erlc.o: erlc.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c erlc.c + +$(BINDIR)/dialyzer@EXEEXT@: $(OBJDIR)/dialyzer.o $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/dialyzer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) + +$(OBJDIR)/dialyzer.o: dialyzer.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c dialyzer.c + +$(BINDIR)/typer@EXEEXT@: $(OBJDIR)/typer.o $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/typer.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) + +$(OBJDIR)/typer.o: typer.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c typer.c + +$(BINDIR)/escript@EXEEXT@: $(OBJDIR)/escript.o $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/escript.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) + +$(OBJDIR)/escript.o: escript.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c escript.c + +$(BINDIR)/ct_run@EXEEXT@: $(OBJDIR)/ct_run.o $(ERTS_LIB) + $(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/ct_run.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS) + +$(OBJDIR)/ct_run.o: ct_run.c $(RC_GENERATED) + $(CC) $(CFLAGS) -o $@ -c ct_run.c + + + Install: ../unix/Install.src ../../vsn.mk $(TARGET)/Makefile sed -e 's;%I_VSN%;$(VSN);' \ -e 's;%EMULATOR%;$(EMULATOR);' \ @@ -515,6 +542,7 @@ erl.src: ../unix/erl.src.src ../../vsn.mk $(TARGET)/Makefile # ---------------------------------------------------- include $(ERL_TOP)/make/otp_release_targets.mk +.PHONY: release_spec release_spec: etc ifneq ($(INSTALL_OBJS),) $(INSTALL_DIR) $(RELEASE_PATH)/erts-$(VSN)/obj @@ -561,9 +589,5 @@ ifneq ($(INSTALL_INCLUDES),) $(INSTALL_DATA) $(INSTALL_INCLUDES) $(RELEASE_PATH)/erts-$(VSN)/include endif +.PHONY: release_docs_spec release_docs_spec: - - - - - diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c index 7a5746e630..fae4d870cc 100644 --- a/erts/etc/common/heart.c +++ b/erts/etc/common/heart.c @@ -685,14 +685,16 @@ do_terminate(reason) print_error("Would reboot. Terminating."); else { kill_old_erlang(); - system(command); + /* suppress gcc warning with 'if' */ + if(system(command)); print_error("Executed \"%s\". Terminating.",command); } free_env_val(command); } else { kill_old_erlang(); - system((char*)&cmd[0]); + /* suppress gcc warning with 'if' */ + if(system((char*)&cmd[0])); print_error("Executed \"%s\". Terminating.",cmd); } } diff --git a/erts/etc/common/inet_gethost.c b/erts/etc/common/inet_gethost.c index 77bfd5e2bc..d25d2910b4 100644 --- a/erts/etc/common/inet_gethost.c +++ b/erts/etc/common/inet_gethost.c @@ -1141,14 +1141,12 @@ static Worker *pick_worker(void) static Worker *pick_worker_greedy(AddrByte *domainbuff) { int i; - int ql = 0; int found = -1; for (i=0; i < num_busy_workers; ++i) { if (domaineq(busy_workers[i].domain, domainbuff)) { if ((found < 0) || (busy_workers[i].que_size < busy_workers[found].que_size)) { found = i; - ql = busy_workers[i].que_size; } } } @@ -1945,12 +1943,14 @@ static int worker_loop(void) } m = NULL; #else - write(1, reply, data_size); /* No signals expected */ + /* expect no signals */ + if (write(1, reply, data_size) < 0) + goto fail; #endif } /* for (;;) */ -#ifdef WIN32 fail: +#ifdef WIN32 if (m != NULL) { FREE(m); } @@ -1959,8 +1959,8 @@ static int worker_loop(void) if (reply) { FREE(reply); } - return 1; #endif + return 1; } static int map_netdb_error(int netdb_code) @@ -2561,7 +2561,8 @@ static void debugf(char *format, ...) WriteFile(debug_console_allocated,buff,strlen(buff),&res,NULL); } #else - write(2,buff,strlen(buff)); + /* suppress warning with 'if' */ + if(write(2,buff,strlen(buff))); #endif va_end(ap); } @@ -2583,7 +2584,8 @@ static void warning(char *format, ...) WriteFile(GetStdHandle(STD_ERROR_HANDLE),buff,strlen(buff),&res,NULL); } #else - write(2,buff,strlen(buff)); + /* suppress warning with 'if' */ + if(write(2,buff,strlen(buff))); #endif va_end(ap); } @@ -2605,7 +2607,8 @@ static void fatal(char *format, ...) WriteFile(GetStdHandle(STD_ERROR_HANDLE),buff,strlen(buff),&res,NULL); } #else - write(2,buff,strlen(buff)); + /* suppress warning with 'if' */ + if(write(2,buff,strlen(buff))); #endif va_end(ap); #ifndef WIN32 diff --git a/erts/etc/unix/to_erl.c b/erts/etc/unix/to_erl.c index 11fa3ff4cc..67274e67ed 100644 --- a/erts/etc/unix/to_erl.c +++ b/erts/etc/unix/to_erl.c @@ -352,7 +352,10 @@ int main(int argc, char **argv) * to trigger the version handshaking between to_erl and run_erl * at the start of every new to_erl-session. */ - write(wfd, "\022", 1); + + if (write(wfd, "\022", 1) < 0) { + fprintf(stderr, "Error in writing ^R to FIFO.\n"); + } /* * read and write @@ -412,7 +415,7 @@ int main(int argc, char **argv) if (len) { #ifdef DEBUG - write(1, buf, len); + if(write(1, buf, len)); #endif if (write_all(wfd, buf, len) != len) { fprintf(stderr, "Error in writing to FIFO.\n"); diff --git a/erts/lib_src/Makefile.in b/erts/lib_src/Makefile.in index 54ee7410fd..ea80e74100 100644 --- a/erts/lib_src/Makefile.in +++ b/erts/lib_src/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2004-2011. All Rights Reserved. +# Copyright Ericsson AB 2004-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -318,10 +318,14 @@ ETHREAD_LIB= endif +_create_dirs := $(shell mkdir -p $(CREATE_DIRS)) # # Everything to build # -all: $(CREATE_DIRS) $(ETHREAD_LIB) $(ERTS_LIBS) $(ERTS_INTERNAL_LIBS) +.PHONY: all +all: $(OBJ_DIR)/MADE + +$(OBJ_DIR)/MADE: $(ETHREAD_LIB) $(ERTS_LIBS) $(ERTS_INTERNAL_LIBS) ifeq ($(OMIT_OMIT_FP),yes) @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' @@ -331,6 +335,8 @@ ifeq ($(OMIT_OMIT_FP),yes) @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' @echo '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' endif + echo $? > $(OBJ_DIR)/MADE + # # The libs ... # @@ -428,13 +434,6 @@ $(MTd_OBJ_DIR)/%.o: $(ETHR_THR_LIB_BASE_DIR)/%.c $(CC) $(THR_DEFS) $(CFLAGS) -MTd $(INCLUDES) -c $< -o $@ # -# Create directories -# - -$(CREATE_DIRS): - $(MKDIR) -p $@ - -# # Install # @@ -471,6 +470,7 @@ INTERNAL_RELEASE_LIBS= \ $(ETHREAD_LIB) \ $(ERTS_INTERNAL_LIBS) +.PHONY: release_spec release_spec: all ifneq ($(strip $(RELEASE_INCLUDES)),) $(INSTALL_DIR) $(RELSYSDIR)/include @@ -500,19 +500,20 @@ ifneq ($(strip $(INTERNAL_RELEASE_LIBS)),) $(INSTALL_DATA) $(INTERNAL_RELEASE_LIBS) $(RELSYSDIR)/lib/internal endif +.PHONY: docs docs: +.PHONY: release_docs_spec release_docs_spec: - # # Cleanup # +.PHONY: clean clean: $(RM) -rf ../lib/internal/$(TARGET)/* $(RM) -rf ../lib/$(TARGET)/* $(RM) -rf obj/$(TARGET)/* - $(RM) -f $(TARGET)/depend.mk # # Make dependencies @@ -554,9 +555,11 @@ SED_MDd_DEPEND=sed '$(SED_PREFIX)$(SED_REPL_MDd_O);$(SED_REPL_TT_DIR);$(SED_REPL SED_MT_DEPEND=sed '$(SED_PREFIX)$(SED_REPL_MT_O);$(SED_REPL_TT_DIR);$(SED_REPL_TARGET)' SED_MTd_DEPEND=sed '$(SED_PREFIX)$(SED_REPL_MTd_O);$(SED_REPL_TT_DIR);$(SED_REPL_TARGET)' -DEPEND_MK=$(TARGET)/depend.mk +DEPEND_MK=$(OBJ_DIR)/depend.mk -depend: +.PHONY: depend +depend: $(DEPEND_MK) +$(DEPEND_MK): @echo "Generating dependency file $(DEPEND_MK)..." @echo "# Generated dependency rules" > $(DEPEND_MK); @echo "# " >> $(DEPEND_MK); @@ -629,6 +632,8 @@ endif endif @echo "# EOF" >> $(DEPEND_MK); +ifneq ($(MAKECMDGOALS),clean) -include $(DEPEND_MK) +endif # eof diff --git a/erts/lib_src/pthread/ethread.c b/erts/lib_src/pthread/ethread.c index ad29249bac..fb7d135418 100644 --- a/erts/lib_src/pthread/ethread.c +++ b/erts/lib_src/pthread/ethread.c @@ -123,34 +123,53 @@ ethr_ts_event *ethr_get_tse__(void) #if defined(ETHR_PPC_RUNTIME_CONF__) -static volatile int lwsync_caused_sigill; +#include <sys/wait.h> static void handle_lwsync_sigill(int signum) { - lwsync_caused_sigill = 1; + _exit(1); } static int ppc_init__(void) { - struct sigaction act, oact; - lwsync_caused_sigill = 0; + int pid; - sigemptyset(&act.sa_mask); - act.sa_flags = 0; - act.sa_handler = handle_lwsync_sigill; - if (sigaction(SIGILL, &act, &oact) != 0) - return errno; + /* If anything what so ever failes we assume no lwsync for safety */ + ethr_runtime__.conf.have_lwsync = 0; + + /* + * We perform the lwsync test (which might cause an illegal + * instruction signal) in a separate process in order to be + * completely certain that we do not mess up our own state. + */ + pid = fork(); + if (pid == 0) { + struct sigaction act, oact; - __asm__ __volatile__ ("lwsync\n\t" : : : "memory"); + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESETHAND; + act.sa_handler = handle_lwsync_sigill; + if (sigaction(SIGILL, &act, &oact) != 0) + _exit(2); - act.sa_flags = 0; - act.sa_handler = SIG_DFL; - if (sigaction(SIGILL, &act, &oact) != 0) - return errno; + __asm__ __volatile__ ("lwsync\n\t" : : : "memory"); + + _exit(0); + } - ethr_runtime__.conf.have_lwsync = (int) !lwsync_caused_sigill; + if (pid != -1) { + while (1) { + int status, res; + res = waitpid(pid, &status, 0); + if (res == pid) { + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + ethr_runtime__.conf.have_lwsync = 1; + break; + } + } + } return 0; } diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam Binary files differindex fe91a604b5..df1831f340 100644 --- a/erts/preloaded/ebin/erl_prim_loader.beam +++ b/erts/preloaded/ebin/erl_prim_loader.beam diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex a21e5c6e06..b78747bc84 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam Binary files differindex 37fd8bb832..cc170b86b2 100644 --- a/erts/preloaded/ebin/init.beam +++ b/erts/preloaded/ebin/init.beam diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam Binary files differindex e255cc803f..45a409738c 100644 --- a/erts/preloaded/ebin/otp_ring0.beam +++ b/erts/preloaded/ebin/otp_ring0.beam diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex bc5631f3dd..87e80aae9b 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam Binary files differindex 1a00fb88c6..f382236af7 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam Binary files differindex b6c49d5c0c..411fc8d524 100644 --- a/erts/preloaded/ebin/prim_zip.beam +++ b/erts/preloaded/ebin/prim_zip.beam diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam Binary files differindex ebf9f8e6d6..bf88a51502 100644 --- a/erts/preloaded/ebin/zlib.beam +++ b/erts/preloaded/ebin/zlib.beam diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 4affc9bffe..4cbff3f36e 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -43,6 +43,9 @@ -export([memory/0, memory/1]). -export([alloc_info/1, alloc_sizes/1]). +-export([gather_sched_wall_time_result/1, + await_sched_wall_time_modifications/2]). + -deprecated([hash/2]). % Get rid of autoimports of spawn to avoid clashes with ourselves. @@ -1202,3 +1205,34 @@ receive_allocator(Ref, N, Acc) -> {Ref, _, InfoList} -> receive_allocator(Ref, N-1, insert_info(InfoList, Acc)) end. + +-spec await_sched_wall_time_modifications(Ref, Result) -> boolean() when + Ref :: reference(), + Result :: boolean(). + +await_sched_wall_time_modifications(Ref, Result) -> + sched_wall_time(Ref, erlang:system_info(schedulers)), + Result. + +-spec gather_sched_wall_time_result(Ref) -> [{pos_integer(), + non_neg_integer(), + non_neg_integer()}] when + Ref :: reference(). + +gather_sched_wall_time_result(Ref) when is_reference(Ref) -> + sched_wall_time(Ref, erlang:system_info(schedulers), []). + +sched_wall_time(_Ref, 0) -> + ok; +sched_wall_time(Ref, N) -> + receive Ref -> sched_wall_time(Ref, N-1) end. + +sched_wall_time(_Ref, 0, Acc) -> + Acc; +sched_wall_time(Ref, N, undefined) -> + receive {Ref, _} -> sched_wall_time(Ref, N-1, undefined) end; +sched_wall_time(Ref, N, Acc) -> + receive + {Ref, undefined} -> sched_wall_time(Ref, N-1, undefined); + {Ref, SWT} -> sched_wall_time(Ref, N-1, [SWT|Acc]) + end. diff --git a/erts/test/erl_print_SUITE.erl b/erts/test/erl_print_SUITE.erl index ee1a200530..adc353bd51 100644 --- a/erts/test/erl_print_SUITE.erl +++ b/erts/test/erl_print_SUITE.erl @@ -303,7 +303,7 @@ read_case_data(Port, TestCase) -> {Port, {data, {eol, [?PID_MARKER | PidStr]}}} -> ?line ?t:format("Port program pid: ~s~n", [PidStr]), ?line CaseProc = self(), - ?line list_to_integer(PidStr), % Sanity check + ?line _ = list_to_integer(PidStr), % Sanity check spawn_opt(fun () -> port_prog_killer(CaseProc, PidStr) end, diff --git a/erts/test/ethread_SUITE.erl b/erts/test/ethread_SUITE.erl index 80f988b0aa..5bb5aed3ed 100644 --- a/erts/test/ethread_SUITE.erl +++ b/erts/test/ethread_SUITE.erl @@ -68,9 +68,6 @@ tests() -> atomic, dw_atomic_massage]. -all(doc) -> []; -all(suite) -> tests(). - suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> @@ -125,35 +122,37 @@ try_lock_mutex(suite) -> try_lock_mutex(Config) -> run_case(Config, "try_lock_mutex", ""). -wd_dispatch(P) -> - receive - bye -> - ?line true = port_command(P, "-1 "), - ?line bye; - L when is_list(L) -> - ?line true = port_command(P, L), - ?line wd_dispatch(P) - end. - -watchdog(Port) -> - ?line process_flag(priority, max), - ?line receive after 500 -> ok end, - - ?line random:seed(), - ?line true = port_command(Port, "0 "), - ?line lists:foreach(fun (T) -> - erlang:send_after(T, - self(), - integer_to_list(T) - ++ " ") - end, - lists:usort(lists:map(fun (_) -> - random:uniform(4500)+500 - end, - lists:duplicate(50,0)))), - ?line erlang:send_after(5100, self(), bye), - - wd_dispatch(Port). +%% Remove dead code? + +% wd_dispatch(P) -> +% receive +% bye -> +% ?line true = port_command(P, "-1 "), +% ?line bye; +% L when is_list(L) -> +% ?line true = port_command(P, L), +% ?line wd_dispatch(P) +% end. +% +% watchdog(Port) -> +% ?line process_flag(priority, max), +% ?line receive after 500 -> ok end, +% +% ?line random:seed(), +% ?line true = port_command(Port, "0 "), +% ?line lists:foreach(fun (T) -> +% erlang:send_after(T, +% self(), +% integer_to_list(T) +% ++ " ") +% end, +% lists:usort(lists:map(fun (_) -> +% random:uniform(4500)+500 +% end, +% lists:duplicate(50,0)))), +% ?line erlang:send_after(5100, self(), bye), +% +% wd_dispatch(Port). cond_wait(doc) -> ["Tests ethr_cond_wait with ethr_cond_signal and ethr_cond_broadcast."]; @@ -307,7 +306,7 @@ read_case_data(Port, TestCase) -> {Port, {data, {eol, [?PID_MARKER | PidStr]}}} -> ?line ?t:format("Port program pid: ~s~n", [PidStr]), ?line CaseProc = self(), - ?line list_to_integer(PidStr), % Sanity check + ?line _ = list_to_integer(PidStr), % Sanity check spawn_opt(fun () -> port_prog_killer(CaseProc, PidStr) end, diff --git a/erts/test/ethread_SUITE_data/ethread_tests.c b/erts/test/ethread_SUITE_data/ethread_tests.c index 7e7e133d6c..ed96ecdbd2 100644 --- a/erts/test/ethread_SUITE_data/ethread_tests.c +++ b/erts/test/ethread_SUITE_data/ethread_tests.c @@ -82,6 +82,7 @@ static void print_eol(void) { fprintf(stderr, EOL); + fflush(stderr); } static void print_line(char *frmt,...) @@ -826,6 +827,7 @@ detached_thread_test(void) * Tests */ #define MTT_TIMES 10 +#define MTT_HARD_LIMIT (80000) static int mtt_terminate; static ethr_mutex mtt_mutex; @@ -866,14 +868,20 @@ mtt_create_join_threads(void) while (1) { if (ix >= no_tids) { no_tids += 100; + if (no_tids > MTT_HARD_LIMIT) { + print_line("Hit the hard limit on number of threads (%d)!", + MTT_HARD_LIMIT); + break; + } tids = (ethr_tid *) realloc((void *)tids, sizeof(ethr_tid)*no_tids); ASSERT(tids); } res = ethr_thr_create(&tids[ix], mtt_thread, NULL, NULL); - if (res != 0) + if (res != 0) { break; + } ix++; - } while (res == 0); + } no_threads = ix; diff --git a/erts/test/z_SUITE.erl b/erts/test/z_SUITE.erl index 482ecb8fba..28da923497 100644 --- a/erts/test/z_SUITE.erl +++ b/erts/test/z_SUITE.erl @@ -236,8 +236,8 @@ format_core(#core_search_conf{file = false}, Core, Ignore) -> [Ignore, Core] ++ mod_time_list(Core)); format_core(#core_search_conf{file = File}, Core, Ignore) -> FRes = str_strip(os:cmd(File ++ " " ++ Core)), - case catch regexp:match(FRes, Core) of - {match, _, _} -> + case catch re:run(FRes, Core, [caseless,{capture,none}]) of + match -> io:format(" ~s~s " ++ time_fstr() ++ "~n", [Ignore, FRes] ++ mod_time_list(Core)); _ -> diff --git a/erts/vsn.mk b/erts/vsn.mk index 1b3cd67947..bbf77b1a68 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2011. All Rights Reserved. +# Copyright Ericsson AB 1997-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -17,8 +17,8 @@ # %CopyrightEnd% # -VSN = 5.9 -SYSTEM_VSN = R15B +VSN = 5.9.1 +SYSTEM_VSN = R15B01 # Port number 4365 in 4.2 # Port number 4366 in 4.3 diff --git a/lib/Makefile b/lib/Makefile index 37e8ce06d7..aa4e074830 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -19,53 +19,21 @@ include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk -# -# Macros -# -ifeq ($(findstring vxworks,$(TARGET)),vxworks) - ERTS_SUB_DIRECTORIES = stdlib sasl kernel compiler - OTHER_SUB_DIRECTORIES = \ - snmp otp_mibs appmon erl_interface os_mon tools runtime_tools - ifdef BUILD_ALL - OTHER_SUB_DIRECTORIES += mnesia jinterface ic asn1 debugger \ - inets mnesia_session diameter orber pman tv observer \ - cosTransactions cosEvent cosTime cosNotification cosProperty - cosFileTransfer cosEventDomain - endif -else -# -# unix and win32 -# -------------- -# - ERTS_SUB_DIRECTORIES = stdlib sasl kernel compiler - OTHER_SUB_DIRECTORIES = tools test_server common_test runtime_tools - ifdef BUILD_ALL - ifeq ($(findstring win32,$(TARGET)),win32) # BUILD_ALL on win32 - OTHER_SUB_DIRECTORIES += \ - snmp otp_mibs appmon erl_interface asn1 jinterface gs wx inets ic \ - mnesia crypto orber os_mon parsetools syntax_tools pman \ - public_key ssl toolbar tv observer debugger reltool odbc \ - diameter \ - cosTransactions cosEvent cosTime cosNotification cosProperty \ - cosFileTransfer cosEventDomain et megaco webtool \ - xmerl edoc eunit ssh inviso typer erl_docgen \ - common_test percept dialyzer -# dialyzer - OTHER_SUB_DIRECTORIES += hipe - else # BUILD_ALL on unix - OTHER_SUB_DIRECTORIES += \ - snmp otp_mibs appmon erl_interface asn1 jinterface wx debugger reltool gs inets \ +ERTS_SUB_DIRECTORIES = stdlib sasl kernel compiler +OTHER_SUB_DIRECTORIES = tools test_server common_test runtime_tools +ifdef BUILD_ALL + OTHER_SUB_DIRECTORIES += \ + snmp otp_mibs appmon erl_interface asn1 jinterface \ + wx debugger reltool gs inets \ ic mnesia crypto orber os_mon parsetools syntax_tools \ pman public_key ssl toolbar tv observer odbc \ diameter \ cosTransactions cosEvent cosTime cosNotification \ cosProperty cosFileTransfer cosEventDomain et megaco webtool \ xmerl edoc eunit ssh inviso typer erl_docgen \ - common_test percept dialyzer -# dialyzer - OTHER_SUB_DIRECTORIES += hipe $(TSP_APP) - endif - endif + percept dialyzer hipe + EXTRA_FILE := $(wildcard EXTRA-APPLICATIONS) + EXTRA_APPLICATIONS := $(if $(EXTRA_FILE),$(shell cat $(EXTRA_FILE))) endif ifdef BOOTSTRAP @@ -76,9 +44,11 @@ else SUB_DIRECTORIES = hipe parsetools asn1/src else ifdef TERTIARY_BOOTSTRAP - SUB_DIRECTORIES = snmp sasl jinterface ic syntax_tools + SUB_DIRECTORIES = snmp sasl jinterface ic syntax_tools wx else # Not bootstrap build - SUB_DIRECTORIES = $(ERTS_SUB_DIRECTORIES) $(OTHER_SUB_DIRECTORIES) + SUB_DIRECTORIES = $(ERTS_SUB_DIRECTORIES) \ + $(OTHER_SUB_DIRECTORIES) \ + $(EXTRA_APPLICATIONS) endif endif endif diff --git a/lib/appmon/doc/src/appmon.xml b/lib/appmon/doc/src/appmon.xml index ae6147a387..5af50daa53 100644 --- a/lib/appmon/doc/src/appmon.xml +++ b/lib/appmon/doc/src/appmon.xml @@ -32,6 +32,12 @@ <module>appmon</module> <modulesummary>A graphical node and application process tree viewer.</modulesummary> <description> + <warning> + <p> + The Appmon application has been superseded by the Observer application. + Appmon will be removed in R16. + </p> + </warning> <p>The application monitor Appmon is a graphical utility used to supervise applications executing either locally or on remote nodes. The process tree of an application can furthermore be monitored.</p> diff --git a/lib/appmon/doc/src/appmon_chapter.xml b/lib/appmon/doc/src/appmon_chapter.xml index 0dab23b549..3f642ad002 100644 --- a/lib/appmon/doc/src/appmon_chapter.xml +++ b/lib/appmon/doc/src/appmon_chapter.xml @@ -31,6 +31,12 @@ <section> <title>Introduction</title> + <warning> + <p> + The Appmon application has been superseded by the Observer application. + Appmon will be removed in R16. + </p> + </warning> <p>The application monitor Appmon is a graphical node and application viewer. The tool shows an overview of all applications on all known nodes, and it is possible to view the process tree for an application running on any of the nodes.</p> <note> <p>If the Appmon code is not available at a node, for example an diff --git a/lib/appmon/doc/src/notes.xml b/lib/appmon/doc/src/notes.xml index ace163bcad..c469880abd 100644 --- a/lib/appmon/doc/src/notes.xml +++ b/lib/appmon/doc/src/notes.xml @@ -30,6 +30,27 @@ </header> <p>This document describes the changes made to the Appmon application.</p> +<section><title>Appmon 2.1.14</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Eliminate use of deprecated regexp module</p> + <p> + Own Id: OTP-9810</p> + </item> + <item> + <p> + Miscellaneous documentation build updates</p> + <p> + Own Id: OTP-9813</p> + </item> + </list> + </section> + +</section> + <section><title>Appmon 2.1.13</title> <section><title>Improvements and New Features</title> diff --git a/lib/appmon/src/appmon.erl b/lib/appmon/src/appmon.erl index 2b982cddf0..7a6d86c9ab 100644 --- a/lib/appmon/src/appmon.erl +++ b/lib/appmon/src/appmon.erl @@ -17,6 +17,11 @@ %% %CopyrightEnd% -module(appmon). -behaviour(gen_server). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,1}}]). %%%--------------------------------------------------------------------- %%% Appmon main module. diff --git a/lib/appmon/src/appmon_a.erl b/lib/appmon/src/appmon_a.erl index b0b5847343..2c8185a85d 100644 --- a/lib/appmon/src/appmon_a.erl +++ b/lib/appmon/src/appmon_a.erl @@ -17,6 +17,11 @@ %% %CopyrightEnd% %% -module(appmon_a). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,1}}]). %%---------------------------------------------------------------------- %% diff --git a/lib/appmon/src/appmon_lb.erl b/lib/appmon/src/appmon_lb.erl index 4e433f37c5..55fda83027 100644 --- a/lib/appmon/src/appmon_lb.erl +++ b/lib/appmon/src/appmon_lb.erl @@ -29,6 +29,13 @@ %%% then pressing the load button, its application window is started. -module(appmon_lb). +-compile([{nowarn_deprecated_function,{gs,button,3}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,listbox,3}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). -export ([ start/1, diff --git a/lib/appmon/src/appmon_txt.erl b/lib/appmon/src/appmon_txt.erl index 4e1785c53f..8647bc9890 100644 --- a/lib/appmon/src/appmon_txt.erl +++ b/lib/appmon/src/appmon_txt.erl @@ -22,6 +22,11 @@ %%------------------------------------------------------------ -module(appmon_txt). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,1}}]). -export([start/0, start/1, print/1, fprint/1]). %% gen_server stuff diff --git a/lib/appmon/vsn.mk b/lib/appmon/vsn.mk index fa17345daf..047f1eadc1 100644 --- a/lib/appmon/vsn.mk +++ b/lib/appmon/vsn.mk @@ -1 +1 @@ -APPMON_VSN = 2.1.13 +APPMON_VSN = 2.1.14 diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c index 9c9f83bc2a..accd368af1 100644 --- a/lib/asn1/c_src/asn1_erl_nif.c +++ b/lib/asn1/c_src/asn1_erl_nif.c @@ -580,7 +580,7 @@ int per_insert_bits_as_bits(int desired_no, int no_bytes, unsigned char **input_ptr, unsigned char **output_ptr, int *unused) { unsigned char *in_ptr = *input_ptr; unsigned char val; - int no_bits, ret, ret2; + int no_bits, ret; if (desired_no == (no_bytes * 8)) { if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused) @@ -606,8 +606,7 @@ int per_insert_bits_as_bits(int desired_no, int no_bytes, == ASN1_ERROR ) return ASN1_ERROR; - ret2 = per_pad_bits(desired_no - (no_bytes * 8), output_ptr, unused); - /* printf("ret2 = %d\n\r",ret2); */ + per_pad_bits(desired_no - (no_bytes * 8), output_ptr, unused); ret = CEIL(desired_no,8); /* printf("ret = %d\n\r",ret); */ } diff --git a/lib/asn1/doc/src/notes.xml b/lib/asn1/doc/src/notes.xml index 52d770c9f6..9b6c482c0a 100644 --- a/lib/asn1/doc/src/notes.xml +++ b/lib/asn1/doc/src/notes.xml @@ -31,6 +31,57 @@ <p>This document describes the changes made to the asn1 application.</p> +<section><title>Asn1 1.6.19</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The linked-in driver used for ber decode and per encode + has been replaced with nifs. To enable the usage of nifs + pass the nif option to erlc or asn1rt:compile when + compiling. If you previously used the linked-in driver, + you have to recompile your ASN1 modules with the current + version of asn1 application as the linked-in driver + modules have been removed.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9419</p> + </item> + <item> + <p> + A few of the heavy calculations which are done for + encoding and decoding operations when dealing with + SEQUENCE OF and DEFAULT in runtime have been moved to be + done in compile time instead.</p> + <p> + Own Id: OTP-9440</p> + </item> + <item> + <p> + When compiling an ASN.1 ber module with the +nif option, + the module will use a new nif for ber encoding, + increasing performance by about 5%.</p> + <p> + Own Id: OTP-9441</p> + </item> + <item> + <p> + Tuple funs (a two-element tuple with a module name and a + function) are now officially deprecated and will be + removed in R16. Use '<c>fun M:F/A</c>' instead. To make + you aware that your system uses tuple funs, the very + first time a tuple fun is applied, a warning will be sent + to the error logger.</p> + <p> + Own Id: OTP-9649</p> + </item> + </list> + </section> + +</section> + <section><title>Asn1 1.6.18</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk index b1132155e6..ae92fcb11b 100644 --- a/lib/asn1/vsn.mk +++ b/lib/asn1/vsn.mk @@ -1,2 +1,2 @@ #next version number to use is 1.6.15 | 1.7 | 2.0 -ASN1_VSN = 1.6.18 +ASN1_VSN = 1.6.19 diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile index 964f7c76c1..d9651f13b0 100644 --- a/lib/common_test/doc/src/Makefile +++ b/lib/common_test/doc/src/Makefile @@ -61,6 +61,7 @@ XML_PART_FILES = part.xml XML_CHAPTER_FILES = \ basics_chapter.xml \ + getting_started_chapter.xml \ install_chapter.xml \ write_test_chapter.xml \ test_structure_chapter.xml \ @@ -80,7 +81,10 @@ MAKE_EDOC = make_edoc BOOK_FILES = book.xml -GIF_FILES = +GIF_FILES = \ + tc_execution.gif \ + config.gif \ + html_logs.gif INSTALL_NOTES = ../../notes.html diff --git a/lib/common_test/doc/src/basics_chapter.xml b/lib/common_test/doc/src/basics_chapter.xml index c1bb365b1f..20141d2561 100644 --- a/lib/common_test/doc/src/basics_chapter.xml +++ b/lib/common_test/doc/src/basics_chapter.xml @@ -28,54 +28,65 @@ <rev></rev> <file>basics_chapter.xml</file> </header> - + <marker id="basics"></marker> <section> <title>Introduction</title> - <p> - The Common Test framework (CT) is a tool which can support - implementation and automated execution of test cases towards different - types of target systems. The framework is based on the OTP Test - Server. Test cases can be run individually or in batches. Common - Test also features a distributed testing mode with central - control and logging. This feature makes it possible to test - multiple systems independently in one common session. This - can be very useful e.g. for running automated large-scale regression - tests. + <p>The <em>Common Test</em> framework (CT) is a tool which supports + implementation and automated execution of test cases towards arbitrary + types of target systems. The CT framework is based on the OTP Test + Server and it's the main tool being used in all testing- and verification + activities that are part of Erlang/OTP system development- and maintenance. + </p> + + <p>Test cases can be executed individually or in batches. Common Test + also features a distributed testing mode with central control and logging + (a feature that makes it possible to test multiple systems independently in + one common session, useful e.g. for running automated large-scale regression + tests). </p> <p> The SUT (System Under Test) may consist of one or several target - nodes. CT contains a generic test server which together with - other test utilities is used to perform test case execution. - It is possible to start the tests from the CT GUI or from an OS- or - Erlang shell prompt. <em>Test suites</em> are files (Erlang + nodes. CT contains a generic test server which, together with + other test utilities, is used to perform test case execution. + It is possible to start the tests from a GUI or from the OS- or + Erlang shell. <em>Test suites</em> are files (Erlang modules) that contain the <em>test cases</em> (Erlang functions) to be executed. <em>Support modules</em> provide functions that the test cases utilize in order to carry out the tests. </p> - <p> - The main idea is that CT based test programs connect to - the target system(s) via standard O&M interfaces. CT - provides implementations and wrappers of some of these O&M - interfaces and will be extended with more interfaces later. - There are a number of target independent interfaces - supported in CT such as Generic Telnet, FTP etc. which can be - specialized or used directly for controlling instruments, - traffic generators etc.</p> + <p>In a black-box testing scenario, CT based test programs connect to + the target system(s) via standard O&M and CLI protocols. CT + provides implementations of, and wrapper interfaces to, some of these + protocols (most of which exist as stand-alone components and + applications in OTP). The wrappers simplify configuration and add + verbosity for logging purposes. CT will be continously extended with + useful support modules. (Note however that it's + a straightforward task to use any arbitrary Erlang/OTP component + for testing purposes with Common Test, without needing a CT wrapper + for it. It's as simple as calling Erlang functions). There + are a number of target independent interfaces supported in CT, such as + Generic Telnet, FTP, etc, which can be specialized or used + directly for controlling instruments, traffic load generators, etc. + </p> <p>Common Test is also a very useful tool for white-box testing Erlang - code since the test programs can call Erlang API functions directly. - For black-box testing Erlang software, Erlang RPC as well as - standard O&M interfaces can be used. + code (e.g. module testing), since the test programs can call exported Erlang + functions directly and there's very little overhead required for + implementing basic test suites and executing simple tests. For black-box + testing Erlang software, Erlang RPC as well as standard O&M interfaces + can for example be used. </p> <p>A test case can handle several connections towards one or several target systems, instruments and traffic generators in parallel in order to perform the necessary actions for a test. The handling of many connections in parallel is one of - the major strengths of Common Test! + the major strengths of Common Test (thanks to the efficient + support for concurrency in the Erlang runtime system - which CT users + can take great advantage of!). </p> </section> @@ -186,7 +197,7 @@ <taglist> <tag>all()</tag> - <item>Returns a list of all test cases in the suite. (Mandatory)</item> + <item>Returns a list of all test cases and groups in the suite. (Mandatory)</item> <tag>suite()</tag> <item>Info function used to return properties for the suite. (Optional)</item> <tag>groups()</tag> @@ -197,12 +208,14 @@ <tag>end_per_suite(Config)</tag> <item>Suite level configuration function, executed after the last test case. (Optional)</item> + <tag>group(GroupName)</tag> + <item>Info function used to return properties for a test case group. (Optional)</item> <tag>init_per_group(GroupName, Config)</tag> <item>Configuration function for a group, executed before the first - test case. (Mandatory if groups are defined)</item> + test case. (Optional)</item> <tag>end_per_group(GroupName, Config)</tag> <item>Configuration function for a group, executed after the last - test case. (Mandatory if groups are defined)</item> + test case. (Optional)</item> <tag>init_per_testcase(TestCase, Config)</tag> <item>Configuration function for a testcase, executed before each test case. (Optional)</item> diff --git a/lib/common_test/doc/src/common_test_app.xml b/lib/common_test/doc/src/common_test_app.xml index f58b2ab0a9..c7f6c7ce5c 100644 --- a/lib/common_test/doc/src/common_test_app.xml +++ b/lib/common_test/doc/src/common_test_app.xml @@ -69,12 +69,25 @@ <funcs> <func> - <name>Module:all() -> TestCases | {skip,Reason} </name> - <fsummary>Returns the list of all test cases in the module.</fsummary> + <name>Module:all() -> Tests | {skip,Reason} </name> + <fsummary>Returns the list of all test case groups and test cases + in the module.</fsummary> <type> - <v>TestCases = [atom() | {group,GroupName}]</v> - <v>Reason = term()</v> + <v>Tests = [TestCase | {group,GroupName} | + {group,GroupName,Properties} | + {group,GroupName,Properties,SubGroups}]</v> + <v>TestCase = atom()</v> <v>GroupName = atom()</v> + <v>Properties = [parallel | sequence | Shuffle | {RepeatType,N}] | + default</v> + <v>SubGroups = [{GroupName,Properties} | + {GroupName,Properties,SubGroups}]</v> + <v>Shuffle = shuffle | {shuffle,Seed}</v> + <v>Seed = {integer(),integer(),integer()}</v> + <v>RepeatType = repeat | repeat_until_all_ok | repeat_until_all_fail | + repeat_until_any_ok | repeat_until_any_fail</v> + <v>N = integer() | forever</v> + <v>Reason = term()</v> </type> <desc> @@ -85,9 +98,14 @@ This list also specifies the order the cases and groups will be executed by Common Test. A test case is represented by an atom, the name of the test case function. A test case group is - represented by a <c>{group,GroupName}</c> tuple, where - <c>GroupName</c>, an atom, is the name of the group (defined - with <c>groups/0</c>).</p> + represented by a <c>group</c> tuple, where <c>GroupName</c>, + an atom, is the name of the group (defined in <c>groups/0</c>). + Execution properties for groups may also be specified, both + for a top level group and for any of its sub-groups. + Group execution properties specified here, will override + properties in the group definition (see <c>groups/0</c>). + (With value <c>default</c>, the group definition properties + will be used).</p> <p> If <c>{skip,Reason}</c> is returned, all test cases in the module will be skipped, and the <c>Reason</c> will @@ -120,14 +138,16 @@ <desc> <p> OPTIONAL </p> - <p>See <seealso marker="write_test_chapter#test_case_groups">Test case + <p>Function for defining test case groups. Please see + <seealso marker="write_test_chapter#test_case_groups">Test case groups</seealso> in the User's Guide for details.</p> </desc> </func> <func> <name>Module:suite() -> [Info] </name> - <fsummary>Test suite info function (providing default data for the suite).</fsummary> + <fsummary>Test suite info function (providing default data + for the suite).</fsummary> <type> <v> Info = {timetrap,Time} | {require,Required} | {require,Name,Required} | {userdata,UserData} | @@ -160,11 +180,11 @@ <p>This is the test suite info function. It is supposed to return a list of tagged tuples that specify various properties - regarding the execution of this test suite (common for all + related to the execution of this test suite (common for all test cases in the suite).</p> <p>The <c>timetrap</c> tag sets the maximum time each - test case is allowed to take (including <c>init_per_testcase/2</c> + test case is allowed to execute (including <c>init_per_testcase/2</c> and <c>end_per_testcase/2</c>). If the timetrap time is exceeded, the test case fails with reason <c>timetrap_timeout</c>. If a <c>TimeFunc</c> function is specified, @@ -172,9 +192,9 @@ <c>TimeVal</c> format.</p> <p>The <c>require</c> tag specifies configuration variables - that are required by test cases in the suite. If the required - configuration variables are not found in any of the - configuration files, all test cases are skipped. For more + that are required by test cases (and/or configuration functions) + in the suite. If the required configuration variables are not found + in any of the configuration files, all test cases are skipped. For more information about the 'require' functionality, see the reference manual for the function <c>ct:require/[1,2]</c>.</p> @@ -196,8 +216,9 @@ </func> <func> - <name>Module:init_per_suite(Config) -> NewConfig | {skip,Reason} | {skip_and_save,Reason,SaveConfig}</name> - <fsummary>Test suite initialization.</fsummary> + <name>Module:init_per_suite(Config) -> NewConfig | {skip,Reason} | + {skip_and_save,Reason,SaveConfig}</name> + <fsummary>Test suite initializations.</fsummary> <type> <v> Config = NewConfig = SaveConfig = [{Key,Value}]</v> <v> Key = atom()</v> @@ -208,15 +229,15 @@ <p> OPTIONAL </p> - <p>This function is called as the first function in the - suite. It typically contains initialization which is common for + <p>This configuration function is called as the first function in the + suite. It typically contains initializations which are common for all test cases in the suite, and which shall only be done - once. The <c>Config</c> parameter is the configuration + once. The <c>Config</c> parameter is the configuration data which can be modified here. Whatever is returned from this function is given as <c>Config</c> to all configuration functions and test cases in the suite. If <c>{skip,Reason}</c> - is returned, all test cases in the suite will be skipped and <c>Reason</c> - printed in the overview log for the suite.</p> + is returned, all test cases in the suite will be skipped + and <c>Reason</c> printed in the overview log for the suite.</p> <p>For information on <c>save_config</c> and <c>skip_and_save</c>, please see <seealso marker="dependencies_chapter#save_config">Dependencies @@ -224,29 +245,106 @@ </desc> </func> - <func> - <name>Module:end_per_suite(Config) -> void() | {save_config,SaveConfig}</name> - <fsummary>Test suite finalization. </fsummary> - <type> - <v> Config = SaveConfig = [{Key,Value}]</v> - <v> Key = atom()</v> - <v> Value = term()</v> - </type> + <func> + <name>Module:end_per_suite(Config) -> void() | + {save_config,SaveConfig}</name> + <fsummary>Test suite finalization. </fsummary> + <type> + <v> Config = SaveConfig = [{Key,Value}]</v> + <v> Key = atom()</v> + <v> Value = term()</v> + </type> + + <desc> + <p> OPTIONAL </p> + <p>This function is called as the last test case in the + suite. It is meant to be used for cleaning up after + <c>init_per_suite/1</c>. + For information on <c>save_config</c>, please see + <seealso marker="dependencies_chapter#save_config">Dependencies + between Test Cases and Suites</seealso> in the User's Guide.</p> + </desc> + </func> + + <func> + <name>Module:group(GroupName) -> [Info] </name> + <fsummary>Test case group info function (providing default data + for a test case group, i.e. its test cases and sub-groups).</fsummary> + <type> + <v> Info = {timetrap,Time} | {require,Required} | + {require,Name,Required} | {userdata,UserData} | + {silent_connections,Conns} | {stylesheet,CSSFile} | + {ct_hooks, CTHs}</v> + <v> Time = TimeVal | TimeFunc</v> + <v> TimeVal = MilliSec | {seconds,integer()} | {minutes,integer()} | + {hours,integer()}</v> + <v> TimeFunc = {Mod,Func,Args} | Fun</v> + <v> MilliSec = integer()</v> + <v> Mod = atom()</v> + <v> Func = atom()</v> + <v> Args = list()</v> + <v> Fun = fun()</v> + <v> Required = Key | {Key,SubKeys}</v> + <v> Key = atom()</v> + <v> SubKeys = SubKey | [SubKey]</v> + <v> SubKey = atom()</v> + <v> Name = atom()</v> + <v> UserData = term()</v> + <v> Conns = [atom()]</v> + <v> CSSFile = string()</v> + <v> CTHs = [CTHModule | {CTHModule, CTHInitArgs} | + {CTHModule, CTHInitArgs, CTHPriority}]</v> + <v> CTHModule = atom()</v> + <v> CTHInitArgs = term()</v> + </type> <desc> + <p> OPTIONAL </p> - <p>This function is called as the last test case in the - suite. It is meant to be used for cleaning up after <c>init_per_suite/1</c>. - For information on <c>save_config</c>, please see - <seealso marker="dependencies_chapter#save_config">Dependencies between - Test Cases and Suites</seealso> in the User's Guide.</p> - </desc> + <p>This is the test case group info function. It is supposed to + return a list of tagged tuples that specify various properties + related to the execution of a test case group (i.e. its test cases + and sub-groups). Properties set by <c>groups/1</c> override + properties with the same key that have been previously set by + <c>suite/0</c>.</p> + + <p>The <c>timetrap</c> tag sets the maximum time each + test case is allowed to execute (including <c>init_per_testcase/2</c> + and <c>end_per_testcase/2</c>). If the timetrap time is + exceeded, the test case fails with reason + <c>timetrap_timeout</c>. If a <c>TimeFunc</c> function is specified, + it will be called initially and must return a value on + <c>TimeVal</c> format.</p> + + <p>The <c>require</c> tag specifies configuration variables + that are required by test cases (and/or configuration functions) + in the suite. If the required configuration variables are not found + in any of the configuration files, all test cases in this group are skipped. + For more information about the 'require' functionality, see the + reference manual for the function + <c>ct:require/[1,2]</c>.</p> + + <p>With <c>userdata</c>, it is possible for the user to + specify arbitrary test case group related information which can be + read by calling <c>ct:userdata/2</c>.</p> + + <p>The <c>ct_hooks</c> tag specifies which + <seealso marker="ct_hooks_chapter">Common Test Hooks</seealso> + are to be run together with this suite.</p> + + <p>Other tuples than the ones defined will simply be ignored.</p> + + <p>For more information about the test case group info function, + see <seealso marker="write_test_chapter#suite">Test + case group info function</seealso> in the User's Guide.</p> + </desc> </func> <func> - <name>Module:init_per_group(GroupName, Config) -> NewConfig | {skip,Reason}</name> - <fsummary>Test case group initialization.</fsummary> + <name>Module:init_per_group(GroupName, Config) -> NewConfig | + {skip,Reason}</name> + <fsummary>Test case group initializations.</fsummary> <type> <v> GroupName = atom()</v> <v> Config = NewConfig = [{Key,Value}]</v> @@ -258,16 +356,16 @@ <p> OPTIONAL </p> - <p>This function is called before execution of a test case group. - It typically contains initialization which is common for - all test cases in the group, and which shall only be performed - once. <c>GroupName</c> is the name of the group, as specified in - the group definition (see <c>groups/0</c>). The <c>Config</c> - parameter is the configuration which can be modified here. - Whatever is returned from this function is given as <c>Config</c> - to all test cases in the group. If <c>{skip,Reason}</c> is returned, - all test cases in the group will be skipped and <c>Reason</c> printed - in the overview log for the group.</p> + <p>This configuration function is called before execution of a + test case group. It typically contains initializations which are + common for all test cases and sub-groups in the group, and which + shall only be performed once. <c>GroupName</c> is the name of the + group, as specified in the group definition (see <c>groups/0</c>). The + <c>Config</c> parameter is the configuration data which can be modified + here. The return value of this function is given as <c>Config</c> + to all test cases and sub-groups in the group. If <c>{skip,Reason}</c> + is returned, all test cases in the group will be skipped and + <c>Reason</c> printed in the overview log for the group.</p> <p>For information about test case groups, please see <seealso marker="write_test_chapter#test_case_groups">Test case @@ -276,7 +374,8 @@ </func> <func> - <name>Module:end_per_group(GroupName, Config) -> void() | {return_group_result,Status}</name> + <name>Module:end_per_group(GroupName, Config) -> void() | + {return_group_result,Status}</name> <fsummary>Test case group finalization.</fsummary> <type> <v> GroupName = atom()</v> @@ -305,7 +404,7 @@ <func> <name>Module:init_per_testcase(TestCase, Config) -> NewConfig | {fail,Reason} | {skip,Reason}</name> - <fsummary>Test case initialization.</fsummary> + <fsummary>Test case initializations.</fsummary> <type> <v> TestCase = atom()</v> <v> Config = NewConfig = [{Key,Value}]</v> @@ -385,10 +484,13 @@ <p>This is the test case info function. It is supposed to return a list of tagged tuples that specify various properties - regarding the execution of this particular test case.</p> + related to the execution of this particular test case. + Properties set by <c>Testcase/0</c> override + properties that have been previously set for the test case + by <c>group/1</c> or <c>suite/0</c>.</p> <p>The <c>timetrap</c> tag sets the maximum time the - test case is allowed to take. If the timetrap time is + test case is allowed to execute. If the timetrap time is exceeded, the test case fails with reason <c>timetrap_timeout</c>. <c>init_per_testcase/2</c> and <c>end_per_testcase/2</c> are included in the @@ -397,16 +499,16 @@ and must return a value on <c>TimeVal</c> format.</p> <p>The <c>require</c> tag specifies configuration variables - that are required by the test case. If the required - configuration variables are not found in any of the + that are required by the test case (and/or <c>init/end_per_testcase/2</c>). + If the required configuration variables are not found in any of the configuration files, the test case is skipped. For more information about the 'require' functionality, see the reference manual for the function <c>ct:require/[1,2]</c>.</p> <p>If <c>timetrap</c> and/or <c>require</c> is not set, the - default values specified in the <c>suite/0</c> return list - will be used.</p> + default values specified by <c>suite/0</c> (or + <c>group/1</c>) will be used.</p> <p>With <c>userdata</c>, it is possible for the user to specify arbitrary test case related information which can be @@ -438,12 +540,12 @@ <p>This is the implementation of a test case. Here you must call the functions you want to test, and do whatever you need to check the result. If something fails, make sure the - function causes a runtime error, or call <c>ct:fail/[0,1]</c> - (which also causes the test case process to crash).</p> + function causes a runtime error, or call <c>ct:fail/1/2</c> + (which also causes the test case process to terminate).</p> - <p>Elements from the <c>Config</c> parameter can be read - with the <c>?config</c> macro. The <c>config</c> - macro is defined in <c>ct.hrl</c></p> + <p>Elements from the <c>Config</c> list can e.g. be read + with <c>proplists:get_value/2</c> (or the macro <c>?config</c> + defined in <c>ct.hrl</c>).</p> <p>You can return <c>{skip,Reason}</c> if you decide not to run the test case after all. <c>Reason</c> will then be diff --git a/lib/common_test/doc/src/config.gif b/lib/common_test/doc/src/config.gif Binary files differnew file mode 100644 index 0000000000..ac8006c4fb --- /dev/null +++ b/lib/common_test/doc/src/config.gif diff --git a/lib/common_test/doc/src/event_handler_chapter.xml b/lib/common_test/doc/src/event_handler_chapter.xml index b41b233ce6..a5886b9687 100644 --- a/lib/common_test/doc/src/event_handler_chapter.xml +++ b/lib/common_test/doc/src/event_handler_chapter.xml @@ -174,6 +174,16 @@ are also given. </p></item> + <item><c>#event{name = tc_logfile, data = {{Suite,Func},LogFileName}}</c> + <p><c>Suite = atom()</c>, name of the test suite.</p> + <p><c>Func = atom()</c>, name of test case or configuration function.</p> + <p><c>LogFileName = string()</c>, full name of test case log file.</p> + <p>This event is sent at the start of each test case (and configuration function + except <c>init/end_per_testcase</c>) and carries information about the + full name (i.e. the file name including the absolute directory path) of + the current test case log file. + </p></item> + <marker id="tc_done"/> <item><c>#event{name = tc_done, data = {Suite,FuncOrGroup,Result}}</c> <p><c>Suite = atom()</c>, name of the suite.</p> diff --git a/lib/common_test/doc/src/getting_started_chapter.xml b/lib/common_test/doc/src/getting_started_chapter.xml new file mode 100644 index 0000000000..7de0912036 --- /dev/null +++ b/lib/common_test/doc/src/getting_started_chapter.xml @@ -0,0 +1,230 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + <header> + <copyright> + <year>2007</year><year>2010</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + The contents of this file are subject to the Erlang Public License, + Version 1.1, (the "License"); you may not use this file except in + compliance with the License. You should have received a copy of the + Erlang Public License along with this software. If not, it can be + retrieved online at http://www.erlang.org/. + + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License. + + </legalnotice> + + <title>Getting Started</title> + <prepared>Peter Andersson</prepared> + <docno></docno> + <date>2011-12-12</date> + <rev></rev> + <file>getting_started_chapter.xml</file> + </header> + + <section> + <title>Are you new around here?</title> + <p> + The purpose of this short chapter is to, with a "learning by example" + approach, give the newcomer a chance to get started quickly writing and + executing some first simple tests. The chapter will introduce some of the + basics, but leave most explanations and details for the later + chapters in this User's Guide. Hopefully though, after this chapter, you + will be inspired and unintimidated enough to go on and get into the + nitty-gritty that follows in this rather heavy User's Guide! If you're + not much into "learning by example" and prefer to get into more technical + detail right away, go ahead and skip to the next chapter. Again, the basics + presented here will be covered in detail in later chapters. + </p> + <p> + This chapter also tries to demonstrate how dead simple it actually is + to write a very basic (yet for many module testing purposes, often sufficiently + complex) test suite, and execute its test cases. This is not necessarily + obvious when you read the rest of the chapters in the User's Guide. + </p> + <p> + A quick note before we start: In order to understand what's discussed and + examplified here, it is recommended that you first read through the + opening <seealso marker="basics_chapter#basics">Common Test Basics</seealso> + chapter. + </p> + </section> + + <section> + <title>Test case execution</title> + <p>Execution of test cases is handled this way:</p> + + <p> + <image file="tc_execution.gif"> + <icaption> + Successful vs unsuccessful test case execution. + </icaption> + </image> + </p> + + <p>For each test case that Common Test is told to execute, it spawns a + dedicated process on which the test case function in question starts + running. (In parallel to the test case process, an idle waiting timer + process is started which is linked to the test case process. If the timer + process runs out of waiting time, it sends an exit signal to terminate + the test case process and this is what's called a <em>timetrap</em>). + </p> + <p>In scenario 1, the test case process terminates normally after case A has + finished executing its test code without detecting any errors. The test + case function simply returns a value and Common Test logs the test case as + successful. + </p> + <p>In scenario 2, an error is detected during test case execution + which causes the test case B function to generate an exception. + This causes the test case process to exit with reason + other than normal, and as a result, Common Test will log this as an + unsuccessful test case. + </p> + <p>As you can understand from the illustration above, Common Test requires + that a test case generates a runtime error to indicate failure (e.g. + by causing a bad match error or by calling <c>exit/1</c>, preferrably + through the <c>ct:fail/1/2</c> help function). A succesful execution is + indicated by means of a normal return from the test case function. + </p> + </section> + + <section> + <title>A simple test suite</title> + <p>As you've seen in the basics chapter, the test suite module implements + callback functions (mandatory or optional) for various purposes, e.g: + <list> + <item>Init/end configuration function for the test suite</item> + <item>Init/end configuration function for a test case</item> + <item>Init/end configuration function for a test case group</item> + <item>Test cases</item> + </list> + The configuration functions are optional and if you don't need them for + your test, a test suite with one simple test case could look like this: + </p> + <pre> + -module(my1st_SUITE). + -compile(export_all). + + all() -> + [mod_exists]. + + mod_exists(_) -> + {module,mymod} = code:load_file(mymod).</pre> + <p> + In this example we check that the <c>mymod</c> module exists (i.e. can be + successfully loaded by the code server). If the operation fails, we will + get a bad match error which terminates the test case. + </p> + </section> + + <section> + <title>A test suite with configuration functions</title> + <p> + If we need to perform configuration operations in order to run our test, we + implement configuration functions in our suite. The result from a + configuration function is configuration data, or simply <em><c>Config</c></em>. + This is a list of key-value tuples which get passed from the configuration + function to the test cases (possibly through configuration functions on + "lower level"). The data flow looks like this: + </p> + + <p> + <image file="config.gif"> + <icaption> + Config data flow in the suite. + </icaption> + </image> + </p> + + <p> + Here's an example of a test suite which uses configuration functions + to open and close a log file for the test cases (an operation that would + be unnecessary and irrelevant to perform by each test case): + </p> + <pre> + -module(check_log_SUITE). + -export([all/0, init_per_suite/1, end_per_suite/1]). + -export([check_restart_result/1, check_no_errors/1]). + + -define(value(Key,Config), proplists:get_value(Key,Config)). + + all() -> [check_restart_result, check_no_errors]. + + init_per_suite(InitConfigData) -> + [{logref,open_log()} | InitConfigData]. + + end_per_suite(ConfigData) -> + close_log(?value(logref, ConfigData)). + + check_restart_result(ConfigData) -> + TestData = read_log(restart, ?value(logref, ConfigData)), + {match,_Line} = search_for("restart successful", TestData). + + check_no_errors(ConfigData) -> + TestData = read_log(all, ?value(logref, ConfigData)), + case search_for("error", TestData) of + {match,Line} -> ct:fail({error_found_in_log,Line}); + nomatch -> ok + end.</pre> + <p> + In this example we have test cases that verify, by parsing a + log file, that our SUT has performed a successful restart and + that no unexpected errors have been printed. + </p> + + <p>To execute the test cases in the test suite above, we could type this on + the Unix/Linux command line (assuming for this example that the suite module + is in the current working directory): + </p> + <pre> + $ ct_run -dir .</pre> + <p>or</p> + <pre> + $ ct_run -suite check_log_SUITE</pre> + + <p>If we want to use the Erlang shell to run our test, we could evaluate this call: + </p> + <pre> + 1> ct:run_test([{dir, "."}]).</pre> + <p>or</p> + <pre> + 1> ct:run_test([{suite, "check_log_SUITE"}]).</pre> + <p> + The result from running our test is printed in log files on HTML format + (stored in unique log directories on different level). This illustration + shows the log file structure: + </p> + + <p> + <image file="html_logs.gif"> + <icaption> + HTML log file structure. + </icaption> + </image> + </p> + </section> + + <section> + <title>What happens next?</title> + <p> + You will find detailed information about the basics introduced here in this + chapter in the following chapters in the User's Guide, as well as + presentations of many more useful features. Have fun! + </p> + </section> +</chapter> + + + + + + + + diff --git a/lib/common_test/doc/src/html_logs.gif b/lib/common_test/doc/src/html_logs.gif Binary files differnew file mode 100644 index 0000000000..3a3fd86bde --- /dev/null +++ b/lib/common_test/doc/src/html_logs.gif diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml index af96ef621f..da0b6b2d65 100644 --- a/lib/common_test/doc/src/notes.xml +++ b/lib/common_test/doc/src/notes.xml @@ -32,6 +32,163 @@ <file>notes.xml</file> </header> +<section><title>Common_Test 1.6</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + A Getting Started chapter has been added to the Common + Test User's Guide.</p> + <p> + Own Id: OTP-9156</p> + </item> + <item> + <p> + The test case group info function has been implemented in + Common Test. Before execution of a test case group, a + call is now made to <c>TestSuite:group(GroupName)</c>. + The function returns a list of test properties, e.g. to + specify timetrap values, require configuration data, etc + (analogue to the test suite- and test case info + function). The scope of the properties set by + <c>group(GroupName)</c> is all test cases and sub-groups + of group <c>GroupName</c>.</p> + <p> + Own Id: OTP-9235</p> + </item> + <item> + <p> + Common Test hooks are now in a final supported version. + The Common Test hooks allow you to abstract out + initialization behaviour that is common to multiple test + suites into one place and also extend the behaviour of a + suite without changing the suite itself. For more + information see the Common Test user's guide.</p> + <p> + Own Id: OTP-9449</p> + </item> + <item> + <p> + A new built-in common test hook has been added which + captures error_logger and SASL event and prints them in + the testcase log. To disable this (and any other built-in + hooks) pass 'enable_builtin_hooks false' to common test.</p> + <p> + Own Id: OTP-9543</p> + </item> + <item> + <p> + Common Test now calls info functions also for the + <c>init/end_per_suite/1</c> and + <c>init/end_per_group/2</c> configuration functions. + These can be used e.g. to set timetraps and require + external configuration data relevant only for the + configuration functions in question (without affecting + properties set for groups and test cases in the suite). + The info function for <c>init/end_per_suite(Config)</c> + is <c>init/end_per_suite()</c>, and for + <c>init/end_per_group(GroupName,Config)</c> it's + <c>init/end_per_group(GroupName)</c>. Info functions can + not be used with <c>init/end_per_testcase(TestCase, + Config)</c>, since these configuration functions execute + on the test case process and will use the same properties + as the test case (i.e. properties set by the test case + info function, <c>TestCase()</c>).</p> + <p> + Own Id: OTP-9569</p> + </item> + <item> + <p> + It's now possible to read the full name of the test case + log file during execution. One way to do this is to + lookup it up as value of the key <c>tc_logfile</c> in the + test case <c>Config</c> list (which means it can also be + read by a pre- or post Common Test hook function). The + data is also sent with the event + <c>#event{name=tc_logfile,data={{Suite,Func},LogFileName}}</c>, + and can be read by any installed event handler.</p> + <p> + Own Id: OTP-9676 Aux Id: seq11941 </p> + </item> + <item> + <p> + The look of the HTML log files generated by Common Test + and Test Server has been improved (and made easier to + customize) by means of a CSS file.</p> + <p> + Own Id: OTP-9706</p> + </item> + <item> + <p> + Functions ct:fail(Format, Args) and ct:comment(Format, + Args) have been added in order to make printouts of + formatted error and comment strings easier (no need for + the user to call io_lib:format/2 explicitly).</p> + <p> + Own Id: OTP-9709 Aux Id: seq11951 </p> + </item> + <item> + <p> + The order in which ct hooks are executed for cleanup + hooks (i.e. *_end_per_* hooks) has been reversed.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9774 Aux Id: seq11913 </p> + </item> + <item> + <p> + Printouts to stdout may be captured during test case + execution. This is useful in order to e.g. read and parse + tty printouts from the SUT during test case execution (if + necessary, say, to determine the outcome of the test). + The capturing session is started with + <c>ct:capture_start/0</c>, and stopped with + <c>ct:capture_stop/0</c>. The list of buffered strings is + read and purged with <c>ct:capture_get/0/1</c>. It's + possible to filter out printouts made with + <c>ct:log/2/3</c> and <c>ct:pal/2/3</c> from the captured + list of strings. This is done by calling + <c>capture_get/1</c> with a list of log categories to + exclude.</p> + <p> + Own Id: OTP-9775</p> + </item> + <item> + <p> + The syntax for specifying test case groups in the all/0 + list has been extended to include execution properties + for both groups and sub-groups. The properties specified + in all/0 for a group overrides the properties specified + in the group declaration (in groups/0). The main purpose + of this extension is to make it possible to run the same + set of tests, but with different properties, without + having to declare copies of the group in question. Also, + the same syntax may be used in test specifications in + order to change properties of groups at the time of + execution, without having to edit the test suite. Please + see the User's Guide for details and examples.</p> + <p> + Own Id: OTP-9809 Aux Id: OTP-9235 </p> + </item> + </list> + </section> + + + <section><title>Known Bugs and Problems</title> + <list> + <item> + <p> + Fix problems in CT/TS due to line numbers in exceptions.</p> + <p> + Own Id: OTP-9203</p> + </item> + </list> + </section> + +</section> + <section><title>Common_Test 1.5.5</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/common_test/doc/src/part.xml b/lib/common_test/doc/src/part.xml index 3284bcadaa..a74185221d 100644 --- a/lib/common_test/doc/src/part.xml +++ b/lib/common_test/doc/src/part.xml @@ -65,6 +65,7 @@ </description> <xi:include href="basics_chapter.xml"/> + <xi:include href="getting_started_chapter.xml"/> <xi:include href="install_chapter.xml"/> <xi:include href="write_test_chapter.xml"/> <xi:include href="test_structure_chapter.xml"/> diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml index 57059f0ba2..848f278fa6 100644 --- a/lib/common_test/doc/src/run_test_chapter.xml +++ b/lib/common_test/doc/src/run_test_chapter.xml @@ -412,6 +412,16 @@ the way from <c>init_per_suite</c> down to the test cases in the sub group).</p> + <p>With the <c>GroupSpec</c> element (below) it's possible to specify + group execution properties that will override those specified in the + group definition (i.e. in <c>groups/0</c>). Execution properties for + sub-groups may be overridden as well. This feature makes it possible to + change properties of groups at the time of execution, + without even having to edit the test suite. More detailed documentation, + and examples, can be found in the + <seealso marker="write_test_chapter#test_case_groups"> + Test case groups</seealso> chapter.</p> + <p>Below is the test specification syntax. Test specifications can be used to run tests both in a single test host environment and in a distributed Common Test environment (Large Scale @@ -475,8 +485,8 @@ {groups, DirRef, Suite, Groups}. {groups, NodeRefsDirRef, Suite, Groups}. - {groups, DirRef, Suite, Group, {cases,Cases}}. - {groups, NodeRefsDirRef, Suite, Group, {cases,Cases}}. + {groups, DirRef, Suite, GroupSpec, {cases,Cases}}. + {groups, NodeRefsDirRef, Suite, GroupSpec, {cases,Cases}}. {cases, DirRef, Suite, Cases}. {cases, NodeRefs, DirRef, Suite, Cases}. @@ -510,7 +520,8 @@ DirRef = DirAlias | Dir Suites = atom() | [atom()] | all Suite = atom() - Groups = atom() | [atom()] | all + Groups = GroupSpec | [GroupSpec] | all + GroupSpec = Group | {Group,Properties} | {Group,Properties,GroupSpec} Group = atom() Cases = atom() | [atom()] | all Comment = string() | "" @@ -644,14 +655,25 @@ to each individual test case log file for quick viewing with an HTML browser.</p> - <p>The minor log file contain full details of every single test - case, each one in a separate file. This way the files should - be easy to compare with previous test runs, even if the set of - test cases change. If SASL is running those logs will also be - printed there by the + <p>The minor log files contain full details of every single test + case, each one in a separate file. This way, it should be + straightforward to compare the latest results to that of previous + test runs, even if the set of test cases changes. If SASL is running, + its logs will also be printed to the current minor log file by the <seealso marker="common_test:ct_hooks_chapter#builtin_cths"> cth_log_redirect built-in hook</seealso>. - </p> + </p> + + <p>The full name of the minor log file (i.e. the name of the file + including the absolute directory path) can be read during execution + of the test case. It comes as value in the tuple + <c>{tc_logfile,LogFileName}</c> in the <c>Config</c> list (which means it + can also be read by a pre- or post Common Test hook function). Also, + at the start of a test case, this data is sent with an event + to any installed event handler. Please see the + <seealso marker="event_handler_chapter#event_handling">Event Handling</seealso> + chapter for details. + </p> <p>Which information goes where is user configurable via the test server controller. Three threshold values determine what @@ -693,8 +715,15 @@ <section> <marker id="html_stylesheet"></marker> <title>HTML Style Sheets</title> - <p>Common Test includes the <em>optional</em> feature to use - HTML style sheets (CSS) for customizing user printouts. The + <p>Common Test uses a CSS file to control the look of the HTML + files generated during test runs. If, for some reason, the + log files are not displayed correctly in the HTML browser of your + choice, or you prefer the "pre Common Test v1.6 look" + of the log files (i.e. not using CSS), use the start flag/option + <c>basic_html</c> to revert to the old style.</p> + + <p>Common Test includes an <em>optional</em> feature to allow + user HTML style sheets for customizing printouts. The functions in <c>ct</c> that print to a test case HTML log file (<c>log/3</c> and <c>pal/3</c>) accept <c>Category</c> as first argument. With this argument it's possible to @@ -708,22 +737,16 @@ look like this:</p> <pre> -<style> - div.ct_internal { background:lightgrey; color:black } - div.default { background:lightgreen; color:black } - div.sys_config { background:blue; color:white } - div.sys_state { background:yellow; color:black } - div.error { background:red; color:white } -</style> - </pre> + div.sys_config { background:blue; color:white } + div.sys_state { background:yellow; color:black } + div.error { background:red; color:white }</pre> <p>To install the CSS file (Common Test inlines the definition in the HTML code), the name may be provided when executing <c>ct_run</c>. Example:</p> <pre> - $ ct_run -dir $TEST/prog -stylesheet $TEST/styles/test_categories.css - </pre> + $ ct_run -dir $TEST/prog -stylesheet $TEST/styles/test_categories.css</pre> <p>Categories in a CSS file installed with the <c>-stylesheet</c> flag are on a global test level in the sense that they can be used in any @@ -744,8 +767,7 @@ ct:log(sys_state, "Connections: ~p", [ConnectionInfo]), ... ct:pal(error, "Error ~p detected! Info: ~p", [SomeFault,ErrorInfo]), - ct:fail(SomeFault). - </pre> + ct:fail(SomeFault).</pre> <p>If the style sheet is installed as in this example, the categories are private to the suite in question. They can be used by all test cases in the @@ -769,21 +791,6 @@ <p>The <c>Category</c> argument in the example above may have the value (atom) <c>sys_config</c> (white on blue), <c>sys_state</c> (black on yellow) or <c>error</c> (white on red).</p> - - <p>If the <c>Category</c> argument is not specified, Common Test will - use the CSS selector <c>div.default</c> for the - printout. For this reason a user supplied style sheet must - include this selector. Also the selector - <c>div.ct_internal</c> must be included. Hence a minimal - user style sheet should look like this (which is also the - default style sheet Common Test uses if no user CSS file is - provided):</p> - <pre> - <style> - div.ct_internal { background:lightgrey; color:black } - div.default { background:lightgreen; color:black } - </style> - </pre> </section> <section> diff --git a/lib/common_test/doc/src/tc_execution.gif b/lib/common_test/doc/src/tc_execution.gif Binary files differnew file mode 100644 index 0000000000..7c89d7be57 --- /dev/null +++ b/lib/common_test/doc/src/tc_execution.gif diff --git a/lib/common_test/doc/src/write_test_chapter.xml b/lib/common_test/doc/src/write_test_chapter.xml index e35888e68f..c0ec26ddcc 100644 --- a/lib/common_test/doc/src/write_test_chapter.xml +++ b/lib/common_test/doc/src/write_test_chapter.xml @@ -68,7 +68,7 @@ <p>Each test suite module must export the function <c>all/0</c> which returns the list of all test case groups and test cases - in that module. + to be executed in that module. </p> </section> @@ -369,10 +369,12 @@ <title>Test suite info function</title> <p>The <c>suite/0</c> function can be used in a test suite - module to set the default values for the <c>timetrap</c> and - <c>require</c> tags. If a test case info function also specifies - any of these tags, the default value is overruled. See above for - more information. + module to e.g. set a default <c>timetrap</c> value and to + <c>require</c> external configuration data. If a test case-, or + group info function also specifies any of the info tags, it + overrides the default values set by <c>suite/0</c>. See the test + case info function above, and group info function below, for more + details. </p> <p>Other options that may be specified with the suite info list are:</p> @@ -450,11 +452,65 @@ <pre> all() -> [testcase1, {group,group1}, testcase2, {group,group2}].</pre> - <p>Properties may be combined so that e.g. if <c>shuffle</c>, - <c>repeat_until_any_fail</c> and <c>sequence</c> are all specified, the test - cases in the group will be executed repeatedly and in random order until - a test case fails, when execution is immediately stopped and the rest of - the cases skipped.</p> + <p>It is also possible to specify execution properties with a group + tuple in <c>all/0</c>: <c>{group,GroupName,Properties}</c>. These + properties will override those specified in the group definition (see + <c>groups/0</c> above). This way, it's possible to run the same set of tests, + but with different properties, without having to make copies of the group + definition in question.</p> + + <p>If a group contains sub-groups, the execution properties for these may + also be specified in the group tuple: + <c>{group,GroupName,Properties,SubGroups}</c>, where <c>SubGroups</c> + is a list of tuples, <c>{GroupName,Properties}</c>, or + <c>{GroupName,Properties,SubGroups}</c>, representing the sub-groups. + Any sub-groups defined in <c>group/0</c> for a group, that are not specified + in the <c>SubGroups</c> list, will simply execute with their pre-defined + properties.</p> + + <p>Example:</p> + <pre> + groups() -> {tests1, [], [{tests2, [], [t2a,t2b]}, + {tests3, [], [t31,t3b]}]}.</pre> + <p>To execute group 'tests1' twice with different properties for 'tests2' + each time:</p> + <pre> + all() -> + [{group, tests1, default, [{tests2, [parallel]}]}, + {group, tests1, default, [{tests2, [shuffle,{repeat,10}]}]}].</pre> + <p>Note that this is equivalent to this specification:</p> + <pre> + all() -> + [{group, tests1, default, [{tests2, [parallel]}, + {tests3, default}]}, + {group, tests1, default, [{tests2, [shuffle,{repeat,10}]}, + {tests3, default}]}].</pre> + <p>The value <c>default</c> states that the pre-defined properties + should be used.</p> + <p>Here's an example of how to override properties in a scenario + with deeply nested groups:</p> + <pre> + groups() -> + [{tests1, [], [{group, tests2}]}, + {tests2, [], [{group, tests3}]}, + {tests3, [{repeat,2}], [t3a,t3b,t3c]}]. + + all() -> + [{group, tests1, default, + [{tests2, default, + [{tests3, [parallel,{repeat,100}]}]}]}].</pre> + + <p>The syntax described above may also be used in Test Specifications + in order to change properties of groups at the time of execution, + without even having to edit the test suite (please see the + <seealso marker="run_test_chapter#test_specifications">Test + Specifications</seealso> chapter for more info).</p> + + <p>As illustrated above, properties may be combined. If e.g. + <c>shuffle</c>, <c>repeat_until_any_fail</c> and <c>sequence</c> + are all specified, the test cases in the group will be executed + repeatedly, and in random order, until a test case fails. Then + execution is immediately stopped and the rest of the cases skipped.</p> <p>Before execution of a group begins, the configuration function <c>init_per_group(GroupName, Config)</c> is called (the function is @@ -641,6 +697,51 @@ </section> <section> + <marker id="group_info"></marker> + <title>Group info function</title> + + <p>The test case group info function, <c>group(GroupName)</c>, + serves the same purpose as the suite- and test case info + functions previously described in this chapter. The scope for + the group info, however, is all test cases and sub-groups in the + group in question (<c>GroupName</c>).</p> + <p>Example:</p> + <pre> + group(connection_tests) -> + [{require,login_data}, + {timetrap,1000}].</pre> + + <p>The group info properties override those set with the + suite info function, and may in turn be overridden by test + case info properties. Please see the test case info + function above for a list of valid info properties and more + general information.</p> + </section> + + <section> + <title>Info functions for init- and end-configuration</title> + <p>It is possible to use info functions also for the <c>init_per_suite</c>, + <c>end_per_suite</c>, <c>init_per_group</c>, and <c>end_per_group</c> + functions, and it works the same way as with info functions + for test cases (see above). This is useful e.g. for setting + timetraps and requiring external configuration data relevant + only for the configuration function in question (without + affecting properties set for groups and test cases in the suite).</p> + + <p>The info function <c>init/end_per_suite()</c> is called for + <c>init/end_per_suite(Config)</c>, and info function + <c>init/end_per_group(GroupName)</c> is called for + <c>init/end_per_group(GroupName,Config)</c>. Info functions + can not be used with <c>init/end_per_testcase(TestCase, Config)</c>, + however, since these configuration functions execute on the test case process + and will use the same properties as the test case (i.e. the properties + set by the test case info function, <c>TestCase()</c>). Please see the test case + info function above for a list of valid info properties and more + general information. + </p> + </section> + + <section> <marker id="data_priv_dir"></marker> <title>Data and Private Directories</title> diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml index 522c1dc411..0f8abf1ccf 100644 --- a/lib/compiler/doc/src/compile.xml +++ b/lib/compiler/doc/src/compile.xml @@ -333,7 +333,7 @@ module.beam: module.erl \ <tag><c>{d,Macro,Value}</c></tag> <item> <p>Defines a macro <c>Macro</c> to have the value - <c>Value</c>. The default is <c>true</c>).</p> + <c>Value</c>. The default is <c>true</c>.</p> </item> <tag><c>{parse_transform,Module}</c></tag> diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml index 740cbcf8eb..3f53a71764 100644 --- a/lib/compiler/doc/src/notes.xml +++ b/lib/compiler/doc/src/notes.xml @@ -31,6 +31,105 @@ <p>This document describes the changes made to the Compiler application.</p> +<section><title>Compiler 4.8</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Add '-callback' attributes in stdlib's behaviours</p> + <p> + Replace the behaviour_info(callbacks) export in stdlib's + behaviours with -callback' attributes for all the + callbacks. Update the documentation with information on + the callback attribute Automatically generate + 'behaviour_info' function from '-callback' attributes</p> + <p> + 'behaviour_info(callbacks)' is a special function that is + defined in a module which describes a behaviour and + returns a list of its callbacks.</p> + <p> + This function is now automatically generated using the + '-callback' specs. An error is returned by lint if user + defines both '-callback' attributes and the + behaviour_info/1 function. If no type info is needed for + a callback use a generic spec for it. Add '-callback' + attribute to language syntax</p> + <p> + Behaviours may define specs for their callbacks using the + familiar spec syntax, replacing the '-spec' keyword with + '-callback'. Simple lint checks are performed to ensure + that no callbacks are defined twice and all types + referred are declared.</p> + <p> + These attributes can be then used by tools to provide + documentation to the behaviour or find discrepancies in + the callback definitions in the callback module.</p> + <p> + Add callback specs into 'application' module in kernel + Add callback specs to tftp module following internet + documentation Add callback specs to inets_service module + following possibly deprecated comments</p> + <p> + Own Id: OTP-9621</p> + </item> + <item> + <p> + The calculation of the 'uniq' value for a fun (see + <c>erlang:fun_info/1</c>) was too weak and has been + strengthened. It used to be based on the only the code + for the fun body, but it is now based on the MD5 of the + BEAM code for the module.</p> + <p> + Own Id: OTP-9667</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Variables are now now allowed in '<c>fun M:F/A</c>' as + suggested by Richard O'Keefe in EEP-23.</p> + <p>The representation of '<c>fun M:F/A</c>' in the + abstract format has been changed in an incompatible way. + Tools that directly read or manipulate the abstract + format (such as parse transforms) may need to be updated. + The compiler can handle both the new and the old format + (i.e. extracting the abstract format from a pre-R15 BEAM + file and compiling it using compile:forms/1,2 will work). + The <c>syntax_tools</c> application can also handle both + formats.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9643</p> + </item> + <item> + <p> + <c>filename:find_src/1,2</c> will now work on stripped + BEAM files (reported by Per Hedeland). The HiPE compiler + will also work on stripped BEAM files. The BEAM compiler + will no longer include compilation options given in the + source code itself in <c>M:module_info(compile)</c> + (because those options will be applied anyway if the + module is re-compiled).</p> + <p> + Own Id: OTP-9752</p> + </item> + <item> + <p>Inlining binary matching could cause an internal + compiler error. (Thanks to Rene Kijewski for reporting + this bug.)</p> + <p> + Own Id: OTP-9770</p> + </item> + </list> + </section> + +</section> + <section><title>Compiler 4.7.5</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/compiler/src/Makefile b/lib/compiler/src/Makefile index 7a237608ad..3415517fff 100644 --- a/lib/compiler/src/Makefile +++ b/lib/compiler/src/Makefile @@ -53,6 +53,7 @@ MODULES = \ beam_dead \ beam_dict \ beam_disasm \ + beam_except \ beam_flatten \ beam_jump \ beam_listing \ diff --git a/lib/compiler/src/beam_except.erl b/lib/compiler/src/beam_except.erl new file mode 100644 index 0000000000..fb1a43cd9e --- /dev/null +++ b/lib/compiler/src/beam_except.erl @@ -0,0 +1,149 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(beam_except). +-export([module/2]). + +%%% Rewrite certain calls to erlang:error/{1,2} to specialized +%%% instructions: +%%% +%%% erlang:error({badmatch,Value}) => badmatch Value +%%% erlang:error({case_clause,Value}) => case_end Value +%%% erlang:error({try_clause,Value}) => try_case_end Value +%%% erlang:error(if_clause) => if_end +%%% erlang:error(function_clause, Args) => jump FuncInfoLabel +%%% + +-import(lists, [reverse/1]). + +module({Mod,Exp,Attr,Fs0,Lc}, _Opt) -> + Fs = [function(F) || F <- Fs0], + {ok,{Mod,Exp,Attr,Fs,Lc}}. + +function({function,Name,Arity,CLabel,Is0}) -> + try + Is = function_1(Is0), + {function,Name,Arity,CLabel,Is} + catch + Class:Error -> + Stack = erlang:get_stacktrace(), + io:fwrite("Function: ~w/~w\n", [Name,Arity]), + erlang:raise(Class, Error, Stack) + end. + +-record(st, + {lbl, %func_info label + loc %location for func_info + }). + +function_1(Is0) -> + case Is0 of + [{label,Lbl},{line,Loc}|_] -> + St = #st{lbl=Lbl,loc=Loc}, + translate(Is0, St, []); + [{label,_}|_] -> + %% No line numbers. The source must be a .S file. + %% There is no need to do anything. + Is0 + end. + +translate([{call_ext,Ar,{extfunc,erlang,error,Ar}}=I|Is], St, Acc) -> + translate_1(Ar, I, Is, St, Acc); +translate([{call_ext_only,Ar,{extfunc,erlang,error,Ar}}=I|Is], St, Acc) -> + translate_1(Ar, I, Is, St, Acc); +translate([{call_ext_last,Ar,{extfunc,erlang,error,Ar},_}=I|Is], St, Acc) -> + translate_1(Ar, I, Is, St, Acc); +translate([I|Is], St, Acc) -> + translate(Is, St, [I|Acc]); +translate([], _, Acc) -> + reverse(Acc). + +translate_1(Ar, I, Is, St, [{line,_}=Line|Acc1]=Acc0) -> + case dig_out(Ar, Acc1) of + no -> + translate(Is, St, [I|Acc0]); + {yes,function_clause,Acc2} -> + case {Line,St} of + {{line,Loc},#st{lbl=Fi,loc=Loc}} -> + Instr = {jump,{f,Fi}}, + translate(Is, St, [Instr|Acc2]); + {_,_} -> + %% This must be "error(function_clause, Args)" in + %% the Erlang source code. Don't translate. + translate(Is, St, [I|Acc0]) + end; + {yes,Instr,Acc2} -> + translate(Is, St, [Instr,Line|Acc2]) + end. + +dig_out(Ar, [{kill,_}|Is]) -> + dig_out(Ar, Is); +dig_out(1, [{block,Bl0}|Is]) -> + case dig_out_block(reverse(Bl0)) of + no -> no; + {yes,What,[]} -> + {yes,What,Is}; + {yes,What,Bl} -> + {yes,What,[{block,Bl}|Is]} + end; +dig_out(2, [{block,Bl}|Is]) -> + case dig_out_block_fc(Bl) of + no -> no; + {yes,What} -> {yes,What,Is} + end; +dig_out(_, _) -> no. + +dig_out_block([{set,[{x,0}],[{atom,if_clause}],move}]) -> + {yes,if_end,[]}; +dig_out_block([{set,[{x,0}],[{literal,{Exc,Value}}],move}|Is]) -> + translate_exception(Exc, {literal,Value}, Is, 0); +dig_out_block([{set,[{x,0}],[Tuple],move}, + {set,[],[Value],put}, + {set,[],[{atom,Exc}],put}, + {set,[Tuple],[],{put_tuple,2}}|Is]) -> + translate_exception(Exc, Value, Is, 3); +dig_out_block([{set,[],[Value],put}, + {set,[],[{atom,Exc}],put}, + {set,[{x,0}],[],{put_tuple,2}}|Is]) -> + translate_exception(Exc, Value, Is, 3); +dig_out_block(_) -> no. + +translate_exception(badmatch, Val, Is, Words) -> + {yes,{badmatch,Val},fix_block(Is, Words)}; +translate_exception(case_clause, Val, Is, Words) -> + {yes,{case_end,Val},fix_block(Is, Words)}; +translate_exception(try_clause, Val, Is, Words) -> + {yes,{try_case_end,Val},fix_block(Is, Words)}; +translate_exception(_, _, _, _) -> no. + +fix_block(Is, 0) -> + reverse(Is); +fix_block(Is0, Words) -> + [{set,[],[],{alloc,Live,{F1,F2,Needed,F3}}}|Is] = reverse(Is0), + [{set,[],[],{alloc,Live,{F1,F2,Needed-Words,F3}}}|Is]. + +dig_out_block_fc([{set,[],[],{alloc,Live,_}}|Bl]) -> + dig_out_fc(Bl, Live-1, nil); +dig_out_block_fc(_) -> no. + +dig_out_fc([{set,[Dst],[{x,Reg},Dst0],put_list}|Is], Reg, Dst0) -> + dig_out_fc(Is, Reg-1, Dst); +dig_out_fc([{set,[{x,0}],[{atom,function_clause}],move}], -1, {x,1}) -> + {yes,function_clause}; +dig_out_fc(_, _, _) -> no. diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl index a631b8cd69..116ede0bc9 100644 --- a/lib/compiler/src/beam_utils.erl +++ b/lib/compiler/src/beam_utils.erl @@ -474,8 +474,15 @@ check_liveness(R, [{make_fun2,_,_,_,NumFree}|Is], St) -> end; check_liveness(R, [{try_end,Y}|Is], St) -> case R of - Y -> {killed,St}; - _ -> check_liveness(R, Is, St) + Y -> + {killed,St}; + {y,_} -> + %% y registers will be used if an exception occurs and + %% control transfers to the label given in the previous + %% try/2 instruction. + {used,St}; + _ -> + check_liveness(R, Is, St) end; check_liveness(R, [{catch_end,Y}|Is], St) -> case R of diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl index a17a10046e..9b505ad15c 100644 --- a/lib/compiler/src/compile.erl +++ b/lib/compiler/src/compile.erl @@ -629,6 +629,8 @@ asm_passes() -> [{unless,no_postopt, [{pass,beam_block}, {iff,dblk,{listing,"block"}}, + {unless,no_except,{pass,beam_except}}, + {iff,dexcept,{listing,"except"}}, {unless,no_bopt,{pass,beam_bool}}, {iff,dbool,{listing,"bool"}}, {unless,no_topt,{pass,beam_type}}, diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src index fb06f2521c..1133882728 100644 --- a/lib/compiler/src/compiler.app.src +++ b/lib/compiler/src/compiler.app.src @@ -28,6 +28,7 @@ beam_dead, beam_dict, beam_disasm, + beam_except, beam_flatten, beam_jump, beam_listing, diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index 6ea67741fa..5b155398dc 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -2641,9 +2641,9 @@ bsm_leftmost_2([_|Ps], Cs, N, Pos) -> bsm_leftmost_2([], Cs, _, Pos) -> bsm_leftmost_1(Cs, Pos). -%% bsm_notempty(Cs, Pos) -> true|false +%% bsm_nonempty(Cs, Pos) -> true|false %% Check if at least one of the clauses matches a non-empty -%% binary in the given argumet position. +%% binary in the given argument position. %% bsm_nonempty([#c_clause{pats=Ps}|Cs], Pos) -> case nth(Pos, Ps) of @@ -2704,7 +2704,7 @@ bsm_ensure_no_partition_2([P|_], 1, _, Vstate, State) -> %% %% But if the clauses can't be freely rearranged, as in %% - %% b(Var, <<>>) -> ... + %% b(Var, <<X>>) -> ... %% b(1, 2) -> ... %% %% we do have a problem. diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl index e7dae67085..6623485609 100644 --- a/lib/compiler/src/v3_codegen.erl +++ b/lib/compiler/src/v3_codegen.erl @@ -53,7 +53,6 @@ %% Main codegen structure. -record(cg, {lcount=1, %Label counter - finfo, %Function info label bfail, %Fail label for BIFs break, %Break label recv, %Receive label @@ -126,7 +125,6 @@ cg_fun(Les, Hvs, Vdb, AtomMod, NameArity, Anno, St0) -> stk=[]}, 0, Vdb), {B,_Aft,St} = cg_list(Les, 0, Vdb, Bef, St3#cg{bfail=0, - finfo=Fi, ultimate_failure=UltimateMatchFail, is_top_block=true}), {Name,Arity} = NameArity, @@ -147,8 +145,6 @@ cg({match,M,Rs}, Le, Vdb, Bef, St) -> match_cg(M, Rs, Le, Vdb, Bef, St); cg({guard_match,M,Rs}, Le, Vdb, Bef, St) -> guard_match_cg(M, Rs, Le, Vdb, Bef, St); -cg({match_fail,F}, Le, Vdb, Bef, St) -> - match_fail_cg(F, Le, Vdb, Bef, St); cg({call,Func,As,Rs}, Le, Vdb, Bef, St) -> call_cg(Func, As, Rs, Le, Vdb, Bef, St); cg({enter,Func,As}, Le, Vdb, Bef, St) -> @@ -294,39 +290,6 @@ match_cg({block,Es}, Le, _Fail, Bef, St) -> Int = clear_dead(Bef, Le#l.i, Le#l.vdb), block_cg(Es, Le, Int, St). -%% match_fail_cg(FailReason, Le, Vdb, StackReg, State) -> -%% {[Ainstr],StackReg,State}. -%% Generate code for the match_fail "call". N.B. there is no generic -%% case for when the fail value has been created elsewhere. - -match_fail_cg({function_clause,As}, Le, Vdb, Bef, St) -> - %% Must have the args in {x,0}, {x,1},... - {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb), - {Sis ++ [{jump,{f,St#cg.finfo}}], - Int#sr{reg=clear_regs(Int#sr.reg)},St}; -match_fail_cg({badmatch,Term}, Le, Vdb, Bef, St) -> - R = cg_reg_arg(Term, Bef), - Int0 = clear_dead(Bef, Le#l.i, Vdb), - {Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb), - {Sis ++ [line(Le),{badmatch,R}], - Int#sr{reg=clear_regs(Int0#sr.reg)},St}; -match_fail_cg({case_clause,Reason}, Le, Vdb, Bef, St) -> - R = cg_reg_arg(Reason, Bef), - Int0 = clear_dead(Bef, Le#l.i, Vdb), - {Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb), - {Sis++[line(Le),{case_end,R}], - Int#sr{reg=clear_regs(Bef#sr.reg)},St}; -match_fail_cg(if_clause, Le, Vdb, Bef, St) -> - Int0 = clear_dead(Bef, Le#l.i, Vdb), - {Sis,Int1} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb), - {Sis++[line(Le),if_end],Int1#sr{reg=clear_regs(Int1#sr.reg)},St}; -match_fail_cg({try_clause,Reason}, Le, Vdb, Bef, St) -> - R = cg_reg_arg(Reason, Bef), - Int0 = clear_dead(Bef, Le#l.i, Vdb), - {Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb), - {Sis ++ [line(Le),{try_case_end,R}], - Int#sr{reg=clear_regs(Int0#sr.reg)},St}. - %% bsm_rename_ctx([Clause], Var) -> [Clause] %% We know from an annotation that the register for a binary can %% be reused for the match context because the two are not truly diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl index d76291f57f..f2eaa37617 100644 --- a/lib/compiler/src/v3_kernel.erl +++ b/lib/compiler/src/v3_kernel.erl @@ -83,6 +83,7 @@ -import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,splitwith/2,member/2, keymember/3,keyfind/3]). -import(ordsets, [add_element/2,del_element/2,union/2,union/1,subtract/2]). +-import(cerl, [c_tuple/1]). -include("core_parse.hrl"). -include("v3_kernel.hrl"). @@ -422,10 +423,11 @@ expr(#c_call{anno=A,module=M0,name=F0,args=Cargs}, Sub, St0) -> end; expr(#c_primop{anno=A,name=#c_literal{val=match_fail},args=Cargs0}, Sub, St0) -> Cargs = translate_match_fail(Cargs0, Sub, A, St0), - %% This special case will disappear. {Kargs,Ap,St} = atomic_list(Cargs, Sub, St0), Ar = length(Cargs), - Call = #k_call{anno=A,op=#k_internal{name=match_fail,arity=Ar},args=Kargs}, + Call = #k_call{anno=A,op=#k_remote{mod=#k_atom{val=erlang}, + name=#k_atom{val=error}, + arity=Ar},args=Kargs}, {Call,Ap,St}; expr(#c_primop{anno=A,name=#c_literal{val=N},args=Cargs}, Sub, St0) -> {Kargs,Ap,St1} = atomic_list(Cargs, Sub, St0), @@ -455,14 +457,14 @@ expr(#ireceive_accept{anno=A}, _Sub, St) -> {#k_receive_accept{anno=A},[],St}. translate_match_fail(Args, Sub, Anno, St) -> case Args of [#c_tuple{es=[#c_literal{val=function_clause}|As]}] -> - translate_match_fail_1(Anno, Args, As, Sub, St); + translate_match_fail_1(Anno, As, Sub, St); [#c_literal{val=Tuple}] when is_tuple(Tuple) -> %% The inliner may have created a literal out of %% the original #c_tuple{}. case tuple_to_list(Tuple) of [function_clause|As0] -> As = [#c_literal{val=E} || E <- As0], - translate_match_fail_1(Anno, Args, As, Sub, St); + translate_match_fail_1(Anno, As, Sub, St); _ -> Args end; @@ -471,7 +473,7 @@ translate_match_fail(Args, Sub, Anno, St) -> Args end. -translate_match_fail_1(Anno, Args, As, Sub, #kern{ff=FF}) -> +translate_match_fail_1(Anno, As, Sub, #kern{ff=FF}) -> AnnoFunc = case keyfind(function_name, 1, Anno) of false -> none; %Force rewrite. @@ -481,10 +483,10 @@ translate_match_fail_1(Anno, Args, As, Sub, #kern{ff=FF}) -> case {AnnoFunc,FF} of {Same,Same} -> %% Still in the correct function. - Args; + translate_fc(As); {{F,_},F} -> %% Still in the correct function. - Args; + translate_fc(As); _ -> %% Wrong function or no function_name annotation. %% @@ -493,9 +495,12 @@ translate_match_fail_1(Anno, Args, As, Sub, #kern{ff=FF}) -> %% the current function). match_fail(function_clause) will %% only work at the top level of the function it was originally %% defined in, so we will need to rewrite it to a case_clause. - [#c_tuple{es=[#c_literal{val=case_clause},#c_tuple{es=As}]}] + [c_tuple([#c_literal{val=case_clause},c_tuple(As)])] end. +translate_fc(Args) -> + [#c_literal{val=function_clause},make_list(Args)]. + %% call_type(Module, Function, Arity) -> call | bif | apply | error. %% Classify the call. call_type(#c_literal{val=M}, #c_literal{val=F}, Ar) when is_atom(M), is_atom(F) -> @@ -1494,7 +1499,6 @@ iletrec_funs_gen(Fs, FreeVs, St) -> %% is_exit_expr(Kexpr) -> boolean(). %% Test whether Kexpr always exits and never returns. -is_exit_expr(#k_call{op=#k_internal{name=match_fail,arity=1}}) -> true; is_exit_expr(#k_receive_next{}) -> true; is_exit_expr(_) -> false. diff --git a/lib/compiler/src/v3_life.erl b/lib/compiler/src/v3_life.erl index fac9a9843d..93f8034230 100644 --- a/lib/compiler/src/v3_life.erl +++ b/lib/compiler/src/v3_life.erl @@ -89,19 +89,8 @@ function(#k_fdef{anno=#k{a=Anno},func=F,arity=Ar,vars=Vs,body=Kb}) -> end. %% body(Kbody, I, Vdb) -> {[Expr],MaxI,Vdb}. -%% Handle a body, need special cases for transforming match_fails. -%% We KNOW that they only occur last in a body. - -body(#k_seq{arg=#k_put{anno=Pa,arg=Arg,ret=[R]}, - body=#k_enter{anno=Ea,op=#k_internal{name=match_fail,arity=1}, - args=[R]}}, - I, Vdb0) -> - Vdb1 = use_vars(Pa#k.us, I, Vdb0), %All used here - {[match_fail(Arg, I, Pa#k.a ++ Ea#k.a)],I,Vdb1}; -body(#k_enter{anno=Ea,op=#k_internal{name=match_fail,arity=1},args=[Arg]}, - I, Vdb0) -> - Vdb1 = use_vars(Ea#k.us, I, Vdb0), - {[match_fail(Arg, I, Ea#k.a)],I,Vdb1}; +%% Handle a body. + body(#k_seq{arg=Ke,body=Kb}, I, Vdb0) -> %%ok = io:fwrite("life ~w:~p~n", [?LINE,{Ke,I,Vdb0}]), A = get_kanno(Ke), @@ -353,25 +342,6 @@ guard_clause(#k_guard_clause{anno=A,guard=Kg,body=Kb}, Ls, I, Ctxt, Vdb0) -> i=I,vdb=use_vars((get_kanno(Kg))#k.us, I+2, Vdb1), a=A#k.a}. -%% match_fail(FailValue, I, Anno) -> Expr. -%% Generate the correct match_fail instruction. N.B. there is no -%% generic case for when the fail value has been created elsewhere. - -match_fail(#k_literal{anno=Anno,val={Atom,Val}}, I, A) when is_atom(Atom) -> - match_fail(#k_tuple{anno=Anno,es=[#k_atom{val=Atom},#k_literal{val=Val}]}, I, A); -match_fail(#k_literal{anno=Anno,val={Atom}}, I, A) when is_atom(Atom) -> - match_fail(#k_tuple{anno=Anno,es=[#k_atom{val=Atom}]}, I, A); -match_fail(#k_tuple{es=[#k_atom{val=function_clause}|As]}, I, A) -> - #l{ke={match_fail,{function_clause,literal_list(As, [])}},i=I,a=A}; -match_fail(#k_tuple{es=[#k_atom{val=badmatch},Val]}, I, A) -> - #l{ke={match_fail,{badmatch,literal(Val, [])}},i=I,a=A}; -match_fail(#k_tuple{es=[#k_atom{val=case_clause},Val]}, I, A) -> - #l{ke={match_fail,{case_clause,literal(Val, [])}},i=I,a=A}; -match_fail(#k_atom{val=if_clause}, I, A) -> - #l{ke={match_fail,if_clause},i=I,a=A}; -match_fail(#k_tuple{es=[#k_atom{val=try_clause},Val]}, I, A) -> - #l{ke={match_fail,{try_clause,literal(Val, [])}},i=I,a=A}. - %% type(Ktype) -> Type. type(k_literal) -> literal; diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile index b90adaf917..e13ad4ae90 100644 --- a/lib/compiler/test/Makefile +++ b/lib/compiler/test/Makefile @@ -10,6 +10,7 @@ MODULES= \ apply_SUITE \ beam_validator_SUITE \ beam_disasm_SUITE \ + beam_expect_SUITE \ bs_bincomp_SUITE \ bs_bit_binaries_SUITE \ bs_construct_SUITE \ @@ -29,7 +30,6 @@ MODULES= \ misc_SUITE \ num_bif_SUITE \ pmod_SUITE \ - parteval_SUITE \ receive_SUITE \ record_SUITE \ trycatch_SUITE \ @@ -39,6 +39,7 @@ MODULES= \ NO_OPT= \ andor \ apply \ + beam_expect \ bs_construct \ bs_match \ bs_utf \ diff --git a/lib/compiler/test/beam_expect_SUITE.erl b/lib/compiler/test/beam_expect_SUITE.erl new file mode 100644 index 0000000000..6f216eac4f --- /dev/null +++ b/lib/compiler/test/beam_expect_SUITE.erl @@ -0,0 +1,67 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +-module(beam_expect_SUITE). + +-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, + init_per_group/2,end_per_group/2, + coverage/1]). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [coverage]. + +groups() -> + []. + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +coverage(_) -> + File = {file,"fake.erl"}, + ok = fc(a), + {'EXIT',{function_clause, + [{?MODULE,fc,[[x]],[File,{line,2}]}|_]}} = + (catch fc([x])), + {'EXIT',{function_clause, + [{?MODULE,fc,[y],[File,{line,2}]}|_]}} = + (catch fc(y)), + {'EXIT',{function_clause, + [{?MODULE,fc,[[a,b,c]],[File,{line,6}]}|_]}} = + (catch fc([a,b,c])), + + {'EXIT',{undef,[{erlang,error,[a,b,c],_}|_]}} = + (catch erlang:error(a, b, c)), + ok. + +-file("fake.erl", 1). +fc(a) -> %Line 2 + ok; %Line 3 +fc(L) when length(L) > 2 -> %Line 4 + %% Not the same as a "real" function_clause error. + error(function_clause, [L]). %Line 6 diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl index 556dc54a8f..902867bc19 100644 --- a/lib/compiler/test/beam_validator_SUITE.erl +++ b/lib/compiler/test/beam_validator_SUITE.erl @@ -79,21 +79,18 @@ beam_files(Config) when is_list(Config) -> %% a grammatical error in the output of the io:format/2 call below. ;-) ?line [_,_|_] = Fs = filelib:wildcard(Wc), ?line io:format("~p files\n", [length(Fs)]), - beam_files_1(Fs, 0). - -beam_files_1([F|Fs], Errors) -> - ?line case beam_validator:file(F) of - ok -> - beam_files_1(Fs, Errors); - {error,Es} -> - io:format("File: ~s", [F]), - io:format("Error: ~p\n", [Es]), - beam_files_1(Fs, Errors+1) - end; -beam_files_1([], 0) -> ok; -beam_files_1([], Errors) -> - ?line io:format("~p error(s)", [Errors]), - ?line ?t:fail(). + test_lib:p_run(fun do_beam_file/1, Fs). + + +do_beam_file(F) -> + case beam_validator:file(F) of + ok -> + ok; + {error,Es} -> + io:format("File: ~s", [F]), + io:format("Error: ~p\n", [Es]), + error + end. compiler_bug(Config) when is_list(Config) -> %% Check that the compiler returns an error if we try to diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl index f8c71a0257..01b7568122 100644 --- a/lib/compiler/test/bs_match_SUITE.erl +++ b/lib/compiler/test/bs_match_SUITE.erl @@ -342,6 +342,10 @@ partitioned_bs_match(Config) when is_list(Config) -> ?line fc(partitioned_bs_match_2, [4,<<0:17>>], catch partitioned_bs_match_2(4, <<0:17>>)), + + anything = partitioned_bs_match_3(anything, <<42>>), + ok = partitioned_bs_match_3(1, 2), + ok. partitioned_bs_match(_, <<42:8,T/binary>>) -> @@ -356,6 +360,9 @@ partitioned_bs_match_2(1, <<B:8,T/binary>>) -> partitioned_bs_match_2(Len, <<_:8,T/binary>>) -> {Len,T}. +partitioned_bs_match_3(Var, <<_>>) -> Var; +partitioned_bs_match_3(1, 2) -> ok. + function_clause(Config) when is_list(Config) -> ?line ok = function_clause_1(<<0,7,0,7,42>>), ?line fc(function_clause_1, [<<0,1,2,3>>], diff --git a/lib/compiler/test/compilation_SUITE.erl b/lib/compiler/test/compilation_SUITE.erl index 1343fbd1c9..664582a3a8 100644 --- a/lib/compiler/test/compilation_SUITE.erl +++ b/lib/compiler/test/compilation_SUITE.erl @@ -44,7 +44,7 @@ all() -> trycatch_4, opt_crash, otp_5404, otp_5436, otp_5481, otp_5553, otp_5632, otp_5714, otp_5872, otp_6121, otp_6121a, otp_6121b, otp_7202, otp_7345, on_load, - string_table,otp_8949_a,otp_8949_a]. + string_table,otp_8949_a,otp_8949_a,split_cases]. groups() -> [{vsn, [], [vsn_1, vsn_2, vsn_3]}]. @@ -427,9 +427,9 @@ self_compile_1(Config, Prefix, Opts) -> %% Compile the compiler again using the newly compiled compiler. %% (In another node because reloading the compiler would disturb cover.) CompilerB = Prefix++"compiler_b", - ?line CompB = make_compiler_dir(Priv, Prefix++"compiler_b"), + CompB = make_compiler_dir(Priv, CompilerB), ?line VsnB = VsnA ++ ".0", - ?line self_compile_node(CompilerB, CompA, CompB, VsnB, Opts), + self_compile_node(CompA, CompB, VsnB, Opts), %% Compare compiler directories. ?line compare_compilers(CompA, CompB), @@ -438,21 +438,26 @@ self_compile_1(Config, Prefix, Opts) -> ?line CompilerC = Prefix++"compiler_c", ?line CompC = make_compiler_dir(Priv, CompilerC), ?line VsnC = VsnB ++ ".0", - ?line self_compile_node(CompilerC, CompB, CompC, VsnC, Opts), + self_compile_node(CompB, CompC, VsnC, Opts), ?line compare_compilers(CompB, CompC), ?line test_server:timetrap_cancel(Dog), ok. -self_compile_node(NodeName0, CompilerDir, OutDir, Version, Opts) -> - ?line NodeName = list_to_atom(NodeName0), - ?line Dog = test_server:timetrap(test_server:minutes(10)), +self_compile_node(CompilerDir, OutDir, Version, Opts) -> + ?line Dog = test_server:timetrap(test_server:minutes(15)), ?line Pa = "-pa " ++ filename:dirname(code:which(?MODULE)) ++ " -pa " ++ CompilerDir, - ?line {ok,Node} = start_node(NodeName, Pa), ?line Files = compiler_src(), - ?line ok = rpc:call(Node, ?MODULE, compile_compiler, [Files,OutDir,Version,Opts]), - ?line test_server:stop_node(Node), + + %% We don't want the cover server started on the other node, + %% because it will load the same cover-compiled code as on this + %% node. Use a shielded node to prevent the cover server from + %% being started. + ?t:run_on_shielded_node( + fun() -> + compile_compiler(Files, OutDir, Version, Opts) + end, Pa), ?line test_server:timetrap_cancel(Dog), ok. @@ -465,9 +470,12 @@ compile_compiler(Files, OutDir, Version, InlineOpts) -> {d,'COMPILER_VSN',"\""++Version++"\""}, nowarn_shadow_vars, {i,filename:join(code:lib_dir(stdlib), "include")}|InlineOpts], - lists:foreach(fun(File) -> - {ok,_} = compile:file(File, Opts) - end, Files). + test_lib:p_run(fun(File) -> + case compile:file(File, Opts) of + {ok,_} -> ok; + _ -> error + end + end, Files). compiler_src() -> filelib:wildcard(filename:join([code:lib_dir(compiler), "src", "*.erl"])). @@ -657,5 +665,19 @@ otp_8949_b(A, B) -> id(Var) end. +split_cases(_) -> + dummy1 = do_split_cases(x), + {'EXIT',{{badmatch,b},_}} = (catch do_split_cases(y)), + ok. + +do_split_cases(A) -> + case A of + x -> + Z = dummy1; + _ -> + Z = dummy2, + a=b + end, + Z. id(I) -> I. diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl index fedbd98f71..640849f2ec 100644 --- a/lib/compiler/test/compile_SUITE.erl +++ b/lib/compiler/test/compile_SUITE.erl @@ -29,7 +29,8 @@ binary/1, makedep/1, cond_and_ifdef/1, listings/1, listings_big/1, other_output/1, package_forms/1, encrypted_abstr/1, bad_record_use1/1, bad_record_use2/1, strict_record/1, - missing_testheap/1, cover/1, env/1, core/1, asm/1]). + missing_testheap/1, cover/1, env/1, core/1, asm/1, + sys_pre_attributes/1]). -export([init/3]). @@ -45,7 +46,8 @@ all() -> binary, makedep, cond_and_ifdef, listings, listings_big, other_output, package_forms, encrypted_abstr, {group, bad_record_use}, strict_record, - missing_testheap, cover, env, core, asm]. + missing_testheap, cover, env, core, asm, + sys_pre_attributes]. groups() -> [{bad_record_use, [], @@ -785,6 +787,37 @@ do_asm(Beam, Outdir) -> error end. +sys_pre_attributes(Config) -> + DataDir = ?config(data_dir, Config), + File = filename:join(DataDir, "attributes.erl"), + Mod = attributes, + CommonOpts = [binary,report,verbose, + {parse_transform,sys_pre_attributes}], + PreOpts = [{attribute,delete,deleted}], + PostOpts = [{attribute,insert,inserted,"value"}], + PrePostOpts = [{attribute,replace,replaced,42}, + {attribute,replace,replace_nonexisting,new}], + {ok,Mod,Code} = compile:file(File, PrePostOpts ++ PreOpts ++ + PostOpts ++ CommonOpts), + code:load_binary(Mod, File, Code), + Attr = Mod:module_info(attributes), + io:format("~p", [Attr]), + {inserted,"value"} = lists:keyfind(inserted, 1, Attr), + {replaced,[42]} = lists:keyfind(replaced, 1, Attr), + {replace_nonexisting,[new]} = lists:keyfind(replace_nonexisting, 1, Attr), + false = lists:keymember(deleted, 1, Attr), + + %% Cover more code. + {ok,Mod,_} = compile:file(File, PostOpts ++ CommonOpts), + {ok,Mod,_} = compile:file(File, CommonOpts -- [verbose]), + {ok,Mod,_} = compile:file(File, PreOpts ++ CommonOpts), + {ok,Mod,_} = compile:file(File, + [{attribute,replace,replaced,42}|CommonOpts]), + {ok,Mod,_} = compile:file(File, PrePostOpts ++ PreOpts ++ + PostOpts ++ CommonOpts -- + [report,verbose]), + ok. + %%% %%% Utilities. %%% diff --git a/lib/compiler/test/compile_SUITE_data/attributes.erl b/lib/compiler/test/compile_SUITE_data/attributes.erl new file mode 100644 index 0000000000..9c3451d272 --- /dev/null +++ b/lib/compiler/test/compile_SUITE_data/attributes.erl @@ -0,0 +1,23 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(attributes). +-deleted(dummy). +-replaced(dummy). + diff --git a/lib/compiler/test/compiler.cover b/lib/compiler/test/compiler.cover index 9fc4c7dd43..3fd7fc1937 100644 --- a/lib/compiler/test/compiler.cover +++ b/lib/compiler/test/compiler.cover @@ -1,5 +1,5 @@ {incl_app,compiler,details}. %% -*- erlang -*- -{excl_mods,[sys_pre_attributes,core_scan,core_parse]}. +{excl_mods,compiler,[core_scan,core_parse]}. diff --git a/lib/compiler/test/core_SUITE.erl b/lib/compiler/test/core_SUITE.erl index 26173c62b8..874e02803d 100644 --- a/lib/compiler/test/core_SUITE.erl +++ b/lib/compiler/test/core_SUITE.erl @@ -21,7 +21,9 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2,end_per_testcase/2, - dehydrated_itracer/1,nested_tries/1]). + dehydrated_itracer/1,nested_tries/1, + make_effect_seq/1,eval_is_boolean/1, + unsafe_case/1,nomatch_shadow/1,reversed_annos/1]). -include_lib("test_server/include/test_server.hrl"). @@ -41,7 +43,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> test_lib:recompile(?MODULE), - [dehydrated_itracer, nested_tries]. + [dehydrated_itracer,nested_tries,make_effect_seq, + eval_is_boolean,unsafe_case,nomatch_shadow,reversed_annos]. groups() -> []. @@ -61,19 +64,18 @@ end_per_group(_GroupName, Config) -> ?comp(dehydrated_itracer). ?comp(nested_tries). +?comp(make_effect_seq). +?comp(eval_is_boolean). +?comp(unsafe_case). +?comp(nomatch_shadow). +?comp(reversed_annos). try_it(Mod, Conf) -> - ?line Src = filename:join(?config(data_dir, Conf), atom_to_list(Mod)), - ?line Out = ?config(priv_dir,Conf), - ?line io:format("Compiling: ~s\n", [Src]), - ?line CompRc0 = compile:file(Src, [from_core,{outdir,Out},report,time]), - ?line io:format("Result: ~p\n",[CompRc0]), - ?line {ok,Mod} = CompRc0, - - ?line {module,Mod} = code:load_abs(filename:join(Out, Mod)), - ?line ok = Mod:Mod(), - ok. - - - - + Src = filename:join(?config(data_dir, Conf), atom_to_list(Mod)), + compile_and_load(Src, []), + compile_and_load(Src, [no_copt]). + +compile_and_load(Src, Opts) -> + {ok,Mod,Bin} = compile:file(Src, [from_core,report,time,binary|Opts]), + {module,Mod} = code:load_binary(Mod, Mod, Bin), + ok = Mod:Mod(). diff --git a/lib/compiler/test/core_SUITE_data/eval_is_boolean.core b/lib/compiler/test/core_SUITE_data/eval_is_boolean.core new file mode 100644 index 0000000000..6a68b1414d --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/eval_is_boolean.core @@ -0,0 +1,22 @@ +module 'eval_is_boolean' ['eval_is_boolean'/0] + attributes [] +'eval_is_boolean'/0 = + %% Line 4 + fun () -> + case <> of + <> when 'true' -> + case call 'erlang':'is_boolean'(call 'erlang':'make_ref'()) of + <'false'> when 'true' -> + 'ok' + ( <_cor1> when 'true' -> + primop 'match_fail' + ({'badmatch',_cor1}) + -| ['compiler_generated'] ) + end + ( <> when 'true' -> + ( primop 'match_fail' + ({'function_clause'}) + -| [{'function_name',{'eval_is_boolean',0}}] ) + -| ['compiler_generated'] ) + end +end diff --git a/lib/compiler/test/core_SUITE_data/make_effect_seq.core b/lib/compiler/test/core_SUITE_data/make_effect_seq.core new file mode 100644 index 0000000000..9941e63b76 --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/make_effect_seq.core @@ -0,0 +1,51 @@ +module 'make_effect_seq' ['make_effect_seq'/0] + attributes [] +'make_effect_seq'/0 = + fun () -> + case <> of + <> when 'true' -> + let <_cor0> = + catch + apply 't'/1 + ('a') + in + case _cor0 of + <{'EXIT',{'badarg',_cor3}}> when 'true' -> + let <_cor4> = + apply 't'/1 + ({'a','b','c'}) + in + case _cor4 of + <'ok'> when 'true' -> + ( _cor4 + -| ['compiler_generated'] ) + ( <_cor2> when 'true' -> + primop 'match_fail' + ({'badmatch',_cor2}) + -| ['compiler_generated'] ) + end + ( <_cor1> when 'true' -> + primop 'match_fail' + ({'badmatch',_cor1}) + -| ['compiler_generated'] ) + end + ( <> when 'true' -> + ( primop 'match_fail' + ({'function_clause'}) + -| [{'function_name',{'make_effect_seq',0}}] ) + -| ['compiler_generated'] ) + end +'t'/1 = + fun (_cor0) -> + case _cor0 of + <T> when 'true' -> + do + {'ok',call 'erlang':'element'(2, T)} + 'ok' + ( <_cor2> when 'true' -> + ( primop 'match_fail' + ({'function_clause',_cor2}) + -| [{'function_name',{'t',1}}] ) + -| ['compiler_generated'] ) + end +end diff --git a/lib/compiler/test/core_SUITE_data/nomatch_shadow.core b/lib/compiler/test/core_SUITE_data/nomatch_shadow.core new file mode 100644 index 0000000000..565d9dc0f3 --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/nomatch_shadow.core @@ -0,0 +1,28 @@ +module 'nomatch_shadow' ['nomatch_shadow'/0] + attributes [] +'nomatch_shadow'/0 = + fun () -> + case <> of + <> when 'true' -> + apply 't'/1 + (42) + ( <> when 'true' -> + ( primop 'match_fail' + ({'function_clause'}) + -| [{'function_name',{'nomatch_shadow',0}}] ) + -| ['compiler_generated'] ) + end +'t'/1 = + fun (_cor0) -> + case _cor0 of + <42> when 'true' -> + 'ok' + <42> when 'true' -> + 'ok' + ( <_cor1> when 'true' -> + ( primop 'match_fail' + ({'function_clause',_cor1}) + -| [{'function_name',{'t',1}}] ) + -| ['compiler_generated'] ) + end +end diff --git a/lib/compiler/test/core_SUITE_data/reversed_annos.core b/lib/compiler/test/core_SUITE_data/reversed_annos.core new file mode 100644 index 0000000000..95b3cd52d6 --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/reversed_annos.core @@ -0,0 +1,49 @@ +module 'reversed_annos' ['reversed_annos'/0] + attributes [] +'reversed_annos'/0 = + fun () -> + case <> of + <> when 'true' -> + case apply 't'/1 + (['a']) of + <'ok'> when 'true' -> + let <_cor2> = + apply 't'/1 + (['a'|['b']]) + in + case _cor2 of + <'ok'> when 'true' -> + ( _cor2 + -| ['compiler_generated'] ) + ( <_cor1> when 'true' -> + primop 'match_fail' + ({'badmatch',_cor1}) + -| ['compiler_generated'] ) + end + ( <_cor0> when 'true' -> + primop 'match_fail' + ({'badmatch',_cor0}) + -| ['compiler_generated'] ) + end + ( <> when 'true' -> + ( primop 'match_fail' + ({'function_clause'}) + -| [{'function_name',{'reversed_annos',0}}] ) + -| ['compiler_generated'] ) + end +'t'/1 = + fun (_cor0) -> + case _cor0 of + <[_cor2|_cor3]> when 'true' -> + 'ok' + %% Cover v3_kernel:get_line/1. + ( <['a']> when 'true' -> + 'error' + -| [{'file',"reversed_annos.erl"},11] ) + ( <_cor1> when 'true' -> + ( primop 'match_fail' + ({'function_clause',_cor1}) + -| [{'function_name',{'t',1}}] ) + -| ['compiler_generated'] ) + end +end diff --git a/lib/compiler/test/core_SUITE_data/unsafe_case.core b/lib/compiler/test/core_SUITE_data/unsafe_case.core new file mode 100644 index 0000000000..84cb2c310a --- /dev/null +++ b/lib/compiler/test/core_SUITE_data/unsafe_case.core @@ -0,0 +1,25 @@ +module 'unsafe_case' ['unsafe_case'/0] + attributes [] +'unsafe_case'/0 = + fun () -> + case apply 't'/1 + (42) of + <{'ok',42}> when 'true' -> + 'ok' + ( <_cor0> when 'true' -> + primop 'match_fail' + ({'badmatch',_cor0}) + -| ['compiler_generated'] ) + end +'t'/1 = + fun (_cor0) -> + case _cor0 of + <X> + when call 'erlang':'>' + (_cor0, + 0) -> + {'ok',X} + %% The default case is intentionally missing + %% to cover v3_kernel:build_match/2. + end +end diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl index ac14d36e82..fb5ec88c9f 100644 --- a/lib/compiler/test/core_fold_SUITE.erl +++ b/lib/compiler/test/core_fold_SUITE.erl @@ -214,6 +214,7 @@ coverage(Config) when is_list(Config) -> (catch cover_will_match_list_type({a,b,c,d})), ?line a = cover_remove_non_vars_alias({a,b,c}), ?line error = cover_will_match_lit_list(), + {ok,[a]} = cover_is_safe_bool_expr(a), %% Make sure that we don't attempt to make literals %% out of pids. (Putting a pid into a #c_literal{} @@ -249,4 +250,17 @@ cover_will_match_lit_list() -> error end. +cover_is_safe_bool_expr(X) -> + %% Use a try...catch that looks like a try...catch in a guard. + try + %% let V = [X] in {ok,V} + %% is_safe_simple([X]) ==> true + %% is_safe_bool_expr([X]) ==> false + V = [X], + {ok,V} + catch + _:_ -> + false + end. + id(I) -> I. diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl index 9b414cade6..5e13a93c52 100644 --- a/lib/compiler/test/misc_SUITE.erl +++ b/lib/compiler/test/misc_SUITE.erl @@ -190,6 +190,15 @@ silly_coverage(Config) when is_list(Config) -> {label,2}|non_proper_list]}],99}, ?line expect_error(fun() -> beam_block:module(BlockInput, []) end), + %% beam_except + ExceptInput = {?MODULE,[{foo,0}],[], + [{function,foo,0,2, + [{label,1}, + {line,loc}, + {func_info,{atom,?MODULE},{atom,foo},0}, + {label,2}|non_proper_list]}],99}, + expect_error(fun() -> beam_except:module(ExceptInput, []) end), + %% beam_bool BoolInput = {?MODULE,[{foo,0}],[], [{function,foo,0,2, @@ -253,8 +262,15 @@ expect_error(Fun) -> io:format("~p", [Any]), ?t:fail(call_was_supposed_to_fail) catch - _:_ -> - io:format("~p\n", [erlang:get_stacktrace()]) + Class:Reason -> + Stk = erlang:get_stacktrace(), + io:format("~p:~p\n~p\n", [Class,Reason,Stk]), + case {Class,Reason} of + {error,undef} -> + ?t:fail(not_supposed_to_fail_with_undef); + {_,_} -> + ok + end end. confused_literals(Config) when is_list(Config) -> diff --git a/lib/compiler/test/parteval_SUITE.erl b/lib/compiler/test/parteval_SUITE.erl deleted file mode 100644 index 6b1ae38c1b..0000000000 --- a/lib/compiler/test/parteval_SUITE.erl +++ /dev/null @@ -1,66 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1998-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% --module(parteval_SUITE). - --include_lib("test_server/include/test_server.hrl"). - --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, pe2/1]). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [pe2]. - -groups() -> - []. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%% (This is more general than needed, since we once compiled the same -%% source code with and without a certain option.) -compile_and_load(Srcname, Outdir, Module, Options) -> - ?line Objname = filename:join(Outdir, "t1") ++ code:objfile_extension(), - ?line {ok, Module} = - compile:file(Srcname, - [{d, 'M', Module}, {outdir, Outdir}] ++ Options), - ?line {ok, B} = file:read_file(Objname), - ?line {module, Module} = code:load_binary(Module, Objname, B), - B. - -pe2(Config) when is_list(Config) -> - ?line DataDir = ?config(data_dir, Config), - ?line PrivDir = ?config(priv_dir, Config), - ?line Srcname = filename:join(DataDir, "t1.erl"), - ?line compile_and_load(Srcname, PrivDir, t1, []), - - ?line {Correct, Actual} = t1:run(), - ?line Correct = Actual, - ok. diff --git a/lib/compiler/test/parteval_SUITE_data/t1.erl b/lib/compiler/test/parteval_SUITE_data/t1.erl deleted file mode 100644 index 5e4a40f103..0000000000 --- a/lib/compiler/test/parteval_SUITE_data/t1.erl +++ /dev/null @@ -1,140 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% --module(?M). - --compile(export_all). - -%%% The arity-0 functions are all called from the test suite. - -f2() -> - size({1,2}). - -i() -> - case [] of - [] -> - ok; - X -> - hopp - end. - -e() -> - case 4+5 of -% X when X>10 -> kvock; % not removed by BEAM opt. - {X,X} when list(X) -> - kvack; - 9 -> - ok; - _ -> - ko - end. - -f() -> - element(2,{a,b,c,d}), - erlang:element(2,{a,b,c,d}), - "hej" ++ "hopp". - -g(X) -> - if - float(3.4) -> - hej; - X == 5, 4==4 -> - japp; - 4 == 4, size({1,2}) == 1 -> - ok - end. - -g() -> - {g(3),g(5)}. - -bliff() -> - if - 3==4 -> - himm - end. - -fi() -> - case 4 of - X when 4==3 -> - {X}; - 4 -> - 4; - _ -> - ok - end. - -iff() when 3==2 -> - if - 3 == 4 -> - baff; - 3 == 3 -> - nipp - end. - -sleep(I) -> receive after I -> ok end. - -sleep() -> - sleep(45). - -s() -> - case 4 of - 3 -> - ok - end. - -error_reason(R) when atom(R) -> - R; -error_reason(R) when tuple(R) -> - error_reason(element(1, R)). - -plusplus() -> - ?MODULE ++ " -> mindre snygg felhantering". - -call_it(F) -> - case (catch apply(?MODULE, F, [])) of - {'EXIT', R0} -> - {'EXIT', error_reason(R0)}; - V -> - V - end. - -run() -> - L = [{f2, 2}, - {i, ok}, - {e, ok}, - {f, "hejhopp"}, - {g, {hej, hej}}, - {bliff, {'EXIT', if_clause}}, - {fi, 4}, - {iff, {'EXIT', function_clause}}, - {sleep, ok}, - {s, {'EXIT', case_clause}, - {plusplus, {'EXIT', badarg}}}], - Actual = [call_it(F) || {F, _} <- L], - Correct = [C || {_, C} <- L], - {Correct, Actual}. - - -%%% Don't call, only compile. -t(A) -> - receive - A when 1==2 -> - ok; - B -> - B - end. diff --git a/lib/compiler/test/test_lib.erl b/lib/compiler/test/test_lib.erl index 53d8c04169..2295592a38 100644 --- a/lib/compiler/test/test_lib.erl +++ b/lib/compiler/test/test_lib.erl @@ -77,7 +77,14 @@ get_data_dir(Config) -> %% Will fail the test case if there were any errors. p_run(Test, List) -> - N = erlang:system_info(schedulers) + 1, + N = case ?t:is_cover() of + false -> + erlang:system_info(schedulers); + true -> + %% Cover is running. Using more than one process + %% will probably only slow down compilation. + 1 + end, p_run_loop(Test, List, N, [], 0, 0). p_run_loop(_, [], _, [], Errors, Ws) -> diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl index 760cf17225..09a23724fe 100644 --- a/lib/compiler/test/trycatch_SUITE.erl +++ b/lib/compiler/test/trycatch_SUITE.erl @@ -24,7 +24,7 @@ catch_oops/1,after_oops/1,eclectic/1,rethrow/1, nested_of/1,nested_catch/1,nested_after/1, nested_horrid/1,last_call_optimization/1,bool/1, - plain_catch_coverage/1,andalso_orelse/1]). + plain_catch_coverage/1,andalso_orelse/1,get_in_try/1]). -include_lib("test_server/include/test_server.hrl"). @@ -35,7 +35,7 @@ all() -> [basic, lean_throw, try_of, try_after, catch_oops, after_oops, eclectic, rethrow, nested_of, nested_catch, nested_after, nested_horrid, last_call_optimization, - bool, plain_catch_coverage, andalso_orelse]. + bool, plain_catch_coverage, andalso_orelse, get_in_try]. groups() -> []. @@ -928,3 +928,17 @@ andalso_orelse_2({Type,Keyval}) -> zero() -> 0.0. + +get_in_try(_) -> + undefined = get_valid_line([a], []), + ok. + +get_valid_line([_|T]=Path, Annotations) -> + try + get(Path) + %% beam_dead used to optimize away an assignment to {y,1} + %% because it didn't appear to be used. + catch + _:not_found -> + get_valid_line(T, Annotations) + end. diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk index 04290c0a7f..416c2f08bb 100644 --- a/lib/compiler/vsn.mk +++ b/lib/compiler/vsn.mk @@ -1 +1 @@ -COMPILER_VSN = 4.7.5 +COMPILER_VSN = 4.8 diff --git a/lib/cosEvent/doc/src/notes.xml b/lib/cosEvent/doc/src/notes.xml index 1da5399755..de98a44b6a 100644 --- a/lib/cosEvent/doc/src/notes.xml +++ b/lib/cosEvent/doc/src/notes.xml @@ -32,7 +32,25 @@ <file>notes.xml</file> </header> - <section> + <section><title>cosEvent 2.1.12</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + </list> + </section> + +</section> + +<section> <title>cosEvent 2.1.11</title> <section> diff --git a/lib/cosEvent/vsn.mk b/lib/cosEvent/vsn.mk index 85d3cf552b..2cd943e4b2 100644 --- a/lib/cosEvent/vsn.mk +++ b/lib/cosEvent/vsn.mk @@ -1,3 +1,3 @@ -COSEVENT_VSN = 2.1.11 +COSEVENT_VSN = 2.1.12 diff --git a/lib/cosEventDomain/doc/src/notes.xml b/lib/cosEventDomain/doc/src/notes.xml index 585761ce65..fa96792c33 100644 --- a/lib/cosEventDomain/doc/src/notes.xml +++ b/lib/cosEventDomain/doc/src/notes.xml @@ -31,7 +31,25 @@ <file>notes.xml</file> </header> - <section> + <section><title>cosEventDomain 1.1.12</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + </list> + </section> + +</section> + +<section> <title>cosEventDomain 1.1.11</title> <section> diff --git a/lib/cosEventDomain/vsn.mk b/lib/cosEventDomain/vsn.mk index 7df47cef2e..5ad421e319 100644 --- a/lib/cosEventDomain/vsn.mk +++ b/lib/cosEventDomain/vsn.mk @@ -1,3 +1,3 @@ -COSEVENTDOMAIN_VSN = 1.1.11 +COSEVENTDOMAIN_VSN = 1.1.12 diff --git a/lib/cosFileTransfer/doc/src/notes.xml b/lib/cosFileTransfer/doc/src/notes.xml index c7a4fd4504..f38597db10 100644 --- a/lib/cosFileTransfer/doc/src/notes.xml +++ b/lib/cosFileTransfer/doc/src/notes.xml @@ -30,7 +30,25 @@ <file>notes.xml</file> </header> - <section><title>cosFileTransfer 1.1.12</title> + <section><title>cosFileTransfer 1.1.13</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + </list> + </section> + +</section> + +<section><title>cosFileTransfer 1.1.12</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/cosFileTransfer/vsn.mk b/lib/cosFileTransfer/vsn.mk index fe0226e3b3..6d0c6669a3 100644 --- a/lib/cosFileTransfer/vsn.mk +++ b/lib/cosFileTransfer/vsn.mk @@ -1 +1 @@ -COSFILETRANSFER_VSN = 1.1.12 +COSFILETRANSFER_VSN = 1.1.13 diff --git a/lib/cosNotification/doc/src/notes.xml b/lib/cosNotification/doc/src/notes.xml index a54230c9f7..c79d040f9a 100644 --- a/lib/cosNotification/doc/src/notes.xml +++ b/lib/cosNotification/doc/src/notes.xml @@ -31,7 +31,25 @@ <file>notes.xml</file> </header> - <section><title>cosNotification 1.1.17</title> + <section><title>cosNotification 1.1.18</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + </list> + </section> + +</section> + +<section><title>cosNotification 1.1.17</title> <section><title>Improvements and New Features</title> <list> diff --git a/lib/cosNotification/vsn.mk b/lib/cosNotification/vsn.mk index b32919a2ef..e7c5465fe4 100644 --- a/lib/cosNotification/vsn.mk +++ b/lib/cosNotification/vsn.mk @@ -1,2 +1,2 @@ -COSNOTIFICATION_VSN = 1.1.17 +COSNOTIFICATION_VSN = 1.1.18 diff --git a/lib/cosProperty/doc/src/notes.xml b/lib/cosProperty/doc/src/notes.xml index 85b2119e9d..f5f737e2a3 100644 --- a/lib/cosProperty/doc/src/notes.xml +++ b/lib/cosProperty/doc/src/notes.xml @@ -31,7 +31,25 @@ <file>notes.xml</file> </header> - <section> + <section><title>cosProperty 1.1.15</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + </list> + </section> + +</section> + +<section> <title>cosProperty 1.1.14</title> <section> diff --git a/lib/cosProperty/vsn.mk b/lib/cosProperty/vsn.mk index ecc4a2746c..a4b1a2c94e 100644 --- a/lib/cosProperty/vsn.mk +++ b/lib/cosProperty/vsn.mk @@ -1,2 +1,2 @@ -COSPROPERTY_VSN = 1.1.14 +COSPROPERTY_VSN = 1.1.15 diff --git a/lib/cosTime/doc/src/notes.xml b/lib/cosTime/doc/src/notes.xml index 3698e4813e..c70978df2b 100644 --- a/lib/cosTime/doc/src/notes.xml +++ b/lib/cosTime/doc/src/notes.xml @@ -32,7 +32,25 @@ <file>notes.xml</file> </header> - <section> + <section><title>cosTime 1.1.12</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + </list> + </section> + +</section> + +<section> <title>cosTime 1.1.11</title> <section> diff --git a/lib/cosTime/vsn.mk b/lib/cosTime/vsn.mk index 4d982f3013..14d3b61bc6 100644 --- a/lib/cosTime/vsn.mk +++ b/lib/cosTime/vsn.mk @@ -1,2 +1,2 @@ -COSTIME_VSN = 1.1.11 +COSTIME_VSN = 1.1.12 diff --git a/lib/cosTransactions/doc/src/notes.xml b/lib/cosTransactions/doc/src/notes.xml index 29addf424d..f3a7a83fb0 100644 --- a/lib/cosTransactions/doc/src/notes.xml +++ b/lib/cosTransactions/doc/src/notes.xml @@ -32,7 +32,25 @@ <file>notes.xml</file> </header> - <section> + <section><title>cosTransactions 1.2.12</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + </list> + </section> + +</section> + +<section> <title>cosTransactions 1.2.11</title> <section> <title>Improvements and New Features</title> diff --git a/lib/cosTransactions/vsn.mk b/lib/cosTransactions/vsn.mk index 3960c58c5b..7ca604b589 100644 --- a/lib/cosTransactions/vsn.mk +++ b/lib/cosTransactions/vsn.mk @@ -1 +1 @@ -COSTRANSACTIONS_VSN = 1.2.11 +COSTRANSACTIONS_VSN = 1.2.12 diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml index 763f79e02d..3a44550ae2 100644 --- a/lib/crypto/doc/src/notes.xml +++ b/lib/crypto/doc/src/notes.xml @@ -30,6 +30,44 @@ </header> <p>This document describes the changes made to the Crypto application.</p> +<section><title>Crypto 2.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + public_key, ssl and crypto now supports PKCS-8</p> + <p> + Own Id: OTP-9312</p> + </item> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + <item> + <p> + Add DES and Triple DES cipher feedback (CFB) mode + functions to <c>crypto</c>. (Thanks to Paul Guyot)</p> + <p> + Own Id: OTP-9640</p> + </item> + <item> + <p> + Add sha256, sha384 and sha512 support for + <c>crypto:rsa_verify</c>.</p> + <p> + Own Id: OTP-9778</p> + </item> + </list> + </section> + +</section> + <section><title>Crypto 2.0.4</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk index 33fa9b1ec3..7e82e47d38 100644 --- a/lib/crypto/vsn.mk +++ b/lib/crypto/vsn.mk @@ -1 +1 @@ -CRYPTO_VSN = 2.0.4 +CRYPTO_VSN = 2.1 diff --git a/lib/debugger/doc/src/notes.xml b/lib/debugger/doc/src/notes.xml index 93e447848a..4d8bd8ebe4 100644 --- a/lib/debugger/doc/src/notes.xml +++ b/lib/debugger/doc/src/notes.xml @@ -32,6 +32,50 @@ <p>This document describes the changes made to the Debugger application.</p> +<section><title>Debugger 3.2.7</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix "OK" spelling in debugger messages and variables</p> + <p> + Simple code refactor in the debugger: renames all the + occurrences of "Ok" to "OK" in the code, variable names + and strings. This improves the consistency of the code + and follows the GTK UI where "OK" is always used.(Thanks + to Ricardo Catalinas Jim�nez)</p> + <p> + Own Id: OTP-9699</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Variables are now now allowed in '<c>fun M:F/A</c>' as + suggested by Richard O'Keefe in EEP-23.</p> + <p>The representation of '<c>fun M:F/A</c>' in the + abstract format has been changed in an incompatible way. + Tools that directly read or manipulate the abstract + format (such as parse transforms) may need to be updated. + The compiler can handle both the new and the old format + (i.e. extracting the abstract format from a pre-R15 BEAM + file and compiling it using compile:forms/1,2 will work). + The <c>syntax_tools</c> application can also handle both + formats.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9643</p> + </item> + </list> + </section> + +</section> + <section><title>Debugger 3.2.6</title> <section><title>Improvements and New Features</title> diff --git a/lib/debugger/src/dbg_ui_break_win.erl b/lib/debugger/src/dbg_ui_break_win.erl index abbec158b0..2894e8223b 100644 --- a/lib/debugger/src/dbg_ui_break_win.erl +++ b/lib/debugger/src/dbg_ui_break_win.erl @@ -17,6 +17,18 @@ %% %CopyrightEnd% %% -module(dbg_ui_break_win). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,entry,2}}, + {nowarn_deprecated_function,{gs,frame,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,listbox,2}}, + {nowarn_deprecated_function,{gs,menu,2}}, + {nowarn_deprecated_function,{gs,menuitem,2}}, + {nowarn_deprecated_function,{gs,radiobutton,2}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,window,2}}]). %% External exports -export([create_win/5, diff --git a/lib/debugger/src/dbg_ui_edit_win.erl b/lib/debugger/src/dbg_ui_edit_win.erl index 9b0441b44c..fb40ab3812 100644 --- a/lib/debugger/src/dbg_ui_edit_win.erl +++ b/lib/debugger/src/dbg_ui_edit_win.erl @@ -17,6 +17,12 @@ %% %CopyrightEnd% %% -module(dbg_ui_edit_win). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,entry,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,window,2}}]). %% External exports -export([create_win/5, get_window/1, diff --git a/lib/debugger/src/dbg_ui_filedialog_win.erl b/lib/debugger/src/dbg_ui_filedialog_win.erl index 1eced1104d..50d198f361 100644 --- a/lib/debugger/src/dbg_ui_filedialog_win.erl +++ b/lib/debugger/src/dbg_ui_filedialog_win.erl @@ -18,6 +18,13 @@ %% -module(dbg_ui_filedialog_win). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,entry,3}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,listbox,3}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,window,2}}]). %% External exports -export([create_win/6, create_win/7, get_window/1, diff --git a/lib/debugger/src/dbg_ui_mon_win.erl b/lib/debugger/src/dbg_ui_mon_win.erl index 52e8f433ba..f446fb7fcd 100644 --- a/lib/debugger/src/dbg_ui_mon_win.erl +++ b/lib/debugger/src/dbg_ui_mon_win.erl @@ -17,6 +17,19 @@ %% %CopyrightEnd% %% -module(dbg_ui_mon_win). +-compile([{nowarn_deprecated_function,{gs,checkbutton,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,frame,2}}, + {nowarn_deprecated_function,{gs,grid,2}}, + {nowarn_deprecated_function,{gs,gridline,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,listbox,2}}, + {nowarn_deprecated_function,{gs,menu,2}}, + {nowarn_deprecated_function,{gs,menubar,2}}, + {nowarn_deprecated_function,{gs,menuitem,2}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,window,2}}]). %% External exports -export([init/0]). diff --git a/lib/debugger/src/dbg_ui_trace_win.erl b/lib/debugger/src/dbg_ui_trace_win.erl index 82d4199630..f237f30e4a 100644 --- a/lib/debugger/src/dbg_ui_trace_win.erl +++ b/lib/debugger/src/dbg_ui_trace_win.erl @@ -17,6 +17,25 @@ %% %CopyrightEnd% %% -module(dbg_ui_trace_win). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,button,3}}, + {nowarn_deprecated_function,{gs,checkbutton,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,editor,2}}, + {nowarn_deprecated_function,{gs,editor,3}}, + {nowarn_deprecated_function,{gs,entry,2}}, + {nowarn_deprecated_function,{gs,entry,3}}, + {nowarn_deprecated_function,{gs,frame,3}}, + {nowarn_deprecated_function,{gs,grid,3}}, + {nowarn_deprecated_function,{gs,gridline,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,label,3}}, + {nowarn_deprecated_function,{gs,menubar,2}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,window,2}}, + {nowarn_deprecated_function,{gs,window,3}}]). %% External exports -export([init/0]). diff --git a/lib/debugger/src/dbg_ui_win.erl b/lib/debugger/src/dbg_ui_win.erl index 9bed6a1ec5..cef091ee28 100644 --- a/lib/debugger/src/dbg_ui_win.erl +++ b/lib/debugger/src/dbg_ui_win.erl @@ -17,6 +17,15 @@ %% %CopyrightEnd% %% -module(dbg_ui_win). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,menu,2}}, + {nowarn_deprecated_function,{gs,menu,3}}, + {nowarn_deprecated_function,{gs,menubutton,2}}, + {nowarn_deprecated_function,{gs,menuitem,2}}, + {nowarn_deprecated_function,{gs,menuitem,3}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,1}}]). %% External exports -export([init/0, diff --git a/lib/debugger/src/dbg_ui_winman.erl b/lib/debugger/src/dbg_ui_winman.erl index c7aac0df23..8619be344b 100644 --- a/lib/debugger/src/dbg_ui_winman.erl +++ b/lib/debugger/src/dbg_ui_winman.erl @@ -18,6 +18,11 @@ %% -module(dbg_ui_winman). -behaviour(gen_server). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,menu,3}}, + {nowarn_deprecated_function,{gs,menubutton,3}}, + {nowarn_deprecated_function,{gs,menuitem,3}}]). %% External exports -export([start/0]). diff --git a/lib/debugger/src/dbg_wx_filedialog_win.erl b/lib/debugger/src/dbg_wx_filedialog_win.erl index de9e11d81f..f109652a70 100644 --- a/lib/debugger/src/dbg_wx_filedialog_win.erl +++ b/lib/debugger/src/dbg_wx_filedialog_win.erl @@ -24,7 +24,7 @@ -export([new/3, getFilename/1, getFilenames/1, getDirectory/1, destroy/1]). %% Internal --export([init/1, handle_call/3, handle_event/2, +-export([init/1, handle_call/3, handle_event/2, handle_cast/2, handle_info/2, code_change/3, terminate/2]). -include_lib("wx/include/wx.hrl"). @@ -193,6 +193,9 @@ handle_call(getDirectory, _From, State = #state{path=Dir}) -> handle_call(destroy, _From, State) -> {stop, normal, ok, State}. +handle_cast(_, State) -> + {noreply, State}. + %% events handle_event(#wx{id=?wxID_UP}, State0) -> State = update_window(change_dir(0, State0)), diff --git a/lib/debugger/src/dbg_wx_trace_win.erl b/lib/debugger/src/dbg_wx_trace_win.erl index 79cf87ae62..aab8fddda7 100644 --- a/lib/debugger/src/dbg_wx_trace_win.erl +++ b/lib/debugger/src/dbg_wx_trace_win.erl @@ -19,6 +19,7 @@ %% -module(dbg_wx_trace_win). +-compile([{nowarn_deprecated_function,{gs,config,2}}]). %% External exports -export([init/0, stop/1]). diff --git a/lib/debugger/test/bs_construct_SUITE.erl b/lib/debugger/test/bs_construct_SUITE.erl index 187c9f53b0..fa7b40ff1e 100644 --- a/lib/debugger/test/bs_construct_SUITE.erl +++ b/lib/debugger/test/bs_construct_SUITE.erl @@ -56,7 +56,7 @@ end_per_group(_GroupName, Config) -> init_per_testcase(_Case, Config) -> test_lib:interpret(?MODULE), - Dog = test_server:timetrap(?t:minutes(1)), + Dog = test_server:timetrap(?t:minutes(15)), [{watchdog,Dog}|Config]. end_per_testcase(_Case, Config) -> diff --git a/lib/debugger/test/bs_match_misc_SUITE.erl b/lib/debugger/test/bs_match_misc_SUITE.erl index 89fce263f5..ec3746d76a 100644 --- a/lib/debugger/test/bs_match_misc_SUITE.erl +++ b/lib/debugger/test/bs_match_misc_SUITE.erl @@ -57,7 +57,7 @@ end_per_suite(Config) when is_list(Config) -> init_per_testcase(_Case, Config) -> test_lib:interpret(?MODULE), - Dog = test_server:timetrap(?t:minutes(1)), + Dog = test_server:timetrap(?t:minutes(15)), [{watchdog,Dog}|Config]. end_per_testcase(_Case, Config) -> diff --git a/lib/debugger/vsn.mk b/lib/debugger/vsn.mk index 0f70dafc19..01ff0eb9a8 100644 --- a/lib/debugger/vsn.mk +++ b/lib/debugger/vsn.mk @@ -1 +1 @@ -DEBUGGER_VSN = 3.2.6 +DEBUGGER_VSN = 3.2.7 diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml index 17291b24f7..f100865b56 100644 --- a/lib/dialyzer/doc/src/notes.xml +++ b/lib/dialyzer/doc/src/notes.xml @@ -31,6 +31,94 @@ <p>This document describes the changes made to the Dialyzer application.</p> +<section><title>Dialyzer 2.5</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix false warning about closure application</p> + <p> + Whenever a variable that could hold one of two or more + possible closures was used in a particular application, + the application was assumed to fail if ONE of the + closures would fail in this application. This has been + corrected to infer failing application if ALL possible + closures would fail in the particular application.</p> + <p> + Change category of 'might also return' warnings</p> + <p> + Dialyzer emits warnings like the following "The + specification for _ states that the function might also + return _ but the inferred return is _", which are + actually underspecifications and not wrong type + specifications. This patch makes sure that they are filed + under the appropriate category.</p> + <p> + Own Id: OTP-9707</p> + </item> + <item> + <p>Wrap up behaviours patch for Dialyzer</p> <list> + <item><p>Enable warnings by default, add two options for + suppressing them</p></item> <item><p>Fix warning + formatting and update testsuites.</p></item> + <item><p>Detection of callback-spec + discrepancies</p></item> <item><p>Allow none() as return + value in callbacks</p></item> <item><p>Behaviour callback + discrepancy detection for Dialyzer</p></item> + <item><p>Add lookup function for callbacks</p></item> + <item><p>Store callbacks in codeserver and PLT</p></item> + <item><p>Collect callback definitions during + compilation</p></item> <item><p>Update inets + results</p></item> </list> + <p> + Own Id: OTP-9731</p> + </item> + <item> + <p> + <list> <item><p>No warnings for underspecs with remote + types</p></item> <item><p> Fix crash in Typer</p></item> + <item><p>Fix Dialyzer's warning for its own + code</p></item> <item><p>Fix Dialyzer's warnings in + HiPE</p></item> <item><p>Add file/line info in a + particular Dialyzer crash</p></item> <item><p>Update + inets test results</p></item> </list></p> + <p> + Own Id: OTP-9758</p> + </item> + <item> + <p> + <list> <item><p>Correct callback spec in application + module</p></item> <item><p>Refine warning about callback + specs with extra ranges</p></item> <item><p>Cleanup + autoimport compiler directives</p></item> <item><p>Fix + Dialyzer's warnings in typer</p></item> <item><p>Fix + Dialyzer's warning for its own code</p></item> + <item><p>Fix bug in Dialyzer's behaviours + analysis</p></item> <item><p>Fix crash in + Dialyzer</p></item> <item><p>Variable substitution was + not generalizing any unknown variables.</p></item> + </list></p> + <p> + Own Id: OTP-9776</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> Optimize the joining of maps in + <c>dialyzer_dataflow</c>. </p> + <p> + Own Id: OTP-9761</p> + </item> + </list> + </section> + +</section> + <section><title>Dialyzer 2.4.4</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl index b42f5e8191..458f3a4c81 100644 --- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl +++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl @@ -359,8 +359,17 @@ store_core(Mod, Core, NoWarn, Callgraph, CServer) -> store_code_and_build_callgraph(Mod, LabeledCore, Callgraph, CServer3, NoWarn). abs_get_nowarn(Abs, M) -> - [{M, F, A} - || {attribute, _, compile, {nowarn_unused_function, {F, A}}} <- Abs]. + Opts = lists:flatten([C || {attribute, _, compile, C} <- Abs]), + Warn = erl_lint:bool_option(warn_unused_function, nowarn_unused_function, + true, Opts), + case Warn of + false -> + [{M, F, A} || {function, _, F, A, _} <- Abs]; % all functions + true -> + [{M, F, A} || + {nowarn_unused_function, FAs} <- Opts, + {F, A} <- lists:flatten([FAs])] + end. get_exported_types_from_core(Core) -> Attrs = cerl:module_attrs(Core), diff --git a/lib/dialyzer/src/dialyzer_gui.erl b/lib/dialyzer/src/dialyzer_gui.erl index ccd80a4835..f60194e01f 100644 --- a/lib/dialyzer/src/dialyzer_gui.erl +++ b/lib/dialyzer/src/dialyzer_gui.erl @@ -28,6 +28,23 @@ %%%----------------------------------------------------------------------- -module(dialyzer_gui). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,editor,2}}, + {nowarn_deprecated_function,{gs,entry,2}}, + {nowarn_deprecated_function,{gs,frame,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,listbox,2}}, + {nowarn_deprecated_function,{gs,menu,2}}, + {nowarn_deprecated_function,{gs,menubar,2}}, + {nowarn_deprecated_function,{gs,menubutton,2}}, + {nowarn_deprecated_function,{gs,menuitem,2}}, + {nowarn_deprecated_function,{gs,radiobutton,2}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,stop,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -export([start/1]). diff --git a/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_1 b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_1 new file mode 100644 index 0000000000..de416455e2 --- /dev/null +++ b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_1 @@ -0,0 +1,2 @@ + +nowarn_unused_function_1.erl:17: Function f3/1 will never be called diff --git a/test b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_2 index e69de29bb2..e69de29bb2 100644 --- a/test +++ b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_2 diff --git a/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_3 b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_3 new file mode 100644 index 0000000000..8ae78673d5 --- /dev/null +++ b/lib/dialyzer/test/user_SUITE_data/results/nowarn_unused_function_3 @@ -0,0 +1,3 @@ + +nowarn_unused_function_3.erl:12: Function f2/1 will never be called +nowarn_unused_function_3.erl:9: Function f1/1 will never be called diff --git a/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl new file mode 100644 index 0000000000..fcce532f73 --- /dev/null +++ b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_1.erl @@ -0,0 +1,18 @@ +%% Test that option 'nowarn_unused_funcion' works similarly in +%% Dialyzer as in the compiler. + +-module(nowarn_unused_function_1). + +-compile(warn_unused_function). + +-compile({nowarn_unused_function,f1/1}). +f1(_) -> + a. + +-compile({nowarn_unused_function,[{f2,1}]}). +f2(_) -> + a. + +-compile({warn_unused_function,[{f3,1}]}). +f3(_) -> + a. diff --git a/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl new file mode 100644 index 0000000000..9bc3ab14ea --- /dev/null +++ b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_2.erl @@ -0,0 +1,18 @@ +%% Test that option 'nowarn_unused_funcion' works similarly in +%% Dialyzer as in the compiler. + +-module(nowarn_unused_function_2). + +-compile(nowarn_unused_function). + +-compile({warn_unused_function,f1/1}). +f1(_) -> + a. + +-compile({warn_unused_function,[{f2,1}]}). +f2(_) -> + a. + +-compile({nowarn_unused_function,[{f3,1}]}). +f3(_) -> + a. diff --git a/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl new file mode 100644 index 0000000000..604c5e436b --- /dev/null +++ b/lib/dialyzer/test/user_SUITE_data/src/nowarn_unused_function_3.erl @@ -0,0 +1,16 @@ +%% Test that option 'nowarn_unused_funcion' works similarly in +%% Dialyzer as in the compiler. + +-module(nowarn_unused_function_3). + +-compile({warn_unused_function,[{f1,1},{f2,1}]}). +-compile({nowarn_unused_function,[{f3,1}]}). + +f1(_) -> + a. + +f2(_) -> + a. + +f3(_) -> + a. diff --git a/lib/dialyzer/vsn.mk b/lib/dialyzer/vsn.mk index a7e82b54ce..622e51b859 100644 --- a/lib/dialyzer/vsn.mk +++ b/lib/dialyzer/vsn.mk @@ -1 +1 @@ -DIALYZER_VSN = 2.4.4 +DIALYZER_VSN = 2.5 diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml index e2723f3e99..6e364a3200 100644 --- a/lib/diameter/doc/src/notes.xml +++ b/lib/diameter/doc/src/notes.xml @@ -36,6 +36,120 @@ first.</p> <!-- ===================================================================== --> +<section><title>Diameter 1.0</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix faulty cleanup after diameter:remove_transport/2.</p> + <p> + Removing a transport removed the configuration but did + not prevent the transport process from being restarted.</p> + <p> + Own Id: OTP-9756</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Add support for TLS over TCP.</p> + <p> + RFC 3588 requires that a Diameter server support TLS. In + practice this seems to mean TLS over SCTP since there are + limitations with running over SCTP: see RFC 6083 (DTLS + over SCTP), which is a response to RFC 3436 (TLS over + SCTP). The current RFC 3588 draft acknowledges this by + equating TLS with TLS/TCP and DTLS/SCTP.</p> + <p> + TLS handshaking can take place either following a CER/CEA + that negotiates TLS using the Inband-Security-Id AVP (the + method documented in RFC 3588) or immediately following + connection establishment (the method added to the current + draft).</p> + <p> + Own Id: OTP-9605</p> + </item> + <item> + <p> + Improvements to the dictionary parser.</p> + <p> + The dictionary parser now emits useful error messages in + case of faults in the input file, also identifying the + line number at which the fault was detected. There are + semantic checks that were missing in the previous parser, + a fault in the interpretation of vendor id's in + combination with @inherits has been fixed and @end can be + used to terminate parsing explicitly instead of always + parsing to end of file.</p> + <p> + Own Id: OTP-9639</p> + </item> + <item> + <p> + Improve dictionary reusability.</p> + <p> + Reusing a dictionary just to get a different generated + module name or prefix previously required taking a copy + of the source, which may consist of several files if + inheritance is used, just to edit a couple of lines which + don't affect the semantics of the Diameter application + being defined. Options --name, --prefix and --inherits + have been added to diameterc to allow corresponding + values to be set at compile time.</p> + <p> + Own Id: OTP-9641</p> + </item> + <item> + <p> + Add capabilities_cb transport option.</p> + <p> + Its value is a function that's applied to the transport + reference and capabilities record after capabilities + exchange. If a callback returns anything but 'ok' then + the connection is closed. In the case of an incoming CER, + the callback can return a result code with which to + answer. Multiple callbacks can be specified and are + applied until either all return 'ok' or one doesn't.</p> + <p> + This provides a way to reject a peer connection.</p> + <p> + Own Id: OTP-9654</p> + </item> + <item> + <p> + Add @codecs to dictionary format.</p> + <p> + The semantics are similar to @custom_types but results in + codec functions of the form TypeName(encode|decode, + AvpName, Data) rather than AvpName(encode|decode, + TypeName, Data). That is, the role of the AVP name and + Diameter type name are reversed. This eliminates the need + for exporting one function for each AVP sharing a common + specialized encode/decode.</p> + <p> + Own Id: OTP-9708 Aux Id: OTP-9639 </p> + </item> + <item> + <p> + Add #diameter_callback{} for more flexible callback + configuration.</p> + <p> + The record allows individual functions to be configured + for each of the diameter_app(3) callbacks, as well as a + default callback.</p> + <p> + Own Id: OTP-9777</p> + </item> + </list> + </section> + +</section> + <section><title>Diameter 0.10</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/diameter/examples/GNUmakefile b/lib/diameter/examples/code/GNUmakefile index 4c3f87939b..a0669119d2 100644 --- a/lib/diameter/examples/GNUmakefile +++ b/lib/diameter/examples/code/GNUmakefile @@ -1,19 +1,19 @@ -# +# # %CopyrightBegin% -# +# # Copyright Ericsson AB 2010-2011. All Rights Reserved. -# +# # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be # retrieved online at http://www.erlang.org/. -# +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# +# # %CopyrightEnd% # diff --git a/lib/diameter/examples/client.erl b/lib/diameter/examples/code/client.erl index 36a77dd524..9e65f98de0 100644 --- a/lib/diameter/examples/client.erl +++ b/lib/diameter/examples/code/client.erl @@ -112,7 +112,7 @@ cast(Name) -> {'Auth-Application-Id', 0}, {'Re-Auth-Request-Type', 1}], diameter:call(Name, ?APP_ALIAS, RAR, [detach]). - + cast() -> cast(?SVC_NAME). diff --git a/lib/diameter/examples/client_cb.erl b/lib/diameter/examples/code/client_cb.erl index 524a8f94a1..524a8f94a1 100644 --- a/lib/diameter/examples/client_cb.erl +++ b/lib/diameter/examples/code/client_cb.erl diff --git a/lib/diameter/examples/peer.erl b/lib/diameter/examples/code/peer.erl index 89203e15c3..89203e15c3 100644 --- a/lib/diameter/examples/peer.erl +++ b/lib/diameter/examples/code/peer.erl diff --git a/lib/diameter/examples/redirect.erl b/lib/diameter/examples/code/redirect.erl index b54701243f..b54701243f 100644 --- a/lib/diameter/examples/redirect.erl +++ b/lib/diameter/examples/code/redirect.erl diff --git a/lib/diameter/examples/redirect_cb.erl b/lib/diameter/examples/code/redirect_cb.erl index ea7ad38749..ea7ad38749 100644 --- a/lib/diameter/examples/redirect_cb.erl +++ b/lib/diameter/examples/code/redirect_cb.erl diff --git a/lib/diameter/examples/relay.erl b/lib/diameter/examples/code/relay.erl index deecb1cfc0..deecb1cfc0 100644 --- a/lib/diameter/examples/relay.erl +++ b/lib/diameter/examples/code/relay.erl diff --git a/lib/diameter/examples/relay_cb.erl b/lib/diameter/examples/code/relay_cb.erl index 9ed6517d5c..9ed6517d5c 100644 --- a/lib/diameter/examples/relay_cb.erl +++ b/lib/diameter/examples/code/relay_cb.erl diff --git a/lib/diameter/examples/sctp.erl b/lib/diameter/examples/code/sctp.erl index 2e0e9d8b0b..08de023571 100644 --- a/lib/diameter/examples/sctp.erl +++ b/lib/diameter/examples/code/sctp.erl @@ -1,3 +1,21 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% -module(sctp). diff --git a/lib/diameter/examples/server.erl b/lib/diameter/examples/code/server.erl index ebb408e501..ebb408e501 100644 --- a/lib/diameter/examples/server.erl +++ b/lib/diameter/examples/code/server.erl diff --git a/lib/diameter/examples/server_cb.erl b/lib/diameter/examples/code/server_cb.erl index 43b8e24b5c..43b8e24b5c 100644 --- a/lib/diameter/examples/server_cb.erl +++ b/lib/diameter/examples/code/server_cb.erl diff --git a/lib/diameter/examples/dict/rfc4004_mip.dia b/lib/diameter/examples/dict/rfc4004_mip.dia new file mode 100644 index 0000000000..575ad4394a --- /dev/null +++ b/lib/diameter/examples/dict/rfc4004_mip.dia @@ -0,0 +1,280 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; RFC 4004, Diameter Mobile IPv4 Application +;; +;; Edits: +;; +;; - MIP-nonce -> MIP-Nonce +;; - Session-ID -> Session-Id +;; - Omit MIP-HA-to-MN-SPI, MIP-MN-FA-SPI and MIP-MN-HA-SPI, none of +;; which are defined. +;; + +@id 2 + +@inherits rfc3588_base + +;; =========================================================================== + +@avp_types + + MIP-Reg-Request 320 OctetString M + MIP-Reg-Reply 321 OctetString M + MIP-MN-AAA-Auth 322 Grouped M + MIP-Mobile-Node-Address 333 Address M + MIP-Home-Agent-Address 334 Address M + MIP-Candidate-Home-Agent-Host 336 DiamIdent M + MIP-Feature-Vector 337 Unsigned32 M + MIP-Auth-Input-Data-Length 338 Unsigned32 M + MIP-Authenticator-Length 339 Unsigned32 M + MIP-Authenticator-Offset 340 Unsigned32 M + MIP-MN-AAA-SPI 341 Unsigned32 M + MIP-Filter-Rule 342 IPFilterRule M + MIP-FA-Challenge 344 OctetString M + MIP-Originating-Foreign-AAA 347 Grouped M + MIP-Home-Agent-Host 348 Grouped M + + MIP-FA-to-HA-SPI 318 Unsigned32 M + MIP-FA-to-MN-SPI 319 Unsigned32 M + MIP-HA-to-FA-SPI 323 Unsigned32 M + MIP-MN-to-FA-MSA 325 Grouped M + MIP-FA-to-MN-MSA 326 Grouped M + MIP-FA-to-HA-MSA 328 Grouped M + MIP-HA-to-FA-MSA 329 Grouped M + MIP-MN-to-HA-MSA 331 Grouped M + MIP-HA-to-MN-MSA 332 Grouped M + MIP-Nonce 335 OctetString M + MIP-Session-Key 343 OctetString M + MIP-Algorithm-Type 345 Enumerated M + MIP-Replay-Mode 346 Enumerated M + MIP-MSA-Lifetime 367 Unsigned32 M + +;; =========================================================================== + +@messages + + ;; 5.1. AA-Mobile-Node-Request + + AMR ::= < Diameter Header: 260, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { User-Name } + { Destination-Realm } + { Origin-Host } + { Origin-Realm } + { MIP-Reg-Request } + { MIP-MN-AAA-Auth } + [ Acct-Multi-Session-Id ] + [ Destination-Host ] + [ Origin-State-Id ] + [ MIP-Mobile-Node-Address ] + [ MIP-Home-Agent-Address ] + [ MIP-Feature-Vector ] + [ MIP-Originating-Foreign-AAA ] + [ Authorization-Lifetime ] + [ Auth-Session-State ] + [ MIP-FA-Challenge ] + [ MIP-Candidate-Home-Agent-Host ] + [ MIP-Home-Agent-Host ] + [ MIP-HA-to-FA-SPI ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 5.2. AA-Mobile-Node-Answer + + AMA ::= < Diameter Header: 260, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ Acct-Multi-Session-Id ] + [ User-Name ] + [ Authorization-Lifetime ] + [ Auth-Session-State ] + [ Error-Message ] + [ Error-Reporting-Host ] + [ Re-Auth-Request-Type ] + [ MIP-Feature-Vector ] + [ MIP-Reg-Reply ] + [ MIP-MN-to-FA-MSA ] + [ MIP-MN-to-HA-MSA ] + [ MIP-FA-to-MN-MSA ] + [ MIP-FA-to-HA-MSA ] + [ MIP-HA-to-MN-MSA ] + [ MIP-MSA-Lifetime ] + [ MIP-Home-Agent-Address ] + [ MIP-Mobile-Node-Address ] + * [ MIP-Filter-Rule ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ AVP ] + + ;; 5.3. Home-Agent-MIP-Request + + HAR ::= < Diameter Header: 262, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Authorization-Lifetime } + { Auth-Session-State } + { MIP-Reg-Request } + { Origin-Host } + { Origin-Realm } + { User-Name } + { Destination-Realm } + { MIP-Feature-Vector } + [ Destination-Host ] + [ MIP-MN-to-HA-MSA ] + [ MIP-MN-to-FA-MSA ] + [ MIP-HA-to-MN-MSA ] + [ MIP-HA-to-FA-MSA ] + [ MIP-MSA-Lifetime ] + [ MIP-Originating-Foreign-AAA ] + [ MIP-Mobile-Node-Address ] + [ MIP-Home-Agent-Address ] + * [ MIP-Filter-Rule ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 5.4. Home-Agent-MIP-Answer + + HAA ::= < Diameter Header: 262, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ Acct-Multi-Session-Id ] + [ User-Name ] + [ Error-Reporting-Host ] + [ Error-Message ] + [ MIP-Reg-Reply ] + [ MIP-Home-Agent-Address ] + [ MIP-Mobile-Node-Address ] + [ MIP-FA-to-HA-SPI ] + [ MIP-FA-to-MN-SPI ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ AVP ] + +;; =========================================================================== + +@grouped + + MIP-MN-AAA-Auth ::= < AVP Header: 322 > + + { MIP-MN-AAA-SPI } + { MIP-Auth-Input-Data-Length } + { MIP-Authenticator-Length } + { MIP-Authenticator-Offset } + * [ AVP ] + + + MIP-Originating-Foreign-AAA ::= < AVP Header: 347 > + + { Origin-Realm } + { Origin-Host } + * [ AVP ] + + MIP-Home-Agent-Host ::= < AVP Header: 348 > + + { Destination-Realm } + { Destination-Host } + * [ AVP ] + + MIP-FA-to-MN-MSA ::= < AVP Header: 326 > + + { MIP-FA-to-MN-SPI } + { MIP-Algorithm-Type } + { MIP-Session-Key } + * [ AVP ] + + MIP-FA-to-HA-MSA ::= < AVP Header: 328 > + + { MIP-FA-to-HA-SPI } + { MIP-Algorithm-Type } + { MIP-Session-Key } + * [ AVP ] + + MIP-HA-to-FA-MSA ::= < AVP Header: 329 > + + { MIP-HA-to-FA-SPI } + { MIP-Algorithm-Type } + { MIP-Session-Key } + * [ AVP ] + + MIP-HA-to-MN-MSA ::= < AVP Header: 332 > + + ; { MIP-HA-to-MN-SPI } + { MIP-Algorithm-Type } + { MIP-Replay-Mode } + { MIP-Session-Key } + * [ AVP ] + + MIP-MN-to-FA-MSA ::= < AVP Header: 325 > + + ; { MIP-MN-FA-SPI } + { MIP-Algorithm-Type } + { MIP-Nonce } + * [ AVP ] + + MIP-MN-to-HA-MSA ::= < AVP Header: 331 > + + ; { MIP-MN-HA-SPI } + { MIP-Algorithm-Type } + { MIP-Replay-Mode } + { MIP-Nonce } + * [ AVP ] + +;; =========================================================================== + +@enum MIP-Algorithm-Type + + HMAC-SHA-1 2 + +@enum MIP-Replay-Mode + + NONE 1 + TIMESTAMPS 2 + NONCES 3 + +;; =========================================================================== + +@define Result-Code + + ;; 6.1. Transient Failures + + MIP_REPLY_FAILURE 4005 + HA_NOT_AVAILABLE 4006 + BAD_KEY 4007 + MIP_FILTER_NOT_SUPPORTED 4008 + + ;; 6.2. Permanent Failures + + NO_FOREIGN_HA_SERVICE 5024 + END_TO_END_MIP_KEY_ENCRYPTION 5025 diff --git a/lib/diameter/examples/dict/rfc4005_nas.dia b/lib/diameter/examples/dict/rfc4005_nas.dia new file mode 100644 index 0000000000..a4b44e38bb --- /dev/null +++ b/lib/diameter/examples/dict/rfc4005_nas.dia @@ -0,0 +1,740 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; RFC 4005, Diameter Network Access Server Application +;; +;; Edits: +;; +;; - Acounting-Auth-Method -> Accounting-Auth-Method +;; - Connection-Info -> ConnectInfo +;; - Framed-Appletalk-Link -> Framed-AppleTalk-Link +;; - Framed-Appletalk-Network -> Framed-AppleTalk-Network +;; - Framed-Appletalk-Zone -> Framed-AppleTalk-Zone +;; - Qos-Filter-Rule -> QoS-Filter-Rule +;; - Redirect-Host-Usase -> Redirect-Host-Usage +;; - Redirected-Host -> Redirect-Host +;; - Redirected-Host-Usage -> Redirect-Host-Usage +;; - Redirected-Host-Cache-Time -> Redirect-Max-Cache-Time +;; - Redirected-Max-Cache-Time -> Redirect-Max-Cache-Time +;; + +@id 1 + +@inherits rfc3588_base + +;; =========================================================================== + +@avp_types + + ;; 4. NAS Session AVPs + + NAS-Port 5 Unsigned32 M + NAS-Port-Id 87 UTF8String M + NAS-Port-Type 61 Enumerated M + Called-Station-Id 30 UTF8String M + Calling-Station-Id 31 UTF8String M + Connect-Info 77 UTF8String M + Originating-Line-Info 94 OctetString - + Reply-Message 18 UTF8String M + + ;; 5. NAS Authentication AVPs + + User-Password 2 OctetString M + Password-Retry 75 Unsigned32 M + Prompt 76 Enumerated M + CHAP-Auth 402 Grouped M + CHAP-Algorithm 403 Enumerated M + CHAP-Ident 404 OctetString M + CHAP-Response 405 OctetString M + CHAP-Challenge 60 OctetString M + ARAP-Password 70 OctetString M + ARAP-Challenge-Response 84 OctetString M + ARAP-Security 73 Unsigned32 M + ARAP-Security-Data 74 OctetString M + + ;; 6. NAS Authorization AVPs + + Service-Type 6 Enumerated M + Callback-Number 19 UTF8String M + Callback-Id 20 UTF8String M + Idle-Timeout 28 Unsigned32 M + Port-Limit 62 Unsigned32 M + NAS-Filter-Rule 400 IPFilterRule M + Filter-Id 11 UTF8String M + Configuration-Token 78 OctetString M + QoS-Filter-Rule 407 QoSFilterRule - + Framed-Protocol 7 Enumerated M + Framed-Routing 10 Enumerated M + Framed-MTU 12 Unsigned32 M + Framed-Compression 13 Enumerated M + Framed-IP-Address 8 OctetString M + Framed-IP-Netmask 9 OctetString M + Framed-Route 22 UTF8String M + Framed-Pool 88 OctetString M + Framed-Interface-Id 96 Unsigned64 M + Framed-IPv6-Prefix 97 OctetString M + Framed-IPv6-Route 99 UTF8String M + Framed-IPv6-Pool 100 OctetString M + Framed-IPX-Network 23 UTF8String M + Framed-AppleTalk-Link 37 Unsigned32 M + Framed-AppleTalk-Network 38 Unsigned32 M + Framed-AppleTalk-Zone 39 OctetString M + ARAP-Features 71 OctetString M + ARAP-Zone-Access 72 Enumerated M + Login-IP-Host 14 OctetString M + Login-IPv6-Host 98 OctetString M + Login-Service 15 Enumerated M + Login-TCP-Port 16 Unsigned32 M + Login-LAT-Service 34 OctetString M + Login-LAT-Node 35 OctetString M + Login-LAT-Group 36 OctetString M + Login-LAT-Port 63 OctetString M + + ;; 7. NAS Tunneling + + Tunneling 401 Grouped M + Tunnel-Type 64 Enumerated M + Tunnel-Medium-Type 65 Enumerated M + Tunnel-Client-Endpoint 66 UTF8String M + Tunnel-Server-Endpoint 67 UTF8String M + Tunnel-Password 69 OctetString M + Tunnel-Private-Group-Id 81 OctetString M + Tunnel-Assignment-Id 82 OctetString M + Tunnel-Preference 83 Unsigned32 M + Tunnel-Client-Auth-Id 90 UTF8String M + Tunnel-Server-Auth-Id 91 UTF8String M + + ;; 8. NAS Accounting + + Accounting-Input-Octets 363 Unsigned64 M + Accounting-Output-Octets 364 Unsigned64 M + Accounting-Input-Packets 365 Unsigned64 M + Accounting-Output-Packets 366 Unsigned64 M + Acct-Session-Time 46 Unsigned32 M + Acct-Authentic 45 Enumerated M + Accounting-Auth-Method 406 Enumerated M + Acct-Delay-Time 41 Unsigned32 M + Acct-Link-Count 51 Unsigned32 M + Acct-Tunnel-Connection 68 OctetString M + Acct-Tunnel-Packets-Lost 86 Unsigned32 M + + ;; 9.3. AVPs Used Only for Compatibility + + NAS-Identifier 32 UTF8String M + NAS-IP-Address 4 OctetString M + NAS-IPv6-Address 95 OctetString M + State 24 OctetString M + ;;Termination-Cause 295 Enumerated M + Origin-AAA-Protocol 408 Enumerated M + +;; =========================================================================== + +@messages + + AAR ::= < Diameter Header: 265, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Request-Type } + [ Destination-Host ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ Port-Limit ] + [ User-Name ] + [ User-Password ] + [ Service-Type ] + [ State ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Auth-Session-State ] + [ Callback-Number ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + [ Originating-Line-Info ] + [ Connect-Info ] + [ CHAP-Auth ] + [ CHAP-Challenge ] + * [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + * [ Framed-IPv6-Prefix ] + [ Framed-IP-Netmask ] + [ Framed-MTU ] + [ Framed-Protocol ] + [ ARAP-Password ] + [ ARAP-Security ] + * [ ARAP-Security-Data ] + * [ Login-IP-Host ] + * [ Login-IPv6-Host ] + [ Login-LAT-Group ] + [ Login-LAT-Node ] + [ Login-LAT-Port ] + [ Login-LAT-Service ] + * [ Tunneling ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + AAA ::= < Diameter Header: 265, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Request-Type } + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Service-Type ] + * [ Class ] + * [ Configuration-Token ] + [ Acct-Interim-Interval ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Idle-Timeout ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Auth-Session-State ] + [ Re-Auth-Request-Type ] + [ Multi-Round-Time-Out ] + [ Session-Timeout ] + [ State ] + * [ Reply-Message ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + * [ Filter-Id ] + [ Password-Retry ] + [ Port-Limit ] + [ Prompt ] + [ ARAP-Challenge-Response ] + [ ARAP-Features ] + [ ARAP-Security ] + * [ ARAP-Security-Data ] + [ ARAP-Zone-Access ] + [ Callback-Id ] + [ Callback-Number ] + [ Framed-AppleTalk-Link ] + * [ Framed-AppleTalk-Network ] + [ Framed-AppleTalk-Zone ] + * [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + * [ Framed-IPv6-Prefix ] + [ Framed-IPv6-Pool ] + * [ Framed-IPv6-Route ] + [ Framed-IP-Netmask ] + * [ Framed-Route ] + [ Framed-Pool ] + [ Framed-IPX-Network ] + [ Framed-MTU ] + [ Framed-Protocol ] + [ Framed-Routing ] + * [ Login-IP-Host ] + * [ Login-IPv6-Host ] + [ Login-LAT-Group ] + [ Login-LAT-Node ] + [ Login-LAT-Port ] + [ Login-LAT-Service ] + [ Login-Service ] + [ Login-TCP-Port ] + * [ NAS-Filter-Rule ] + * [ QoS-Filter-Rule ] + * [ Tunneling ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + + RAR ::= < Diameter Header: 258, REQ, PXY > + + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Destination-Host } + { Auth-Application-Id } + { Re-Auth-Request-Type } + [ User-Name ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Service-Type ] + [ Framed-IP-Address ] + [ Framed-IPv6-Prefix ] + [ Framed-Interface-Id ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + [ Originating-Line-Info ] + [ Acct-Session-Id ] + [ Acct-Multi-Session-Id ] + [ State ] + * [ Class ] + [ Reply-Message ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + RAA ::= < Diameter Header: 258, PXY > + + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + [ Service-Type ] + * [ Configuration-Token ] + [ Idle-Timeout ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Re-Auth-Request-Type ] + [ State ] + * [ Class ] + * [ Reply-Message ] + [ Prompt ] + * [ Proxy-Info ] + * [ AVP ] + + STR ::= < Diameter Header: 275, REQ, PXY > + + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Application-Id } + { Termination-Cause } + [ User-Name ] + [ Destination-Host ] + * [ Class ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + STA ::= < Diameter Header: 275, PXY > + + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + * [ Class ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + + ASR ::= < Diameter Header: 274, REQ, PXY > + + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Destination-Host } + { Auth-Application-Id } + [ User-Name ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Service-Type ] + [ Framed-IP-Address ] + [ Framed-IPv6-Prefix ] + [ Framed-Interface-Id ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + [ Originating-Line-Info ] + [ Acct-Session-Id ] + [ Acct-Multi-Session-Id ] + [ State ] + * [ Class ] + * [ Reply-Message ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ASA ::= < Diameter Header: 274, PXY > + + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ State] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + + ACR ::= < Diameter Header: 271, REQ, PXY > + + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Accounting-Record-Type } + { Accounting-Record-Number } + [ Acct-Application-Id ] + [ Vendor-Specific-Application-Id ] + [ User-Name ] + [ Accounting-Sub-Session-Id ] + [ Acct-Session-Id ] + [ Acct-Multi-Session-Id ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ Destination-Host ] + [ Event-Timestamp ] + [ Acct-Delay-Time ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + * [ Class ] + [ Service-Type ] + [ Termination-Cause ] + [ Accounting-Input-Octets ] + [ Accounting-Input-Packets ] + [ Accounting-Output-Octets ] + [ Accounting-Output-Packets ] + [ Acct-Authentic ] + [ Accounting-Auth-Method ] + [ Acct-Link-Count ] + [ Acct-Session-Time ] + [ Acct-Tunnel-Connection ] + [ Acct-Tunnel-Packets-Lost ] + [ Callback-Id ] + [ Callback-Number ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + * [ Connect-Info ] + [ Originating-Line-Info ] + [ Authorization-Lifetime ] + [ Session-Timeout ] + [ Idle-Timeout ] + [ Port-Limit ] + [ Accounting-Realtime-Required ] + [ Acct-Interim-Interval ] + * [ Filter-Id ] + * [ NAS-Filter-Rule ] + * [ QoS-Filter-Rule ] + [ Framed-AppleTalk-Link ] + [ Framed-AppleTalk-Network ] + [ Framed-AppleTalk-Zone ] + [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + [ Framed-IP-Netmask ] + * [ Framed-IPv6-Prefix ] + [ Framed-IPv6-Pool ] + * [ Framed-IPv6-Route ] + [ Framed-IPX-Network ] + [ Framed-MTU ] + [ Framed-Pool ] + [ Framed-Protocol ] + * [ Framed-Route ] + [ Framed-Routing ] + * [ Login-IP-Host ] + * [ Login-IPv6-Host ] + [ Login-LAT-Group ] + [ Login-LAT-Node ] + [ Login-LAT-Port ] + [ Login-LAT-Service ] + [ Login-Service ] + [ Login-TCP-Port ] + * [ Tunneling ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ACA ::= < Diameter Header: 271, PXY > + + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + { Accounting-Record-Type } + { Accounting-Record-Number } + [ Acct-Application-Id ] + [ Vendor-Specific-Application-Id ] + [ User-Name ] + [ Accounting-Sub-Session-Id ] + [ Acct-Session-Id ] + [ Acct-Multi-Session-Id ] + [ Event-Timestamp ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Service-Type ] + [ Termination-Cause ] + [ Accounting-Realtime-Required ] + [ Acct-Interim-Interval ] + * [ Class ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +;; =========================================================================== + +@grouped + + CHAP-Auth ::= < AVP Header: 402 > + + { CHAP-Algorithm } + { CHAP-Ident } + [ CHAP-Response ] + * [ AVP ] + + Tunneling ::= < AVP Header: 401 > + + { Tunnel-Type } + { Tunnel-Medium-Type } + { Tunnel-Client-Endpoint } + { Tunnel-Server-Endpoint } + [ Tunnel-Preference ] + [ Tunnel-Client-Auth-Id ] + [ Tunnel-Server-Auth-Id ] + [ Tunnel-Assignment-Id ] + [ Tunnel-Password ] + [ Tunnel-Private-Group-Id ] + +;; =========================================================================== + +@enum NAS-Port-Type + + ASYNC 0 + SYNC 1 + ISDN_SYNC 2 + ISDN_ASYNC_V120 3 + ISDN_ASYNC_V110 4 + VIRTUAL 5 + PIAFS 6 + HDLC_CLEAR_CHANNEL 7 + X25 8 + X75 9 + G3FAX 10 + SDSL 11 + ADSL-CAP 12 + ADSL-DMT 13 + IDSL 14 + ETHERNET 15 + XDSL 16 + CABLE 17 + WIRELESS_OTHER 18 + 'WIRELESS_802.11' 19 + TOKEN-RING 20 + FDDI 21 + WIRELESS_CDMA2000 22 + WIRELESS_UMTS 23 + WIRELESS_1X-EV 24 + IAPP 25 + +@enum Prompt + + NO_ECHO 0 + ECHO 1 + +@enum CHAP-Algorithm + + WITH_MD5 5 + +@enum Service-Type + + LOGIN 1 + FRAMED 2 + CALLBACK_LOGIN 3 + CALLBACK_FRAMED 4 + OUTBOUND 5 + ADMINISTRATIVE 6 + NAS_PROMPT 7 + AUTHENTICATE_ONLY 8 + CALLBACK_NAS_PROMPT 9 + CALL_CHECK 10 + CALLBACK_ADMINISTRATIVE 11 + VOICE 12 + FAX 13 + MODEM_RELAY 14 + IAPP-REGISTER 15 + IAPP-AP-CHECK 16 + AUTHORIZE_ONLY 17 + +@enum Framed-Protocol + + PPP 1 + SLIP 2 + ARAP 3 + GANDALF 4 + XYLOGICS 5 + X75 6 + +@enum Framed-Routing + + NONE 0 + SEND 1 + LISTEN 2 + SEND_AND_LISTEN 3 + +@enum Framed-Compression + + NONE 0 + VJ 1 + IPX 2 + STAC-LZS 3 + +@enum ARAP-Zone-Access + + DEFAULT 1 + FILTER_INCLUSIVELY 2 + FILTER_EXCLUSIVELY 4 + +@enum Login-Service + + TELNET 0 + RLOGIN 1 + TCP_CLEAR 2 + PORTMASTER 3 + LAT 4 + X25-PAD 5 + X25-T3POS 6 + TCP_CLEAR_QUIET 8 + +@enum Tunnel-Type + + PPTP 1 + L2F 2 + L2TP 3 + ATMP 4 + VTP 5 + AH 6 + IP-IP 7 + MIN-IP-IP 8 + ESP 9 + GRE 10 + DVS 11 + IP-IN-IP 12 + VLAN 13 + +@enum Tunnel-Medium-Type + + IPV4 1 + IPV6 2 + NSAP 3 + HDLC 4 + BBN_1822 5 + '802' 6 + E163 7 + E164 8 + F69 9 + X121 10 + IPX 11 + APPLETALK 12 + DECNET_IV 13 + BANYAN_VINES 14 + E164_NSAP 15 + + +@enum Acct-Authentic + + RADIUS 1 + LOCAL 2 + REMOTE 3 + DIAMETER 4 + +@enum Accounting-Auth-Method + + PAP 1 + CHAP 2 + MS-CHAP-1 3 + MS-CHAP-2 4 + EAP 5 + NONE 7 + +@enum Termination-Cause + + USER_REQUEST 11 + LOST_CARRIER 12 + LOST_SERVICE 13 + IDLE_TIMEOUT 14 + SESSION_TIMEOUT 15 + ADMIN_RESET 16 + ADMIN_REBOOT 17 + PORT_ERROR 18 + NAS_ERROR 19 + NAS_REQUEST 20 + NAS_REBOOT 21 + PORT_UNNEEDED 22 + PORT_PREEMPTED 23 + PORT_SUSPENDED 24 + SERVICE_UNAVAILABLE 25 + CALLBACK 26 + USER_ERROR 27 + HOST_REQUEST 28 + SUPPLICANT_RESTART 29 + REAUTHORIZATION_FAILURE 30 + PORT_REINIT 31 + PORT_DISABLED 32 diff --git a/lib/diameter/examples/dict/rfc4006_cc.dia b/lib/diameter/examples/dict/rfc4006_cc.dia new file mode 100644 index 0000000000..b723e4ddbb --- /dev/null +++ b/lib/diameter/examples/dict/rfc4006_cc.dia @@ -0,0 +1,349 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; RFC 4006, Diameter Credit-Control Application +;; + +@id 4 + +@inherits rfc3588_base +@inherits rfc4005_nas Filter-Id + +;; =========================================================================== + +@avp_types + + CC-Correlation-Id 411 OctetString - + CC-Input-Octets 412 Unsigned64 M + CC-Money 413 Grouped M + CC-Output-Octets 414 Unsigned64 M + CC-Request-Number 415 Unsigned32 M + CC-Request-Type 416 Enumerated M + CC-Service-Specific-Units 417 Unsigned64 M + CC-Session-Failover 418 Enumerated M + CC-Sub-Session-Id 419 Unsigned64 M + CC-Time 420 Unsigned32 M + CC-Total-Octets 421 Unsigned64 M + CC-Unit-Type 454 Enumerated M + Check-Balance-Result 422 Enumerated M + Cost-Information 423 Grouped M + Cost-Unit 424 UTF8String M + Credit-Control 426 Enumerated M + Credit-Control-Failure-Handling 427 Enumerated M + Currency-Code 425 Unsigned32 M + Direct-Debiting-Failure-Handling 428 Enumerated M + Exponent 429 Integer32 M + Final-Unit-Action 449 Enumerated M + Final-Unit-Indication 430 Grouped M + Granted-Service-Unit 431 Grouped M + G-S-U-Pool-Identifier 453 Unsigned32 M + G-S-U-Pool-Reference 457 Grouped M + Multiple-Services-Credit-Control 456 Grouped M + Multiple-Services-Indicator 455 Enumerated M + Rating-Group 432 Unsigned32 M + Redirect-Address-Type 433 Enumerated M + Redirect-Server 434 Grouped M + Redirect-Server-Address 435 UTF8String M + Requested-Action 436 Enumerated M + Requested-Service-Unit 437 Grouped M + Restriction-Filter-Rule 438 IPFilterRule M + Service-Context-Id 461 UTF8String M + Service-Identifier 439 Unsigned32 M + Service-Parameter-Info 440 Grouped - + Service-Parameter-Type 441 Unsigned32 - + Service-Parameter-Value 442 OctetString - + Subscription-Id 443 Grouped M + Subscription-Id-Data 444 UTF8String M + Subscription-Id-Type 450 Enumerated M + Tariff-Change-Usage 452 Enumerated M + Tariff-Time-Change 451 Time M + Unit-Value 445 Grouped M + Used-Service-Unit 446 Grouped M + User-Equipment-Info 458 Grouped - + User-Equipment-Info-Type 459 Enumerated - + User-Equipment-Info-Value 460 OctetString - + Value-Digits 447 Integer64 M + Validity-Time 448 Unsigned32 M + +;; =========================================================================== + +@messages + + CCR ::= < Diameter Header: 272, REQ, PXY > + + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Application-Id } + { Service-Context-Id } + { CC-Request-Type } + { CC-Request-Number } + [ Destination-Host ] + [ User-Name ] + [ CC-Sub-Session-Id ] + [ Acct-Multi-Session-Id ] + [ Origin-State-Id ] + [ Event-Timestamp ] + * [ Subscription-Id ] + [ Service-Identifier ] + [ Termination-Cause ] + [ Requested-Service-Unit ] + [ Requested-Action ] + * [ Used-Service-Unit ] + [ Multiple-Services-Indicator ] + * [ Multiple-Services-Credit-Control ] + * [ Service-Parameter-Info ] + [ CC-Correlation-Id ] + [ User-Equipment-Info ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + CCA ::= < Diameter Header: 272, PXY > + + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + { Auth-Application-Id } + { CC-Request-Type } + { CC-Request-Number } + [ User-Name ] + [ CC-Session-Failover ] + [ CC-Sub-Session-Id ] + [ Acct-Multi-Session-Id ] + [ Origin-State-Id ] + [ Event-Timestamp ] + [ Granted-Service-Unit ] + * [ Multiple-Services-Credit-Control ] + [ Cost-Information] + [ Final-Unit-Indication ] + [ Check-Balance-Result ] + [ Credit-Control-Failure-Handling ] + [ Direct-Debiting-Failure-Handling ] + [ Validity-Time] + * [ Redirect-Host] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ Failed-AVP ] + * [ AVP ] + +;; =========================================================================== + +@grouped + + Cost-Information ::= < AVP Header: 423 > + + { Unit-Value } + { Currency-Code } + [ Cost-Unit ] + + Unit-Value ::= < AVP Header: 445 > + + { Value-Digits } + [ Exponent ] + + Multiple-Services-Credit-Control ::= < AVP Header: 456 > + + [ Granted-Service-Unit ] + [ Requested-Service-Unit ] + * [ Used-Service-Unit ] + [ Tariff-Change-Usage ] + * [ Service-Identifier ] + [ Rating-Group ] + * [ G-S-U-Pool-Reference ] + [ Validity-Time ] + [ Result-Code ] + [ Final-Unit-Indication ] + * [ AVP ] + + Granted-Service-Unit ::= < AVP Header: 431 > + + [ Tariff-Time-Change ] + [ CC-Time ] + [ CC-Money ] + [ CC-Total-Octets ] + [ CC-Input-Octets ] + [ CC-Output-Octets ] + [ CC-Service-Specific-Units ] + * [ AVP ] + + Requested-Service-Unit ::= < AVP Header: 437 > + + [ CC-Time ] + [ CC-Money ] + [ CC-Total-Octets ] + [ CC-Input-Octets ] + [ CC-Output-Octets ] + [ CC-Service-Specific-Units ] + * [ AVP ] + + Used-Service-Unit ::= < AVP Header: 446 > + + [ Tariff-Change-Usage ] + [ CC-Time ] + [ CC-Money ] + [ CC-Total-Octets ] + [ CC-Input-Octets ] + [ CC-Output-Octets ] + [ CC-Service-Specific-Units ] + * [ AVP ] + + CC-Money ::= < AVP Header: 413 > + + { Unit-Value } + [ Currency-Code ] + + G-S-U-Pool-Reference ::= < AVP Header: 457 > + + { G-S-U-Pool-Identifier } + { CC-Unit-Type } + { Unit-Value } + + Final-Unit-Indication ::= < AVP Header: 430 > + + { Final-Unit-Action } + * [ Restriction-Filter-Rule ] + * [ Filter-Id ] + [ Redirect-Server ] + + Redirect-Server ::= < AVP Header: 434 > + + { Redirect-Address-Type } + { Redirect-Server-Address } + + Service-Parameter-Info ::= < AVP Header: 440 > + + { Service-Parameter-Type } + { Service-Parameter-Value } + + Subscription-Id ::= < AVP Header: 443 > + + { Subscription-Id-Type } + { Subscription-Id-Data } + + User-Equipment-Info ::= < AVP Header: 458 > + + { User-Equipment-Info-Type } + { User-Equipment-Info-Value } + +;; =========================================================================== + +@enum CC-Request-Type + + INITIAL_REQUEST 1 + UPDATE_REQUEST 2 + TERMINATION_REQUEST 3 + EVENT_REQUEST 4 + +@enum CC-Session-Failover + + NOT_SUPPORTED 0 + SUPPORTED 1 + +@enum Check-Balance-Result + + ENOUGH_CREDIT 0 + NO_CREDIT 1 + +@enum Credit-Control + + AUTHORIZATION 0 + RE_AUTHORIZATION 1 + +@enum Credit-Control-Failure-Handling + + TERMINATE 0 + CONTINUE 1 + RETRY_AND_TERMINATE 2 + +@enum Direct-Debiting-Failure-Handling + + TERMINATE_OR_BUFFER 0 + CONTINUE 1 + +@enum Tariff-Change-Usage + + UNIT_BEFORE_TARIFF_CHANGE 0 + UNIT_AFTER_TARIFF_CHANGE 1 + UNIT_INDETERMINATE 2 + +@enum CC-Unit-Type + + TIME 0 + MONEY 1 + TOTAL-OCTETS 2 + INPUT-OCTETS 3 + OUTPUT-OCTETS 4 + SERVICE-SPECIFIC-UNITS 5 + +@enum Final-Unit-Action + + TERMINATE 0 + REDIRECT 1 + RESTRICT_ACCESS 2 + +@enum Redirect-Address-Type + + IPV4 0 + IPV6 1 + URL 2 + SIP_URI 3 + +@enum Multiple-Services-Indicator + + NOT_SUPPORTED 0 + SUPPORTED 1 + +@enum Requested-Action + + DIRECT_DEBITING 0 + REFUND_ACCOUNT 1 + CHECK_BALANCE 2 + PRICE_ENQUIRY 3 + +@enum Subscription-Id-Type + + END_USER_E164 0 + END_USER_IMSI 1 + END_USER_SIP_URI 2 + END_USER_NAI 3 + END_USER_PRIVATE 4 + +@enum User-Equipment-Info-Type + + IMEISV 0 + MAC 1 + EUI64 2 + MODIFIED_EUI64 3 + +;; =========================================================================== + +@define Result-Code + + END_USER_SERVICE_DENIED 4010 + CREDIT_CONTROL_NOT_APPLICABLE 4011 + CREDIT_LIMIT_REACHED 4012 + + USER_UNKNOWN 5030 + RATING_FAILED 5031 diff --git a/lib/diameter/examples/dict/rfc4072_eap.dia b/lib/diameter/examples/dict/rfc4072_eap.dia new file mode 100644 index 0000000000..111516b347 --- /dev/null +++ b/lib/diameter/examples/dict/rfc4072_eap.dia @@ -0,0 +1,150 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; RFC 4072, Diameter Extensible Authentication Protocol (EAP) Application +;; +;; Edits: +;; +;; - Move EAP-Payload to not break fixed/required/optional order +;; - Framed-Appletalk-Link -> Framed-AppleTalk-Link +;; - Framed-Appletalk-Network -> Framed-AppleTalk-Network +;; - Framed-Appletalk-Zone -> Framed-AppleTalk-Zone +;; + +@id 5 + +@inherits rfc3588_base +@inherits rfc4005_nas + +;; =========================================================================== + +@avp_types + + EAP-Master-Session-Key 464 OctetString - + EAP-Key-Name 102 OctetString - + EAP-Payload 462 OctetString - + EAP-Reissued-Payload 463 OctetString - + Accounting-EAP-Auth-Method 465 Unsigned64 - + +;; =========================================================================== + +@messages + + DER ::= < Diameter Header: 268, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Request-Type } + { EAP-Payload } + [ Destination-Host ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Origin-State-Id ] + [ Port-Limit ] + [ User-Name ] + [ EAP-Key-Name ] + [ Service-Type ] + [ State ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Auth-Session-State ] + [ Callback-Number ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + [ Originating-Line-Info ] + [ Connect-Info ] + * [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + * [ Framed-IPv6-Prefix ] + [ Framed-IP-Netmask ] + [ Framed-MTU ] + [ Framed-Protocol ] + * [ Tunneling ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + DEA ::= < Diameter Header: 268, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Request-Type } + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ EAP-Payload ] + [ EAP-Reissued-Payload ] + [ EAP-Master-Session-Key ] + [ EAP-Key-Name ] + [ Multi-Round-Time-Out ] + [ Accounting-EAP-Auth-Method ] + [ Service-Type ] + * [ Class ] + * [ Configuration-Token ] + [ Acct-Interim-Interval ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Idle-Timeout ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Auth-Session-State ] + [ Re-Auth-Request-Type ] + [ Session-Timeout ] + [ State ] + * [ Reply-Message ] + [ Origin-State-Id ] + * [ Filter-Id ] + [ Port-Limit ] + [ Callback-Id ] + [ Callback-Number ] + [ Framed-AppleTalk-Link ] + * [ Framed-AppleTalk-Network ] + [ Framed-AppleTalk-Zone ] + * [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + * [ Framed-IPv6-Prefix ] + [ Framed-IPv6-Pool ] + * [ Framed-IPv6-Route ] + [ Framed-IP-Netmask ] + * [ Framed-Route ] + [ Framed-Pool ] + [ Framed-IPX-Network ] + [ Framed-MTU ] + [ Framed-Protocol ] + [ Framed-Routing ] + * [ NAS-Filter-Rule ] + * [ QoS-Filter-Rule ] + * [ Tunneling ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] diff --git a/lib/diameter/examples/dict/rfc4590_digest.dia b/lib/diameter/examples/dict/rfc4590_digest.dia new file mode 100644 index 0000000000..a4ebe0c456 --- /dev/null +++ b/lib/diameter/examples/dict/rfc4590_digest.dia @@ -0,0 +1,45 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; RFC 4590, RADIUS Extension for Digest Authentication +;; + +@avp_types + + Digest-Response 103 OctetString - + Digest-Realm 104 OctetString - + Digest-Nonce 105 OctetString - + Digest-Response-Auth 106 OctetString - + Digest-Nextnonce 107 OctetString - + Digest-Method 108 OctetString - + Digest-URI 109 OctetString - + Digest-Qop 110 OctetString - + Digest-Algorithm 111 OctetString - + Digest-Entity-Body-Hash 112 OctetString - + Digest-CNonce 113 OctetString - + Digest-Nonce-Count 114 OctetString - + Digest-Username 115 OctetString - + Digest-Opaque 116 OctetString - + Digest-Auth-Param 117 OctetString - + Digest-AKA-Auts 118 OctetString - + Digest-Domain 119 OctetString - + Digest-Stale 120 OctetString - + Digest-HA1 121 OctetString - + SIP-AOR 122 OctetString - diff --git a/lib/diameter/examples/dict/rfc4740_sip.dia b/lib/diameter/examples/dict/rfc4740_sip.dia new file mode 100644 index 0000000000..8c21882649 --- /dev/null +++ b/lib/diameter/examples/dict/rfc4740_sip.dia @@ -0,0 +1,446 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +;; +;; RFC 4740, Diameter Session Initiation Protocol (SIP) Application +;; + +@id 6 + +@inherits rfc3588_base +@inherits rfc4590_digest + +;; =========================================================================== + +@avp_types + + SIP-Accounting-Information 368 Grouped M + SIP-Accounting-Server-URI 369 DiameterURI M + SIP-Credit-Control-Server-URI 370 DiameterURI M + SIP-Server-URI 371 UTF8String M + SIP-Server-Capabilities 372 Grouped M + SIP-Mandatory-Capability 373 Unsigned32 M + SIP-Optional-Capability 374 Unsigned32 M + SIP-Server-Assignment-Type 375 Enumerated M + SIP-Auth-Data-Item 376 Grouped M + SIP-Authentication-Scheme 377 Enumerated M + SIP-Item-Number 378 Unsigned32 M + SIP-Authenticate 379 Grouped M + SIP-Authorization 380 Grouped M + SIP-Authentication-Info 381 Grouped M + SIP-Number-Auth-Items 382 Unsigned32 M + SIP-Deregistration-Reason 383 Grouped M + SIP-Reason-Code 384 Enumerated M + SIP-Reason-Info 385 UTF8String M + SIP-Visited-Network-Id 386 UTF8String M + SIP-User-Authorization-Type 387 Enumerated M + SIP-Supported-User-Data-Type 388 UTF8String M + SIP-User-Data 389 Grouped M + SIP-User-Data-Type 390 UTF8String M + SIP-User-Data-Contents 391 OctetString M + SIP-User-Data-Already-Available 392 Enumerated M + SIP-Method 393 UTF8String M + +;; =========================================================================== + +@messages + + ;; 8.1. User-Authorization-Request + + UAR ::= < Diameter Header: 283, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { SIP-AOR } + [ Destination-Host ] + [ User-Name ] + [ SIP-Visited-Network-Id ] + [ SIP-User-Authorization-Type ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.2. User-Authorization-Answer + + UAA ::= < Diameter Header: 283, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ SIP-Server-URI ] + [ SIP-Server-Capabilities ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.3. Server-Assignment-Request + + SAR ::= < Diameter Header: 284, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { SIP-Server-Assignment-Type } + { SIP-User-Data-Already-Available } + [ Destination-Host ] + [ User-Name ] + [ SIP-Server-URI ] + * [ SIP-Supported-User-Data-Type ] + * [ SIP-AOR ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.4. Server-Assignment-Answer + + SAA ::= < Diameter Header: 284, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + * [ SIP-User-Data ] + [ SIP-Accounting-Information ] + * [ SIP-Supported-User-Data-Type ] + [ User-Name ] + [ Auth-Grace-Period ] + [ Authorization-Lifetime ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.5. Location-Info-Request + + LIR ::= < Diameter Header: 285, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { SIP-AOR } + [ Destination-Host ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.6. Location-Info-Answer + + LIA ::= < Diameter Header: 285, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ SIP-Server-URI ] + [ SIP-Server-Capabilities ] + [ Auth-Grace-Period ] + [ Authorization-Lifetime ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.7. Multimedia-Auth-Request + + MAR ::= < Diameter Header: 286, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { SIP-AOR } + { SIP-Method } + [ Destination-Host ] + [ User-Name ] + [ SIP-Server-URI ] + [ SIP-Number-Auth-Items ] + [ SIP-Auth-Data-Item ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.8. Multimedia-Auth-Answer + + MAA ::= < Diameter Header: 286, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ SIP-AOR ] + [ SIP-Number-Auth-Items ] + * [ SIP-Auth-Data-Item ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.9. Registration-Termination-Request + + RTR ::= < Diameter Header: 287, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Host } + { SIP-Deregistration-Reason } + [ Destination-Realm ] + [ User-Name ] + * [ SIP-AOR ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.10. Registration-Termination-Answer + + RTA ::= < Diameter Header: 287, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.11. Push-Profile-Request + + PPR ::= < Diameter Header: 288, REQ, PXY > + + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { User-Name } + * [ SIP-User-Data ] + [ SIP-Accounting-Information ] + [ Destination-Host ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ;; 8.12. Push-Profile-Answer + + PPA ::= < Diameter Header: 288, PXY > + + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +;; =========================================================================== + +@grouped + + SIP-Accounting-Information ::= < AVP Header: 368 > + + * [ SIP-Accounting-Server-URI ] + * [ SIP-Credit-Control-Server-URI ] + * [ AVP] + + SIP-Server-Capabilities ::= < AVP Header: 372 > + + * [ SIP-Mandatory-Capability ] + * [ SIP-Optional-Capability ] + * [ SIP-Server-URI ] + * [ AVP ] + + SIP-Auth-Data-Item ::= < AVP Header: 376 > + + { SIP-Authentication-Scheme } + [ SIP-Item-Number ] + [ SIP-Authenticate ] + [ SIP-Authorization ] + [ SIP-Authentication-Info ] + * [ AVP ] + + SIP-Authenticate ::= < AVP Header: 379 > + + { Digest-Realm } + { Digest-Nonce } + [ Digest-Domain ] + [ Digest-Opaque ] + [ Digest-Stale ] + [ Digest-Algorithm ] + [ Digest-Qop ] + [ Digest-HA1] + * [ Digest-Auth-Param ] + * [ AVP ] + + SIP-Authorization ::= < AVP Header: 380 > + + { Digest-Username } + { Digest-Realm } + { Digest-Nonce } + { Digest-URI } + { Digest-Response } + [ Digest-Algorithm ] + [ Digest-CNonce ] + [ Digest-Opaque ] + [ Digest-Qop ] + [ Digest-Nonce-Count ] + [ Digest-Method] + [ Digest-Entity-Body-Hash ] + * [ Digest-Auth-Param ] + * [ AVP ] + + SIP-Authentication-Info ::= < AVP Header: 381 > + + [ Digest-Nextnonce ] + [ Digest-Qop ] + [ Digest-Response-Auth ] + [ Digest-CNonce ] + [ Digest-Nonce-Count ] + * [ AVP ] + + SIP-Deregistration-Reason ::= < AVP Header: 383 > + + { SIP-Reason-Code } + [ SIP-Reason-Info ] + * [ AVP ] + + SIP-User-Data ::= < AVP Header: 389 > + + { SIP-User-Data-Type } + { SIP-User-Data-Contents } + * [ AVP ] + +;; =========================================================================== + +@enum SIP-Server-Assignment-Type + + NO_ASSIGNMENT 0 + REGISTRATION 1 + RE_REGISTRATION 2 + UNREGISTERED_USER 3 + TIMEOUT_DEREGISTRATION 4 + USER_DEREGISTRATION 5 + TIMEOUT_DEREGISTRATION_STORE 6 + USER_DEREGISTRATION_STORE 7 + ADMINISTRATIVE_DEREGISTRATION 8 + AUTHENTICATION_FAILURE 9 + AUTHENTICATION_TIMEOUT 10 + DEREGISTRATION_TOO_MUCH_DATA 11 + +@enum SIP-Authentication-Scheme + + DIGEST 0 + +@enum SIP-Reason-Code + + PERMANENT_TERMINATION 0 + NEW_SIP_SERVER_ASSIGNED 1 + SIP_SERVER_CHANGE 2 + REMOVE_SIP_SERVER 3 + +@enum SIP-User-Authorization-Type + + REGISTRATION 0 + DEREGISTRATION 1 + REGISTRATION_AND_CAPABILITIES 2 + +@enum SIP-User-Data-Already-Available + + USER_DATA_NOT_AVAILABLE 0 + USER_DATA_ALREADY_AVAILABLE 1 + +;; =========================================================================== + +@define Result-Code + + ;; Success + + FIRST_REGISTRATION 2003 + SUBSEQUENT_REGISTRATION 2004 + UNREGISTERED_SERVICE 2005 + SUCCESS_SERVER_NAME_NOT_STORED 2006 + SERVER_SELECTION 2007 + SUCCESS_AUTH_SENT_SERVER_NOT_STORED 2008 + + ;; Transient Failures + + USER_NAME_REQUIRED 4013 + + ;; Permanent Failures + + USER_UNKNOWN 5032 + IDENTITIES_DONT_MATCH 5033 + IDENTITY_NOT_REGISTERED 5034 + ROAMING_NOT_ALLOWED 5035 + IDENTITY_ALREADY_REGISTERED 5036 + AUTH_SCHEME_NOT_SUPPORTED 5037 + IN_ASSIGNMENT_TYPE 5038 + TOO_MUCH_DATA 5039 + NOT_SUPPORTED_USER_DATA 5040 diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile index 2ec016ecbc..dbfaa4e140 100644 --- a/lib/diameter/src/Makefile +++ b/lib/diameter/src/Makefile @@ -88,6 +88,9 @@ TARGET_FILES = \ # Subdirectories of src to release modules into. TARGET_DIRS = $(sort $(dir $(TARGET_MODULES))) +# Ditto for examples. +EXAMPLE_DIRS = $(sort $(dir $(EXAMPLES))) + APP_FILE = diameter.app APP_SRC = $(APP_FILE).src APP_TARGET = $(EBIN)/$(APP_FILE) @@ -169,6 +172,8 @@ info: @echo @$(call list,EXAMPLES) @echo + @$(call list,EXAMPLE_DIRS) + @echo @$(call list,BINS) @echo ======================================== @@ -189,23 +194,29 @@ endif # Can't $(INSTALL_DIR) more than one directory at a time on Solaris. release_spec: opt - for d in bin ebin examples include src/dict $(TARGET_DIRS:%/=src/%); do \ + for d in bin ebin include src/dict; do \ $(INSTALL_DIR) $(RELSYSDIR)/$$d; \ done $(INSTALL_SCRIPT) $(BINS:%=../bin/%) $(RELSYSDIR)/bin $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin - $(INSTALL_DATA) $(EXAMPLES:%=../examples/%) $(RELSYSDIR)/examples $(INSTALL_DATA) $(EXTERNAL_HRLS:%=../include/%) $(DICT_HRLS) \ $(RELSYSDIR)/include $(INSTALL_DATA) $(DICTS:%=dict/%.dia) $(RELSYSDIR)/src/dict $(MAKE) $(TARGET_DIRS:%/=release_src_%) + $(MAKE) $(EXAMPLE_DIRS:%/=release_examples_%) $(TARGET_DIRS:%/=release_src_%): release_src_%: + $(INSTALL_DIR) $(RELSYSDIR)/src/$* $(INSTALL_DATA) $(filter $*/%, $(TARGET_MODULES:%=%.erl) \ $(INTERNAL_HRLS)) \ $(filter $*/%, compiler/$(DICT_YRL).yrl) \ $(RELSYSDIR)/src/$* +$(EXAMPLE_DIRS:%/=release_examples_%): release_examples_%: + $(INSTALL_DIR) $(RELSYSDIR)/examples/$* + $(INSTALL_DATA) $(patsubst %, ../examples/%, $(filter $*/%, $(EXAMPLES))) \ + $(RELSYSDIR)/examples/$* + release_docs_spec: # ---------------------------------------------------- @@ -237,6 +248,7 @@ depend.mk: depend.sed $(MODULES:%=%.erl) Makefile .PHONY: app clean depend dict info release_subdir .PHONY: debug opt release_docs_spec release_spec .PHONY: $(TARGET_DIRS:%/=%) $(TARGET_DIRS:%/=release_src_%) +.PHONY: $(EXAMPLE_DIRS:%/=release_examples_%) # Keep intermediate files. .SECONDARY: $(DICT_ERLS) $(DICT_HRLS) gen/$(DICT_YRL:%=%.erl) diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 0893956f97..3dfdcee2b2 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -629,10 +629,6 @@ insert(Tbl, Rec) -> ets:insert(Tbl, Rec), Rec. -monitor(Pid) -> - erlang:monitor(process, Pid), - Pid. - %% Using the process dictionary for the callback state was initially %% just a way to make what was horrendous trace (big state record and %% much else everywhere) somewhat more readable. There's not as much @@ -814,10 +810,10 @@ start(Ref, Type, Opts, #state{peerT = PeerT, service = Svc}) when Type == connect; Type == accept -> - Pid = monitor(s(Type, Ref, {ConnT, - Opts, - SvcName, - merge_service(Opts, Svc)})), + Pid = s(Type, Ref, {ConnT, + Opts, + SvcName, + merge_service(Opts, Svc)}), insert(PeerT, #peer{pid = Pid, type = Type, ref = Ref, @@ -830,7 +826,13 @@ start(Ref, Type, Opts, #state{peerT = PeerT, %% callbacks. s(Type, Ref, T) -> - diameter_watchdog:start({Type, Ref}, T). + case diameter_watchdog:start({Type, Ref}, T) of + {_MRef, Pid} -> + Pid; + Pid when is_pid(Pid) -> %% from old code + erlang:monitor(process, Pid), + Pid + end. %% merge_service/2 diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl index 6dc53d9f31..fb22fd8275 100644 --- a/lib/diameter/src/base/diameter_watchdog.erl +++ b/lib/diameter/src/base/diameter_watchdog.erl @@ -59,10 +59,19 @@ message_data}). %% term passed into diameter_service with message %% start/2 +%% +%% Start a monitor before the watchdog is allowed to proceed to ensure +%% that a failed capabilities exchange produces the desired exit +%% reason. start({_,_} = Type, T) -> - {ok, Pid} = diameter_watchdog_sup:start_child({Type, self(), T}), - Pid. + Ref = make_ref(), + {ok, Pid} = diameter_watchdog_sup:start_child({Ref, {Type, self(), T}}), + try + {erlang:monitor(process, Pid), Pid} + after + Pid ! Ref + end. start_link(T) -> {ok, _} = proc_lib:start_link(?MODULE, @@ -80,14 +89,29 @@ init(T) -> proc_lib:init_ack({ok, self()}), gen_server:enter_loop(?MODULE, [], i(T)). -i({T, Pid, {ConnT, Opts, SvcName, #diameter_service{applications = Apps, - capabilities = Caps} - = Svc}}) -> - {M,S,U} = now(), - random:seed(M,S,U), +i({Ref, {_, Pid, _} = T}) -> + MRef = erlang:monitor(process, Pid), + receive + Ref -> + make_state(T); + {'DOWN', MRef, process, _, _} = D -> + exit({shutdown, D}) + end; + +i({_, Pid, _} = T) -> %% from old code + erlang:monitor(process, Pid), + make_state(T). + +make_state({T, Pid, {ConnT, + Opts, + SvcName, + #diameter_service{applications = Apps, + capabilities = Caps} + = Svc}}) -> + random:seed(now()), putr(restart, {T, Opts, Svc}), %% save seeing it in trace putr(dwr, dwr(Caps)), %% - #watchdog{parent = monitor(Pid), + #watchdog{parent = Pid, transport = monitor(diameter_peer_fsm:start(T, Opts, Svc)), tw = proplists:get_value(watchdog_timer, Opts, diff --git a/lib/diameter/src/compiler/diameter_dict_util.erl b/lib/diameter/src/compiler/diameter_dict_util.erl index e4cd29ab7f..36a6efa294 100644 --- a/lib/diameter/src/compiler/diameter_dict_util.erl +++ b/lib/diameter/src/compiler/diameter_dict_util.erl @@ -630,13 +630,28 @@ reset(K, Dict, Opts) -> opt({inherits = Key, "-"}, Dict) -> dict:erase(Key, Dict); + opt({inherits = Key, Mod}, Dict) -> - dict:append(Key, [0, {word, 0, Mod}], Dict); + case lists:splitwith(fun(C) -> C /= $/ end, Mod) of + {Mod, ""} -> + dict:append(Key, [0, {word, 0, Mod}], Dict); + {From, [$/|To]} -> + dict:store(Key, + [reinherit(From, To, M) || M <- find(Key, Dict)], + Dict) + end; + opt({Key, Val}, Dict) -> - dict:store(Key, [0, {word, 0, Val}], Dict); + dict:store(Key, [[0, {word, 0, Val}]], Dict); + opt(_, Dict) -> Dict. +reinherit(From, To, [L, {word, _, From} = T | Avps]) -> + [L, setelement(3, T, To) | Avps]; +reinherit(_, _, T) -> + T. + %% =========================================================================== %% pass1/1 %% diff --git a/lib/diameter/src/modules.mk b/lib/diameter/src/modules.mk index 11d354e57e..7a700a6d53 100644 --- a/lib/diameter/src/modules.mk +++ b/lib/diameter/src/modules.mk @@ -88,11 +88,17 @@ BINS = \ # Released files relative to ../examples. EXAMPLES = \ - GNUmakefile \ - peer.erl \ - client.erl \ - client_cb.erl \ - server.erl \ - server_cb.erl \ - relay.erl \ - relay_cb.erl + code/GNUmakefile \ + code/peer.erl \ + code/client.erl \ + code/client_cb.erl \ + code/server.erl \ + code/server_cb.erl \ + code/relay.erl \ + code/relay_cb.erl \ + dict/rfc4004_mip.dia \ + dict/rfc4005_nas.dia \ + dict/rfc4006_cc.dia \ + dict/rfc4072_eap.dia \ + dict/rfc4590_digest.dia \ + dict/rfc4740_sip.dia diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index 97d9069f4a..ab5b45ff3d 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -50,6 +50,8 @@ TARGET_FILES = $(MODULES:%=%.$(EMULATOR)) SUITE_MODULES = $(filter diameter_%_SUITE, $(MODULES)) SUITES = $(SUITE_MODULES:diameter_%_SUITE=%) +DATA_DIRS = $(sort $(dir $(DATA))) + # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- @@ -121,12 +123,12 @@ help: # diameter_ct:run/1 itself can't tell (it seems). The absolute -pa is # because ct will change directories. $(SUITES): log opt - $(ERL) -noshell \ + $(ERL) -noinput \ -pa $(realpath ../ebin) \ -sname diameter_test_$@ \ -s diameter_ct run diameter_$@_SUITE \ -s init stop \ - | awk '1{rc=0} {print} / FAILED /{rc=1} END{exit rc}' + | awk '{print} / FAILED /{rc=1} END{exit rc}' rc=0 # Shorter in sed but requires a GNU extension (ie. Q). log: @@ -147,9 +149,7 @@ else include $(ERL_TOP)/make/otp_release_targets.mk endif -release_spec: - -release_docs_spec: +release_spec release_docs_spec: release_tests_spec: $(INSTALL_DIR) $(RELSYSDIR) @@ -157,12 +157,18 @@ release_tests_spec: $(COVER_SPEC_FILE) \ $(HRL_FILES) \ $(RELSYSDIR) + $(MAKE) $(DATA_DIRS:%/=release_data_%) $(MAKE) $(ERL_FILES:%=/%) +$(DATA_DIRS:%/=release_data_%): release_data_%: + $(INSTALL_DIR) $(RELSYSDIR)/$* + $(INSTALL_DATA) $(filter $*/%, $(DATA)) $(RELSYSDIR)/$* + force: .PHONY: release_spec release_docs_spec release_test_specs .PHONY: force +.PHONY: $(DATA_DIRS:%/=release_data_%) # Can't just make $(ERL_FILES:%=/%) phony since then implicit rule # searching is skipped. diff --git a/lib/diameter/test/diameter_capx_SUITE.erl b/lib/diameter/test/diameter_capx_SUITE.erl index e6b1558bf6..54a161d606 100644 --- a/lib/diameter/test/diameter_capx_SUITE.erl +++ b/lib/diameter/test/diameter_capx_SUITE.erl @@ -27,8 +27,6 @@ -export([suite/0, all/0, groups/0, - init_per_group/2, - end_per_group/2, init_per_testcase/2, end_per_testcase/2]). @@ -93,30 +91,26 @@ -define(cea, #diameter_base_CEA). -define(answer_message, #'diameter_base_answer-message'). +-define(fail(T), erlang:error({T, process_info(self(), messages)})). + +-define(TIMEOUT, 2000). + %% =========================================================================== suite() -> [{timetrap, {seconds, 10}}]. -all() -> - [start, start_services, add_listeners - | [{group, N} || {N, _, _} <- groups()]] - ++ [remove_listeners, stop_services, stop]. +all() -> [start, + start_services, + add_listeners, + {group, all}, + {group, all, [parallel]}, + remove_listeners, + stop_services, + stop]. groups() -> - Ts = testcases(), - [{grp(P), P, Ts} || P <- [[], [parallel]]]. - -grp([]) -> - sequential; -grp([parallel = P]) -> - P. - -init_per_group(_Name, Config) -> - Config. - -end_per_group(_, _) -> - ok. + [{all, [], lists:flatmap(fun tc/1, tc())}]. %% Generate a unique hostname for each testcase so that watchdogs %% don't prevent a connection from being brought up immediately. @@ -137,9 +131,6 @@ end_per_testcase(Name, Config) -> ok = diameter:remove_transport(?CLIENT, CRef). %% Testcases all come in two flavours, client and server. -testcases() -> - lists:flatmap(fun tc/1, tc()). - tc(Name) -> [?A([C,$_|?L(Name)]) || C <- "cs"]. @@ -270,8 +261,8 @@ s_client_reject(Config) -> ?packet{}}} = Info -> Info - after 2000 -> - fail({LRef, OH}) + after ?TIMEOUT -> + ?fail({LRef, OH}) end. c_client_reject(Config) -> @@ -307,12 +298,12 @@ server_closed(Config, F, RC) -> = Reason, {listen, _}}} -> Reason - after 2000 -> - fail({LRef, OH}) + after ?TIMEOUT -> + ?fail({LRef, OH}) end. %% server_reject/3 - + server_reject(Config, F, RC) -> true = diameter:subscribe(?SERVER), OH = host(Config), @@ -328,8 +319,8 @@ server_reject(Config, F, RC) -> = Reason, {listen, _}}} -> Reason - after 2000 -> - fail({LRef, OH}) + after ?TIMEOUT -> + ?fail({LRef, OH}) end. %% cliient_closed/4 @@ -345,13 +336,13 @@ client_closed(Config, Host, F, RC) -> %% client_recv/1 -client_recv(CRef) -> +client_recv(CRef) -> receive ?event{service = ?CLIENT, info = {closed, CRef, Reason, {connect, _}}} -> Reason - after 2000 -> - fail(CRef) + after ?TIMEOUT -> + ?fail(CRef) end. %% server_capx/3 @@ -373,9 +364,6 @@ client_capx(_, ?caps{origin_host = {[_,$_|"client_reject." ++ _], _}}) -> %% =========================================================================== -fail(T) -> - erlang:error({T, process_info(self(), messages)}). - host(Config) -> {_, H} = lists:keyfind(host, 1, Config), ?HOST(H). diff --git a/lib/diameter/test/diameter_codec_SUITE.erl b/lib/diameter/test/diameter_codec_SUITE.erl index 30c60be8e9..2e219bbb10 100644 --- a/lib/diameter/test/diameter_codec_SUITE.erl +++ b/lib/diameter/test/diameter_codec_SUITE.erl @@ -35,7 +35,8 @@ %% testcases -export([base/1, gen/1, - lib/1]). + lib/1, + unknown/1]). -include("diameter_ct.hrl"). @@ -47,7 +48,7 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [base, gen, lib]. + [base, gen, lib, unknown]. init_per_testcase(gen, Config) -> [{application, ?APP, App}] = diameter_util:consult(?APP, app), @@ -74,3 +75,26 @@ gen([{dicts, Ms} | _]) -> lib(_Config) -> diameter_codec_test:lib(). + +%% Have a separate AVP dictionary just to exercise more code. +unknown(Config) -> + Priv = proplists:get_value(priv_dir, Config), + Data = proplists:get_value(data_dir, Config), + ok = make(Data, "recv.dia"), + ok = make(Data, "avps.dia"), + {ok, _, _} = compile("diameter_test_avps.erl"), + ok = make(Data, "send.dia"), + {ok, _, _} = compile("diameter_test_send.erl"), + {ok, _, _} = compile("diameter_test_recv.erl"), + {ok, _, _} = compile(filename:join([Data, "diameter_test_unknown.erl"]), + [{i, Priv}]), + diameter_test_unknown:run(). + +make(Dir, File) -> + diameter_make:codec(filename:join([Dir, File])). + +compile(File) -> + compile(File, []). + +compile(File, Opts) -> + compile:file(File, [return | Opts]). diff --git a/lib/diameter/test/diameter_codec_SUITE_data/avps.dia b/lib/diameter/test/diameter_codec_SUITE_data/avps.dia new file mode 100644 index 0000000000..c9d80a37a9 --- /dev/null +++ b/lib/diameter/test/diameter_codec_SUITE_data/avps.dia @@ -0,0 +1,25 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +@name diameter_test_avps + +@avp_types + + XXX 111 Unsigned32 M + YYY 222 Unsigned32 - diff --git a/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl b/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl new file mode 100644 index 0000000000..bce3d78a37 --- /dev/null +++ b/lib/diameter/test/diameter_codec_SUITE_data/diameter_test_unknown.erl @@ -0,0 +1,76 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_test_unknown). + +-compile(export_all). + +%% +%% Test reception of unknown AVP's. +%% + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_test_send.hrl"). +-include("diameter_test_recv.hrl"). + +-define(HOST, "test.erlang.org"). +-define(REALM, "erlang.org"). + +%% Patterns to match decoded AVP's. +-define(MANDATORY_XXX, #diameter_avp{code = 111}). +-define(NOT_MANDATORY_YYY, #diameter_avp{code = 222}). + +%% Ensure that an unknown AVP with an M flag is regarded as an error +%% while one without an M flag is returned as 'AVP'. + +run() -> + H = #diameter_header{version = 1, + end_to_end_id = 1, + hop_by_hop_id = 1}, + Vs = [{'Origin-Host', ?HOST}, + {'Origin-Realm', ?REALM}, + {'XXX', [0]}, + {'YYY', [1]}], + Pkt = #diameter_packet{header = H, + msg = Vs}, + + [] = diameter_util:run([{?MODULE, [run, M, enc(M, Pkt)]} + || M <- ['AR','BR']]). + +enc(M, #diameter_packet{msg = Vs} = P) -> + diameter_codec:encode(diameter_test_send, + P#diameter_packet{msg = [M|Vs]}). + +run(M, Pkt) -> + dec(M, diameter_codec:decode(diameter_test_recv, Pkt)). +%% Note that the recv dictionary defines neither XXX nor YYY. + +dec('AR', #diameter_packet + {msg = #recv_AR{'Origin-Host' = ?HOST, + 'Origin-Realm' = ?REALM, + 'AVP' = [?NOT_MANDATORY_YYY]}, + errors = [{5001, ?MANDATORY_XXX}]}) -> + ok; + +dec('BR', #diameter_packet + {msg = #recv_BR{'Origin-Host' = ?HOST, + 'Origin-Realm' = ?REALM}, + errors = [{5008, ?NOT_MANDATORY_YYY}, + {5001, ?MANDATORY_XXX}]}) -> + ok. diff --git a/lib/diameter/test/diameter_codec_SUITE_data/recv.dia b/lib/diameter/test/diameter_codec_SUITE_data/recv.dia new file mode 100644 index 0000000000..15fec5a5dd --- /dev/null +++ b/lib/diameter/test/diameter_codec_SUITE_data/recv.dia @@ -0,0 +1,51 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +@id 17 +@name diameter_test_recv +@prefix recv + +@inherits diameter_gen_base_rfc3588 + + Origin-Host + Origin-Realm + Result-Code + +@messages + + AR ::= < Diameter Header: 123, REQ > + { Origin-Host } + { Origin-Realm } + * [ AVP ] + + AA ::= < Diameter Header: 123 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + * [ AVP ] + + BR ::= < Diameter Header: 124, REQ > + { Origin-Host } + { Origin-Realm } + + BA ::= < Diameter Header: 124 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + * [ AVP ] diff --git a/lib/diameter/test/diameter_codec_SUITE_data/send.dia b/lib/diameter/test/diameter_codec_SUITE_data/send.dia new file mode 100644 index 0000000000..1472f146ae --- /dev/null +++ b/lib/diameter/test/diameter_codec_SUITE_data/send.dia @@ -0,0 +1,56 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +@id 17 +@name diameter_test_send +@prefix send + +@inherits diameter_gen_base_rfc3588 + + Origin-Host + Origin-Realm + Result-Code + +@inherits diameter_test_avps + +@messages + + AR ::= < Diameter Header: 123, REQ > + { Origin-Host } + { Origin-Realm } + [ XXX ] + [ YYY ] + + AA ::= < Diameter Header: 123 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + * [ AVP ] + + BR ::= < Diameter Header: 124, REQ > + { Origin-Host } + { Origin-Realm } + [ XXX ] + [ YYY ] + + BA ::= < Diameter Header: 124 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + * [ AVP ] diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl index 66d788f6ec..3b4c9706e0 100644 --- a/lib/diameter/test/diameter_compiler_SUITE.erl +++ b/lib/diameter/test/diameter_compiler_SUITE.erl @@ -29,9 +29,10 @@ end_per_suite/1]). %% testcases --export([format/1, format/2, - replace/1, replace/2, - generate/1, generate/4, generate/0]). +-export([format/1, format/2, + replace/1, replace/2, + generate/1, generate/4, generate/0, + examples/1, examples/0]). -export([dict/0]). %% fake dictionary module @@ -327,6 +328,14 @@ "@codecs mymod " "Origin-Host Origin-Realm\n&"}]}]). +%% Standard dictionaries in examples/dict. +-define(EXAMPLES, [rfc4004_mip, + rfc4005_nas, + rfc4006_cc, + rfc4072_eap, + rfc4590_digest, + rfc4740_sip]). + %% =========================================================================== suite() -> @@ -335,7 +344,8 @@ suite() -> all() -> [format, replace, - generate]. + generate, + examples]. %% Error handling testcases will make an erroneous dictionary out of %% the base dictionary and check that the expected error results. @@ -349,8 +359,6 @@ end_per_suite(_Config) -> ok. %% =========================================================================== -%% testcases - %% format/1 %% %% Ensure that parse o format is the identity map. @@ -367,6 +375,7 @@ format(Mods, Bin) -> {ok, D} = diameter_dict_util:parse(diameter_dict_util:format(Dict), []), {Dict, Dict} = {Dict, D}. +%% =========================================================================== %% replace/1 %% %% Ensure the expected success/error when parsing a morphed common @@ -393,12 +402,13 @@ replace({E, Mods}, Bin) -> re({RE, Repl}, Bin) -> re:replace(Bin, RE, Repl, [multiline]). +%% =========================================================================== %% generate/1 %% %% Ensure success when generating code and compiling. generate() -> - [{timetrap, {seconds, length(?REPLACE)}}]. + [{timetrap, {seconds, 2*length(?REPLACE)}}]. generate(Config) -> Bin = proplists:get_value(base, Config), @@ -422,6 +432,44 @@ generate(Mods, Bin, N, Mode) -> andalso ({ok, _} = compile:file(File ++ ".erl", [return_errors])). %% =========================================================================== +%% examples/1 +%% +%% Compile dictionaries extracted from various standards. + +examples() -> + [{timetrap, {seconds, 3*length(?EXAMPLES)}}]. + +examples(_Config) -> + Dir = filename:join([code:lib_dir(diameter, examples), "dict"]), + [D || D <- ?EXAMPLES, _ <- [examples(?S(D), Dir)]]. + +examples(Dict, Dir) -> + {Name, Pre} = make_name(Dict), + ok = diameter_make:codec(filename:join([Dir, Dict ++ ".dia"]), + [{name, Name}, + {prefix, Pre}, + inherits("rfc3588_base") + | opts(Dict)]), + {ok, _, _} = compile:file(Name ++ ".erl", [return]). + +opts(M) + when M == "rfc4006_cc"; + M == "rfc4072_eap" -> + [inherits("rfc4005_nas")]; +opts("rfc4740_sip") -> + [inherits("rfc4590_digest")]; +opts(_) -> + []. + +inherits(File) -> + {Name, _} = make_name(File), + {inherits, File ++ "/" ++ Name}. + +make_name(File) -> + {R, [$_|N]} = lists:splitwith(fun(C) -> C /= $_ end, File), + {string:join(["diameter_gen", N, R], "_"), "diameter_" ++ N}. + +%% =========================================================================== modify(Bin, Mods) -> lists:foldl(fun re/2, Bin, Mods). diff --git a/lib/diameter/test/diameter_dict_SUITE.erl b/lib/diameter/test/diameter_dict_SUITE.erl index 87bb9727fe..5cf8506d3f 100644 --- a/lib/diameter/test/diameter_dict_SUITE.erl +++ b/lib/diameter/test/diameter_dict_SUITE.erl @@ -25,9 +25,7 @@ -export([suite/0, all/0, - groups/0, - init_per_group/2, - end_per_group/2]). + groups/0]). %% testcases -export([append/1, @@ -53,10 +51,11 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [{group, all} | tc()]. + [{group, all}, + {group, all, [parallel]}]. groups() -> - [{all, [parallel], tc()}]. + [{all, [], tc()}]. tc() -> [append, @@ -71,12 +70,6 @@ tc() -> update, update_counter]. -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. - %% =========================================================================== -define(KV100, [{N,[N]} || N <- lists:seq(1,100)]). diff --git a/lib/diameter/test/diameter_failover_SUITE.erl b/lib/diameter/test/diameter_failover_SUITE.erl index 429b6328e6..53398dd93e 100644 --- a/lib/diameter/test/diameter_failover_SUITE.erl +++ b/lib/diameter/test/diameter_failover_SUITE.erl @@ -174,7 +174,7 @@ realm(Host) -> call(Req, Opts) -> diameter:call(?CLIENT, ?APP_ALIAS, Req, Opts). - + set([H|T], Vs) -> [H | Vs ++ T]. diff --git a/lib/diameter/test/diameter_gen_sctp_SUITE.erl b/lib/diameter/test/diameter_gen_sctp_SUITE.erl new file mode 100644 index 0000000000..7f435a6b7a --- /dev/null +++ b/lib/diameter/test/diameter_gen_sctp_SUITE.erl @@ -0,0 +1,354 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Some gen_sctp-specific tests demonstrating problems that were +%% encountered during diameter development but have nothing +%% specifically to do with diameter. At least one of them can cause +%% diameter_transport_SUITE testcases to fail. +%% + +-module(diameter_gen_sctp_SUITE). + +-export([suite/0, + all/0, + init_per_suite/1, + end_per_suite/1]). + +%% testcases +-export([send_not_from_controlling_process/1, + send_from_multiple_clients/1, + receive_what_was_sent/1]). + +-include_lib("kernel/include/inet_sctp.hrl"). + +%% Message from gen_sctp are of this form. +-define(SCTP(Sock, Data), {sctp, Sock, _, _, Data}). + +%% Open sockets on the loopback address. +-define(ADDR, {127,0,0,1}). + +%% Snooze, nap, siesta. +-define(SLEEP(T), receive after T -> ok end). + +%% An indescribably long number of milliseconds after which everthing +%% that should have happened has. +-define(FOREVER, 2000). + +%% The first byte in each message we send as a simple guard against +%% not receiving what was sent. +-define(MAGIC, 42). + +%% =========================================================================== + +suite() -> + [{timetrap, {minutes, 2}}]. + +all() -> + [send_not_from_controlling_process, + send_from_multiple_clients, + receive_what_was_sent]. + +init_per_suite(Config) -> + case gen_sctp:open() of + {ok, Sock} -> + gen_sctp:close(Sock), + Config; + {error, E} when E == eprotonosupport; + E == esocktnosupport -> + {skip, no_sctp} + end. + +end_per_suite(_Config) -> + ok. + +%% =========================================================================== + +%% send_not_from_controlling_process/1 +%% +%% This testcase failing shows gen_sctp:send/4 hanging when called +%% outside the controlling process of the socket in question. + +send_not_from_controlling_process(_) -> + Pids = send_not_from_controlling_process(), + ?SLEEP(?FOREVER), + try + [] = [{P,I} || P <- Pids, I <- [process_info(P)], I /= undefined] + after + lists:foreach(fun(P) -> exit(P, kill) end, Pids) + end. + +%% send_not_from_controlling_process/0 +%% +%% Returns the pids of three spawned processes: a listening process, a +%% connecting process and a sending process. +%% +%% The expected behaviour is that all three processes exit: +%% +%% - The listening process exits upon receiving an SCTP message +%% sent by the sending process. +%% - The connecting process exits upon listening process exit. +%% - The sending process exits upon gen_sctp:send/4 return. +%% +%% The observed behaviour is that all three processes remain alive +%% indefinitely: +%% +%% - The listening process never receives the SCTP message sent +%% by the sending process. +%% - The connecting process has an inet_reply message in its mailbox +%% as a consequence of the call to gen_sctp:send/4 call from the +%% sending process. +%% - The call to gen_sctp:send/4 in the sending process doesn't return, +%% hanging in prim_inet:getopts/2. + +send_not_from_controlling_process() -> + FPid = self(), + {L, MRef} = spawn_monitor(fun() -> listen(FPid) end),%% listening process + receive + {?MODULE, C, S} -> + erlang:demonitor(MRef, [flush]), + [L,C,S]; + {'DOWN', MRef, process, _, _} = T -> + error(T) + end. + +%% listen/1 + +listen(FPid) -> + {ok, Sock} = open(), + ok = gen_sctp:listen(Sock, true), + {ok, PortNr} = inet:port(Sock), + LPid = self(), + spawn(fun() -> connect1(PortNr, FPid, LPid) end), %% connecting process + Id = assoc(Sock), + ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], _Bin}) + = recv(). %% Waits with this as current_function. + +%% recv/0 + +recv() -> + receive T -> T end. + +%% connect1/3 + +connect1(PortNr, FPid, LPid) -> + {ok, Sock} = open(), + ok = gen_sctp:connect_init(Sock, ?ADDR, PortNr, []), + Id = assoc(Sock), + FPid ! {?MODULE, + self(), + spawn(fun() -> send(Sock, Id) end)}, %% sending process + MRef = erlang:monitor(process, LPid), + down(MRef). %% Waits with this as current_function. + +%% down/1 + +down(MRef) -> + receive {'DOWN', MRef, process, _, Reason} -> Reason end. + +%% send/2 + +send(Sock, Id) -> + ok = gen_sctp:send(Sock, Id, 0, <<0:32>>). + +%% =========================================================================== + +%% send_from_multiple_clients/0 +%% +%% Demonstrates sluggish delivery of messages. + +send_from_multiple_clients(_) -> + {S, Rs} = T = send_from_multiple_clients(8, 1024), + {false, [], _} = {?FOREVER < S, + Rs -- [OI || {O,_} = OI <- Rs, is_integer(O)], + T}. + +%% send_from_multiple_clients/2 +%% +%% Opens a listening socket and then spawns a specified number of +%% processes, each of which connects to the listening socket. Each +%% connecting process then sends a message, whose size in bytes is +%% passed as an argument, the listening process sends a reply +%% containing the time at which the message was received, and the +%% connecting process then exits upon reception of this reply. +%% +%% Returns the elapsed time for all connecting process to exit +%% together with a list of exit reasons for the connecting processes. +%% In the successful case a connecting process exits with the +%% outbound/inbound transit times for the sent/received message as +%% reason. +%% +%% The observed behaviour is that some outbound messages (that is, +%% from a connecting process to the listening process) can take an +%% unexpectedly long time to complete their journey. The more +%% connecting processes, the longer the possible delay it seems. +%% +%% eg. (With F = fun send_from_multiple_clients/2.) +%% +%% 5> F(2, 1024). +%% {875,[{128,116},{113,139}]} +%% 6> F(4, 1024). +%% {2995290,[{2994022,250},{2994071,80},{200,130},{211,113}]} +%% 7> F(8, 1024). +%% {8997461,[{8996161,116}, +%% {2996471,86}, +%% {2996278,116}, +%% {2996360,95}, +%% {246,112}, +%% {213,159}, +%% {373,173}, +%% {376,118}]} +%% 8> F(8, 1024). +%% {21001891,[{20999968,128}, +%% {8997891,172}, +%% {8997927,91}, +%% {2995716,164}, +%% {2995860,87}, +%% {134,100}, +%% {117,98}, +%% {149,125}]} + +send_from_multiple_clients(N, Sz) + when is_integer(N), 0 < N, is_integer(Sz), 0 < Sz -> + timer:tc(fun listen/2, [N, <<?MAGIC, 0:Sz/unit:8>>]). + +%% listen/2 + +listen(N, Bin) -> + {ok, Sock} = open(), + ok = gen_sctp:listen(Sock, true), + {ok, PortNr} = inet:port(Sock), + + %% Spawn a middleman that in turn spawns N connecting processes, + %% collects a list of exit reasons and then exits with the list as + %% reason. loop/3 returns when we receive this list from the + %% middleman's 'DOWN'. + + Self = self(), + Fun = fun() -> exit(connect2(Self, PortNr, Bin)) end, + {_, MRef} = spawn_monitor(fun() -> exit(fold(N, Fun)) end), + loop(Sock, MRef, Bin). + +%% fold/2 +%% +%% Spawn N processes and collect their exit reasons in a list. + +fold(N, Fun) -> + start(N, Fun), + acc(N, []). + +start(0, _) -> + ok; +start(N, Fun) -> + spawn_monitor(Fun), + start(N-1, Fun). + +acc(0, Acc) -> + Acc; +acc(N, Acc) -> + receive + {'DOWN', _MRef, process, _, RC} -> + acc(N-1, [RC | Acc]) + end. + +%% loop/3 + +loop(Sock, MRef, Bin) -> + receive + ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], B}) -> + Sz = size(Bin), + {Sz, Bin} = {size(B), B}, %% assert + ok = send(Sock, Id, mark(Bin)), + loop(Sock, MRef, Bin); + ?SCTP(Sock, _) -> + loop(Sock, MRef, Bin); + {'DOWN', MRef, process, _, Reason} -> + Reason + end. + +%% connect2/3 + +connect2(Pid, PortNr, Bin) -> + erlang:monitor(process, Pid), + + {ok, Sock} = open(), + ok = gen_sctp:connect_init(Sock, ?ADDR, PortNr, []), + Id = assoc(Sock), + + %% T1 = time before send + %% T2 = time after listening process received our message + %% T3 = time after reply is received + + T1 = now(), + ok = send(Sock, Id, Bin), + T2 = unmark(recv(Sock, Id)), + T3 = now(), + {timer:now_diff(T2, T1), timer:now_diff(T3, T2)}. %% {Outbound, Inbound} + +%% recv/2 + +recv(Sock, Id) -> + receive + ?SCTP(Sock, {[#sctp_sndrcvinfo{assoc_id = Id}], Bin}) -> + Bin; + T -> %% eg. 'DOWN' + exit(T) + end. + +%% send/3 + +send(Sock, Id, Bin) -> + gen_sctp:send(Sock, Id, 0, Bin). + +%% mark/1 + +mark(Bin) -> + Info = term_to_binary(now()), + <<Info/binary, Bin/binary>>. + +%% unmark/1 + +unmark(Bin) -> + {_,_,_} = binary_to_term(Bin). + +%% =========================================================================== + +%% receive_what_was_sent/1 +%% +%% Demonstrates reception of a message that differs from that sent. + +receive_what_was_sent(_Config) -> + send_from_multiple_clients(1, 1024*32). %% fails + +%% =========================================================================== + +%% open/0 + +open() -> + gen_sctp:open([{ip, ?ADDR}, {port, 0}, {active, true}, binary]). + +%% assoc/1 + +assoc(Sock) -> + receive + ?SCTP(Sock, {[], #sctp_assoc_change{state = S, + assoc_id = Id}}) -> + comm_up = S, %% assert + Id + end. diff --git a/lib/diameter/test/diameter_reg_SUITE.erl b/lib/diameter/test/diameter_reg_SUITE.erl index ade824c9dd..ec6a0ca731 100644 --- a/lib/diameter/test/diameter_reg_SUITE.erl +++ b/lib/diameter/test/diameter_reg_SUITE.erl @@ -26,8 +26,6 @@ -export([suite/0, all/0, groups/0, - init_per_group/2, - end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -48,10 +46,11 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [{group, all} | tc()]. + [{group, all}, + {group, all, [parallel]}]. groups() -> - [{all, [parallel], tc()}]. + [{all, [], tc()}]. tc() -> [add, @@ -61,12 +60,6 @@ tc() -> terms, pids]. -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. - init_per_suite(Config) -> ok = diameter:start(), Config. diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl index c0351f8cf2..70e1866791 100644 --- a/lib/diameter/test/diameter_relay_SUITE.erl +++ b/lib/diameter/test/diameter_relay_SUITE.erl @@ -35,9 +35,7 @@ -export([suite/0, all/0, - groups/0, - init_per_group/2, - end_per_group/2]). + groups/0]). %% testcases -export([start/1, @@ -117,21 +115,17 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [start, start_services, connect] - ++ tc() - ++ [{group, all}, - disconnect, - stop_services, - stop]. + [start, + start_services, + connect, + {group, all}, + {group, all, [parallel]}, + disconnect, + stop_services, + stop]. groups() -> - [{all, [parallel], tc()}]. - -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. + [{all, [], tc()}]. %% Traffic cases run when services are started and connections %% established. @@ -248,7 +242,7 @@ call(Server) -> call(Req, Opts) -> diameter:call(?CLIENT, ?APP_ALIAS, Req, Opts). - + set([H|T], Vs) -> [H | Vs ++ T]. diff --git a/lib/diameter/test/diameter_stats_SUITE.erl b/lib/diameter/test/diameter_stats_SUITE.erl index e50a0050a6..e7807fd360 100644 --- a/lib/diameter/test/diameter_stats_SUITE.erl +++ b/lib/diameter/test/diameter_stats_SUITE.erl @@ -26,8 +26,6 @@ -export([suite/0, all/0, groups/0, - init_per_group/2, - end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -44,21 +42,16 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [{group, all} | tc()]. + [{group, all}, + {group, all, [parallel]}]. groups() -> - [{all, [parallel], tc()}]. + [{all, [], tc()}]. tc() -> [an, twa]. -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. - init_per_suite(Config) -> ok = diameter:start(), Config. diff --git a/lib/diameter/test/diameter_sync_SUITE.erl b/lib/diameter/test/diameter_sync_SUITE.erl index 84f77b6066..ab629fb1c1 100644 --- a/lib/diameter/test/diameter_sync_SUITE.erl +++ b/lib/diameter/test/diameter_sync_SUITE.erl @@ -26,8 +26,6 @@ -export([suite/0, all/0, groups/0, - init_per_group/2, - end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -48,10 +46,11 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [{group, all} | tc()]. + [{group, all}, + {group, all, [parallel]}]. groups() -> - [{all, [parallel], tc()}]. + [{all, [], tc()}]. tc() -> [call, @@ -59,12 +58,6 @@ tc() -> timeout, flush]. -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. - init_per_suite(Config) -> ok = diameter:start(), Config. diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl index 38282282b8..85b953dc1a 100644 --- a/lib/diameter/test/diameter_tls_SUITE.erl +++ b/lib/diameter/test/diameter_tls_SUITE.erl @@ -36,8 +36,6 @@ -export([suite/0, all/0, groups/0, - init_per_group/2, - end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -136,20 +134,16 @@ all() -> start_diameter, make_certs, start_services, - add_transports] - ++ [{group, N} || {N, _, _} <- groups()] - ++ [remove_transports, stop_services, stop_diameter, stop_ssl]. + add_transports, + {group, all}, + {group, all, [parallel]}, + remove_transports, + stop_services, + stop_diameter, + stop_ssl]. groups() -> - Ts = tc(), - [{all, [], Ts}, - {p, [parallel], Ts}]. - -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. + [{all, [], tc()}]. %% Shouldn't really have to know about crypto here but 'ok' from %% ssl:start() isn't enough to guarantee that TLS is available. diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 78131b4ec4..6eed8d3b5d 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -162,27 +162,16 @@ suite() -> [{timetrap, {seconds, 10}}]. all() -> - [start, start_services, add_transports, result_codes - | [{group, N} || {N, _, _} <- groups()]] + [start, start_services, add_transports, result_codes] + ++ [{group, E, P} || E <- ?ENCODINGS, P <- [[], [parallel]]] ++ [remove_transports, stop_services, stop]. groups() -> Ts = tc(), - [{grp(E,P), P, Ts} || E <- ?ENCODINGS, P <- [[], [parallel]]]. - -grp(E, []) -> - E; -grp(E, [parallel]) -> - ?P(E). + [{E, [], Ts} || E <- ?ENCODINGS]. init_per_group(Name, Config) -> - E = case ?L(Name) of - "p_" ++ Rest -> - ?A(Rest); - _ -> - Name - end, - [{encode, E} | Config]. + [{encode, Name} | Config]. end_per_group(_, _) -> ok. @@ -516,10 +505,10 @@ send_multiple_filters(Config, Fs) -> %% Ensure that we can pass a request in any form to diameter:call/4, %% only the return value from the prepare_request callback being %% significant. -send_anything(Config) -> +send_anything(Config) -> #diameter_base_STA{'Result-Code' = ?SUCCESS} = call(Config, anything). - + %% =========================================================================== call(Config, Req) -> diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl index df7161fd1e..893b7ba2f9 100644 --- a/lib/diameter/test/diameter_transport_SUITE.erl +++ b/lib/diameter/test/diameter_transport_SUITE.erl @@ -27,8 +27,6 @@ -export([suite/0, all/0, groups/0, - init_per_group/2, - end_per_group/2, init_per_suite/1, end_per_suite/1]). @@ -92,10 +90,13 @@ suite() -> [{timetrap, {minutes, 2}}]. all() -> - [start | tc()] ++ [{group, all}, stop]. + [start, + {group, all}, + {group, all, [parallel]}, + stop]. groups() -> - [{all, [parallel], tc()}]. + [{all, [], tc()}]. tc() -> [tcp_accept, @@ -103,12 +104,6 @@ tc() -> sctp_accept, sctp_connect]. -init_per_group(_, Config) -> - Config. - -end_per_group(_, _) -> - ok. - init_per_suite(Config) -> [{sctp, have_sctp()} | Config]. @@ -175,16 +170,13 @@ connect(Prot) -> %% have_sctp/0 have_sctp() -> - try gen_sctp:open() of + case gen_sctp:open() of {ok, Sock} -> gen_sctp:close(Sock), true; {error, E} when E == eprotonosupport; E == esocktnosupport -> %% fail on any other reason false - catch - error: badarg -> - false end. %% if_sctp/2 @@ -220,7 +212,7 @@ init(gen_connect, {Prot, Ref}) -> [PortNr] = ?util:lport(Prot, Ref, 20), %% Connect, send a message and receive it back. - {ok, Sock} = gen_connect(Prot, PortNr, Ref), + {ok, Sock} = gen_connect(Prot, PortNr), Bin = make_msg(), ok = gen_send(Prot, Sock, Bin), Bin = gen_recv(Prot, Sock); @@ -359,20 +351,7 @@ tmod(tcp) -> %% =========================================================================== -%% gen_connect/3 - -gen_connect(Prot, PortNr, Ref) -> - Pid = sync(connect, Ref), - - %% Stagger connect attempts to avoid the situation that no - %% transport process is accepting yet. - receive after 250 -> ok end, - - try - gen_connect(Prot, PortNr) - after - Pid ! Ref - end. +%% gen_connect/2 gen_connect(sctp = P, PortNr) -> {ok, Sock} = Ok = gen_sctp:open([{ip, ?ADDR}, {port, 0} | ?SCTP_OPTS]), diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl index 6b1dc1f0c9..0c42f955ad 100644 --- a/lib/diameter/test/diameter_util.erl +++ b/lib/diameter/test/diameter_util.erl @@ -212,7 +212,7 @@ read_priv(Config, Name) -> read(Path) -> {ok, Bin} = file:read_file(Path), binary_to_term(Bin). - + %% map_priv/3 %% %% Modify a term in a file and return both old and new values. diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl index b40d7c104d..ff40326947 100644 --- a/lib/diameter/test/diameter_watchdog_SUITE.erl +++ b/lib/diameter/test/diameter_watchdog_SUITE.erl @@ -306,11 +306,8 @@ watchdog(Type, Ref, TPid, Wd) -> Opts = [{transport_module, ?MODULE}, {transport_config, TPid}, {watchdog_timer, Wd}], - monitor(diameter_watchdog:start({Type, Ref}, - {false, Opts, false, ?SERVICE})). - -monitor(Pid) -> - erlang:monitor(process, Pid), + {_MRef, Pid} = diameter_watchdog:start({Type, Ref}, + {false, Opts, false, ?SERVICE}), Pid. %% =========================================================================== @@ -350,6 +347,10 @@ init(_, _, TPid, _) -> monitor(TPid), 3. +monitor(Pid) -> + erlang:monitor(process, Pid), + Pid. + %% Generate a unique hostname for the faked peer. hostname() -> lists:flatten(io_lib:format("~p-~p-~p", tuple_to_list(now()))). diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk index 54978d820c..7f163536fb 100644 --- a/lib/diameter/test/modules.mk +++ b/lib/diameter/test/modules.mk @@ -33,6 +33,7 @@ MODULES = \ diameter_sync_SUITE \ diameter_stats_SUITE \ diameter_watchdog_SUITE \ + diameter_gen_sctp_SUITE \ diameter_transport_SUITE \ diameter_capx_SUITE \ diameter_traffic_SUITE \ @@ -42,3 +43,9 @@ MODULES = \ HRL_FILES = \ diameter_ct.hrl + +DATA = \ + diameter_codec_SUITE_data/avps.dia \ + diameter_codec_SUITE_data/send.dia \ + diameter_codec_SUITE_data/recv.dia \ + diameter_codec_SUITE_data/diameter_test_unknown.erl diff --git a/lib/edoc/doc/src/notes.xml b/lib/edoc/doc/src/notes.xml index b220067bbe..a74a19bc05 100644 --- a/lib/edoc/doc/src/notes.xml +++ b/lib/edoc/doc/src/notes.xml @@ -31,6 +31,21 @@ <p>This document describes the changes made to the EDoc application.</p> +<section><title>Edoc 0.7.9.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Miscellaneous documentation build updates</p> + <p> + Own Id: OTP-9813</p> + </item> + </list> + </section> + +</section> + <section><title>Edoc 0.7.9</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk index 22f225dd9b..b8f33894f1 100644 --- a/lib/edoc/vsn.mk +++ b/lib/edoc/vsn.mk @@ -1 +1 @@ -EDOC_VSN = 0.7.9 +EDOC_VSN = 0.7.9.1 diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml index 9591b363f7..23f64b876a 100644 --- a/lib/erl_docgen/doc/src/notes.xml +++ b/lib/erl_docgen/doc/src/notes.xml @@ -30,7 +30,50 @@ </header> <p>This document describes the changes made to the <em>erl_docgen</em> application.</p> - <section><title>Erl_Docgen 0.2.6</title> + <section><title>Erl_Docgen 0.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> Bug fixes concerning the generation of manpages. </p> + <p> + Own Id: OTP-9614</p> + </item> + <item> + <p> Fix syntax bug in eix files. </p> + <p> + Own Id: OTP-9617</p> + </item> + <item> + <p> Bug fix concerning the generation of manpages. </p> + <p> + Own Id: OTP-9759</p> + </item> + <item> + <p> Fixed an arity calculation bug for erlang functions + in the documentation index for html and pdf. </p> + <p> + Own Id: OTP-9772</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> The docbuilder application is removed in R15 and + parts still used in the OTP documentation build process + and the DTD documentation is moved to erl_docgen. </p> + <p> + Own Id: OTP-9721</p> + </item> + </list> + </section> + +</section> + +<section><title>Erl_Docgen 0.2.6</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/erl_docgen/priv/css/otp_doc.css b/lib/erl_docgen/priv/css/otp_doc.css index 97d8c2df74..c56de378f4 100644 --- a/lib/erl_docgen/priv/css/otp_doc.css +++ b/lib/erl_docgen/priv/css/otp_doc.css @@ -1,6 +1,5 @@ - - -body { +/* standard OTP style sheet */ +body { background: white; font-family: Verdana, Arial, Helvetica, sans-serif; margin: 0; @@ -11,7 +10,6 @@ body { max-height: 100%; } - th { font-family: Verdana, Arial, Helvetica, sans-serif } td { font-family: Verdana, Arial, Helvetica, sans-serif } p { font-family: Verdana, Arial, Helvetica, sans-serif } @@ -33,8 +31,7 @@ a:visited { color: blue; text-decoration: none } background-color: #fff; } - -#leftnav { +#leftnav { position: fixed; float: left; top: 0; @@ -47,8 +44,7 @@ a:visited { color: blue; text-decoration: none } border-right: 1px solid red; } - -#content { +#content { margin-left: 240px; /* set left value to WidthOfFrameDiv */ } @@ -57,7 +53,6 @@ a:visited { color: blue; text-decoration: none } padding-top: 50px; /* Magins for inner DIV inside each DIV (to provide padding) */ } - .innertube { margin: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */ @@ -66,16 +61,15 @@ a:visited { color: blue; text-decoration: none } .footer { margin: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */ - } -span.bold_code { font-family: courier;font-weight: bold} -span.code { font-family: courier;font-weight: normal} + +span.bold_code { font-family: Courier, monospace; font-weight: bold } +span.code { font-family: Courier, monospace; font-weight: normal } .note, .warning { border: solid black 1px; margin: 1em 3em; } - .note .label { background: #30d42a; color: white; @@ -102,16 +96,15 @@ span.code { font-family: courier;font-weight: normal} font-size: 90%; padding: 5px 10px; } - -.example { +.example { background-color:#eeeeff; padding: 0px 10px; -} +} -pre { font-family: courier; font-weight: normal } +pre { font-family: Courier, monospace; font-weight: normal } .REFBODY { margin-left: 13mm } .REFTYPES { margin-left: 8mm } -footer { } +footer { } diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl index bdef7bfd3d..7cf5465f90 100644 --- a/lib/erl_docgen/priv/xsl/db_html.xsl +++ b/lib/erl_docgen/priv/xsl/db_html.xsl @@ -3,7 +3,7 @@ # # %CopyrightBegin% # - # Copyright Ericsson AB 2009-2011. All Rights Reserved. + # Copyright Ericsson AB 2009-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -40,6 +40,11 @@ <xsl:variable name="m2a" select="document($mod2app_file)"></xsl:variable> <xsl:key name="mod2app" match="module" use="@name"/> + <xsl:key + name="mfa" + match="func/name[string-length(@arity) > 0 and ancestor::erlref]" + use="concat(ancestor::erlref/module,':',@name, '/', @arity)"/> + <xsl:template name="err"> <xsl:param name="f"/> <xsl:param name="m"/> @@ -101,10 +106,14 @@ </xsl:message> </xsl:when> <xsl:when test="ancestor::erlref"> + <!-- Do not to use preceding since it is very slow! --> + <xsl:variable name="curModule" select="ancestor::erlref/module"/> + <xsl:variable name="mfas" + select="key('mfa', + concat($curModule,':',$name,'/',$arity))"/> <xsl:choose> - <xsl:when test="preceding-sibling::name[position() = 1 - and @name = $name and @arity = $arity]"> - <!-- Avoid duplicated anchors.--> + <xsl:when test="generate-id($mfas[1]) != generate-id(.)"> + <!-- Avoid duplicated anchors. See also menu.funcs. --> </xsl:when> <xsl:otherwise> <a name="{$name}-{$arity}"></a> @@ -546,6 +555,23 @@ <!-- End of Dialyzer type/spec tags --> + <!-- Cache for each module all the elements used for navigation. --> + <xsl:variable name="erlref.nav" select="exsl:node-set($erlref.nav_rtf)"/> + + <xsl:variable name="erlref.nav_rtf"> + <xsl:for-each select="//erlref"> + <xsl:variable name="cval" select="module"/> + <xsl:variable name="link_cval"><xsl:value-of select="translate($cval, '­', '')"/></xsl:variable> + <module name="{$cval}"> + <xsl:call-template name="menu.funcs"> + <xsl:with-param name="entries" select="funcs/func/name"/> + <xsl:with-param name="cval" select="$cval"/> + <xsl:with-param name="basename" select="$link_cval"/> + </xsl:call-template> + </module> + </xsl:for-each> + </xsl:variable> + <!-- Page layout --> <xsl:template name="pagelayout"> <xsl:param name="chapnum"/> @@ -1315,11 +1341,25 @@ Top of manual page </a> </li> - <xsl:call-template name="menu.funcs"> - <xsl:with-param name="entries" - select="funcs/func/name"/> - <xsl:with-param name="basename"><xsl:value-of select="$link_cval"/></xsl:with-param> - </xsl:call-template> + <xsl:call-template name="nl"/> + <xsl:choose> + <xsl:when test="local-name() = 'erlref'"> + <!-- Use the cached value in order to save time. + value-of a string node is _much_ faster than + copy-of a rtf --> + <xsl:value-of + disable-output-escaping="yes" + select="$erlref.nav/module[@name = $cval]"/> + </xsl:when> + <xsl:otherwise> + <xsl:call-template name="menu.funcs"> + <xsl:with-param name="entries" + select="funcs/func/name"/> + <xsl:with-param name="basename"><xsl:value-of select="$link_cval"/></xsl:with-param> + <xsl:with-param name="cval" select="$cval"/> + </xsl:call-template> + </xsl:otherwise> + </xsl:choose> </ul> </li> </xsl:when> @@ -1349,6 +1389,7 @@ <xsl:template name="menu.funcs"> <xsl:param name="entries"/> <xsl:param name="basename"/> + <xsl:param name="cval"/> <xsl:for-each select="$entries"> @@ -1434,17 +1475,41 @@ </xsl:choose> </xsl:variable> + <!-- Avoid duplicated entries. See also template "spec_name" --> + <!-- Do not to use preceding since it is very slow! --> + <xsl:variable name="mfas" + select="key('mfa', + concat($cval,':',$fname,'/',$arity))"/> <xsl:choose> - <xsl:when test="preceding-sibling::name[position() = 1 - and @name = $fname and @arity = $arity]"> + <xsl:when test="string-length(@name) > 0 and + generate-id($mfas[1]) != generate-id(.)"> <!-- Skip. Only works for Dialyzer specs. --> </xsl:when> <xsl:otherwise> +<!-- <li title="{$fname}-{$arity}"> <a href="{$basename}.html#{$fname}-{$arity}"> <xsl:value-of select="$fname"/>/<xsl:value-of select="$arity"/> </a> </li> +--> + <!-- Generate a text node --> + <xsl:text><li title="</xsl:text> + <xsl:value-of select="$fname"/> + <xsl:text>-</xsl:text> + <xsl:value-of select="$arity"/> + <xsl:text>"><a href="</xsl:text> + <xsl:value-of select="$basename"/> + <xsl:text>.html#</xsl:text> + <xsl:value-of select="$fname"/> + <xsl:text>-</xsl:text> + <xsl:value-of select="$arity"/> + <xsl:text>"></xsl:text> + <xsl:value-of select="$fname"/> + <xsl:text>/</xsl:text> + <xsl:value-of select="$arity"/> + <xsl:text></a></li></xsl:text> + <xsl:call-template name="nl"/> </xsl:otherwise> </xsl:choose> </xsl:when> @@ -1854,18 +1919,24 @@ <xsl:choose> <xsl:when test="string-length($filepart) > 0"> - <xsl:variable name="modulepart"><xsl:value-of select="substring-before($filepart, ':')"/></xsl:variable> + <!-- "Filepart#Linkpart" (or "Filepart#") --> + <xsl:variable name="app_part"><xsl:value-of select="substring-before($filepart, ':')"/></xsl:variable> <xsl:choose> - <xsl:when test="string-length($modulepart) > 0"> - <xsl:variable name="filepart1"><xsl:value-of select="substring-after($filepart, ':')"/></xsl:variable> - <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$modulepart}','{$filepart1}.html#{$linkpart}');"><xsl:apply-templates/></a></span> + <xsl:when test="string-length($app_part) > 0"> + <!-- "AppPart:ModPart#Linkpart" --> + <xsl:variable name="mod_part"><xsl:value-of select="substring-after($filepart, ':')"/></xsl:variable> + <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app_part}','{$mod_part}.html#{$linkpart}');"><xsl:apply-templates/></a></span> </xsl:when> <xsl:otherwise> + <!-- "Filepart#Linkpart (there is no ':' in Filepart) --> + <xsl:variable name="minus_prefix" + select="substring-before($linkpart, '-')"/> <xsl:choose> - <!-- Dialyzer seealso (the application is unknown) --> - <xsl:when test="string-length($specs_file) > 0 + <xsl:when test="$minus_prefix = 'type' + and string-length($specs_file) > 0 and count($i/specs/module[@name=$filepart]) = 0"> - <!-- Deemed to slow; use key() instead + <!-- Dialyzer seealso (the application is unknown) --> + <!-- Following code deemed too slow; use key() instead <xsl:variable name="app" select="$m2a/mod2app/module[@name=$filepart]"/> --> @@ -1877,41 +1948,45 @@ <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app}','{$filepart}.html#{$linkpart}');"><xsl:value-of select="$this"/></a></span> </xsl:when> <xsl:otherwise> - <!-- Unknown application; no link --> - <xsl:value-of select="$this"/> + <!-- Unknown application --> + <xsl:message terminate="yes"> + Error <xsl:value-of select="$filepart"/>: cannot find module exporting type + </xsl:message> </xsl:otherwise> </xsl:choose> </xsl:for-each> </xsl:when> <xsl:when test="string-length($linkpart) > 0"> + <!-- Still Filepart#Linkpart (there is no ':' in Filepart --> <span class="bold_code"><a href="{$filepart}.html#{$linkpart}"><xsl:apply-templates/></a></span> </xsl:when> <xsl:otherwise> + <!-- "Filepart#" (there is no ':' in Filepart --> <span class="bold_code"><a href="{$filepart}.html"><xsl:apply-templates/></a></span> </xsl:otherwise> </xsl:choose> </xsl:otherwise> </xsl:choose> + </xsl:when> <!-- string-length($filepart) > 0 --> + <xsl:when test="string-length($linkpart) > 0"> + <!-- "#Linkpart" --> + <span class="bold_code"><a href="#{$linkpart}"><xsl:apply-templates/></a></span> </xsl:when> <xsl:otherwise> - <xsl:choose> - <xsl:when test="string-length($linkpart) > 0"> - <span class="bold_code"><a href="#{$linkpart}"><xsl:apply-templates/></a></span> - </xsl:when> - <xsl:otherwise> - <xsl:variable name="modulepart"><xsl:value-of select="substring-before(@marker, ':')"/></xsl:variable> + <!-- "AppPart:Mod" or "Mod" (there is no '#') --> + <xsl:variable name="app_part"><xsl:value-of select="substring-before(@marker, ':')"/></xsl:variable> - <xsl:choose> - <xsl:when test="string-length($modulepart) > 0"> - <xsl:variable name="filepart1"><xsl:value-of select="substring-after(@marker, ':')"/></xsl:variable> - <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$modulepart}','{$filepart1}.html');"><xsl:apply-templates/></a></span> - </xsl:when> - <xsl:otherwise> - <span class="bold_code"><a href="{@marker}.html"><xsl:apply-templates/></a></span> - </xsl:otherwise> - </xsl:choose> - </xsl:otherwise> - </xsl:choose> + <xsl:choose> + <xsl:when test="string-length($app_part) > 0"> + <!-- "App:Mod" --> + <xsl:variable name="mod_part"><xsl:value-of select="substring-after(@marker, ':')"/></xsl:variable> + <span class="bold_code"><a href="javascript:erlhref('{$topdocdir}/../','{$app_part}','{$mod_part}.html');"><xsl:apply-templates/></a></span> + </xsl:when> + <xsl:otherwise> + <!-- "Mod" --> + <span class="bold_code"><a href="{@marker}.html"><xsl:apply-templates/></a></span> + </xsl:otherwise> + </xsl:choose> </xsl:otherwise> </xsl:choose> @@ -2200,4 +2275,9 @@ </xsl:template> + <xsl:template name="nl"> + <xsl:text> +</xsl:text> + </xsl:template> + </xsl:stylesheet> diff --git a/lib/erl_interface/doc/src/notes.xml b/lib/erl_interface/doc/src/notes.xml index 9a42ebfddf..4cb9532880 100644 --- a/lib/erl_interface/doc/src/notes.xml +++ b/lib/erl_interface/doc/src/notes.xml @@ -30,6 +30,44 @@ </header> <p>This document describes the changes made to the Erl_interface application.</p> +<section><title>Erl_Interface 3.7.6</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + An error when getting global names on OS X Lion has been + fixed. The error caused truncated strings to be returned + from the function.</p> + <p> + Own Id: OTP-9799</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + <item> + <p> + Eliminate use of deprecated regexp module</p> + <p> + Own Id: OTP-9810</p> + </item> + </list> + </section> + +</section> + <section><title>Erl_Interface 3.7.5</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/erl_interface/src/misc/ei_format.c b/lib/erl_interface/src/misc/ei_format.c index cf50f12451..c1e5d998e4 100644 --- a/lib/erl_interface/src/misc/ei_format.c +++ b/lib/erl_interface/src/misc/ei_format.c @@ -149,7 +149,7 @@ static int pdigit(const char** fmt, ei_x_buff* x) { const char* start = *fmt; char c; - int len, dotp=0; + int dotp=0; double d; long l; @@ -166,7 +166,6 @@ static int pdigit(const char** fmt, ei_x_buff* x) break; } --(*fmt); - len = *fmt - start; if (dotp) { sscanf(start, "%lf", &d); return ei_x_encode_double(x, d); diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk index 601958579c..2c402bba6c 100644 --- a/lib/erl_interface/vsn.mk +++ b/lib/erl_interface/vsn.mk @@ -1 +1 @@ -EI_VSN = 3.7.5 +EI_VSN = 3.7.6 diff --git a/lib/et/src/et_gs_contents_viewer.erl b/lib/et/src/et_gs_contents_viewer.erl index f6a87bd608..5331c7697a 100644 --- a/lib/et/src/et_gs_contents_viewer.erl +++ b/lib/et/src/et_gs_contents_viewer.erl @@ -21,6 +21,17 @@ %%---------------------------------------------------------------------- -module(et_gs_contents_viewer). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,editor,2}}, + {nowarn_deprecated_function,{gs,frame,2}}, + {nowarn_deprecated_function,{gs,menu,2}}, + {nowarn_deprecated_function,{gs,menubar,2}}, + {nowarn_deprecated_function,{gs,menubutton,2}}, + {nowarn_deprecated_function,{gs,menuitem,2}}, + {nowarn_deprecated_function,{gs,menuitem,3}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -behaviour(gen_server). diff --git a/lib/et/src/et_gs_viewer.erl b/lib/et/src/et_gs_viewer.erl index 0af7814d15..4e6f0e3f64 100644 --- a/lib/et/src/et_gs_viewer.erl +++ b/lib/et/src/et_gs_viewer.erl @@ -21,6 +21,23 @@ %%---------------------------------------------------------------------- -module(et_gs_viewer). +-compile([{nowarn_deprecated_function,{gs,canvas,2}}, + {nowarn_deprecated_function,{gs,checkbutton,3}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,frame,2}}, + {nowarn_deprecated_function,{gs,line,2}}, + {nowarn_deprecated_function,{gs,menu,2}}, + {nowarn_deprecated_function,{gs,menu,3}}, + {nowarn_deprecated_function,{gs,menubar,2}}, + {nowarn_deprecated_function,{gs,menubutton,2}}, + {nowarn_deprecated_function,{gs,menubutton,3}}, + {nowarn_deprecated_function,{gs,menuitem,2}}, + {nowarn_deprecated_function,{gs,menuitem,3}}, + {nowarn_deprecated_function,{gs,scale,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,text,2}}, + {nowarn_deprecated_function,{gs,window,2}}]). -behaviour(gen_server). diff --git a/lib/eunit/doc/src/notes.xml b/lib/eunit/doc/src/notes.xml index e68330482c..34e8a47e3d 100644 --- a/lib/eunit/doc/src/notes.xml +++ b/lib/eunit/doc/src/notes.xml @@ -32,6 +32,24 @@ </header> <p>This document describes the changes made to the EUnit application.</p> +<section><title>Eunit 2.2.2</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + </list> + </section> + +</section> + <section><title>Eunit 2.2.1</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk index b0a77a225b..445c070e96 100644 --- a/lib/eunit/vsn.mk +++ b/lib/eunit/vsn.mk @@ -1 +1 @@ -EUNIT_VSN = 2.2.1 +EUNIT_VSN = 2.2.2 diff --git a/lib/gs/contribs/bonk/bonk.erl b/lib/gs/contribs/bonk/bonk.erl index 79f01bf659..7e68a4ddc5 100644 --- a/lib/gs/contribs/bonk/bonk.erl +++ b/lib/gs/contribs/bonk/bonk.erl @@ -19,6 +19,12 @@ %% -module(bonk). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,start,0}}]). + -export([run/0, run/1,bonk_dir/0,start/0]). -record(colors, {miss, x, bomb, face}). diff --git a/lib/gs/contribs/cols/cols.erl b/lib/gs/contribs/cols/cols.erl index 111c9a58f1..9c44837f3e 100644 --- a/lib/gs/contribs/cols/cols.erl +++ b/lib/gs/contribs/cols/cols.erl @@ -19,6 +19,12 @@ %% -module(cols). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}]). -export([start/0, init/0]). diff --git a/lib/gs/contribs/cols/highscore.erl b/lib/gs/contribs/cols/highscore.erl index 9ffbea50a7..8f984aaa83 100644 --- a/lib/gs/contribs/cols/highscore.erl +++ b/lib/gs/contribs/cols/highscore.erl @@ -19,6 +19,13 @@ %% -module(highscore). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,grid,2}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -export([run/2]). diff --git a/lib/gs/contribs/mandel/mandel.erl b/lib/gs/contribs/mandel/mandel.erl index 0f1df5c665..6293f867e2 100644 --- a/lib/gs/contribs/mandel/mandel.erl +++ b/lib/gs/contribs/mandel/mandel.erl @@ -18,6 +18,11 @@ %% -module(mandel). +-compile([{nowarn_deprecated_function,{gs,assq,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,image,2}}, + {nowarn_deprecated_function,{gs,start,0}}]). -author('(mbj,eklas)@erlang.ericsson.se'). %% User's interface diff --git a/lib/gs/contribs/othello/othello_board.erl b/lib/gs/contribs/othello/othello_board.erl index 212ba9bfe1..c52211a495 100644 --- a/lib/gs/contribs/othello/othello_board.erl +++ b/lib/gs/contribs/othello/othello_board.erl @@ -19,6 +19,12 @@ %% -module(othello_board). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,start,0}}]). + -export([start/0,stop/0,init/0]). diff --git a/lib/gs/doc/src/gs.xml b/lib/gs/doc/src/gs.xml index f2182fc673..c61e8c4938 100644 --- a/lib/gs/doc/src/gs.xml +++ b/lib/gs/doc/src/gs.xml @@ -39,9 +39,7 @@ graphical user interface. </p> <p> - GS is not maintained and we plan to deprecate and remove it from - the distribution as soon as possible, maybe already in the next - major release (R15). + GS is deprecated and will be removed in the R16 release. </p> </warning> <p>The Graphics System, GS, is easy to learn and diff --git a/lib/gs/doc/src/notes.xml b/lib/gs/doc/src/notes.xml index f56f9ea6ec..cd63104346 100644 --- a/lib/gs/doc/src/notes.xml +++ b/lib/gs/doc/src/notes.xml @@ -30,7 +30,31 @@ </header> <p>This document describes the changes made to the GS application.</p> - <section><title>GS 1.5.14</title> + <section><title>GS 1.5.15</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + <item> + <p> + Eliminate use of deprecated regexp module</p> + <p> + Own Id: OTP-9810</p> + </item> + </list> + </section> + +</section> + +<section><title>GS 1.5.14</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/gs/examples/ball.erl b/lib/gs/examples/ball.erl index 3f91a7b379..03fac3b5fc 100644 --- a/lib/gs/examples/ball.erl +++ b/lib/gs/examples/ball.erl @@ -24,6 +24,12 @@ %% ------------------------------------------------------------ -module(ball). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,canvas,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,oval,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -export([start/0,init/0]). diff --git a/lib/gs/examples/browser.erl b/lib/gs/examples/browser.erl index 1dba5a915b..0f8b3fc7e6 100644 --- a/lib/gs/examples/browser.erl +++ b/lib/gs/examples/browser.erl @@ -23,6 +23,14 @@ %% ------------------------------------------------------------ -module(browser). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,entry,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,listbox,2}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -export([start/0,start/2,init/3]). diff --git a/lib/gs/examples/calc.erl b/lib/gs/examples/calc.erl index 992b8adb4e..ca29ae1cb9 100644 --- a/lib/gs/examples/calc.erl +++ b/lib/gs/examples/calc.erl @@ -23,6 +23,11 @@ %% ------------------------------------------------------------ -module(calc). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -export([start/0,calc/0]). diff --git a/lib/gs/examples/calc2.erl b/lib/gs/examples/calc2.erl index 0e841397f6..83e1870b7a 100644 --- a/lib/gs/examples/calc2.erl +++ b/lib/gs/examples/calc2.erl @@ -24,6 +24,12 @@ %% ------------------------------------------------------------ -module(calc2). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). + -export([start/0,calc/0]). start() -> diff --git a/lib/gs/examples/color_demo.erl b/lib/gs/examples/color_demo.erl index 650f853061..a2f4d0eb87 100644 --- a/lib/gs/examples/color_demo.erl +++ b/lib/gs/examples/color_demo.erl @@ -24,6 +24,11 @@ %% ------------------------------------------------------------ -module(color_demo). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,scale,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -export([start/0,init/0]). diff --git a/lib/gs/examples/color_demo2.erl b/lib/gs/examples/color_demo2.erl index 817cc9ed7d..3b0b36221d 100644 --- a/lib/gs/examples/color_demo2.erl +++ b/lib/gs/examples/color_demo2.erl @@ -24,6 +24,10 @@ %% ------------------------------------------------------------ -module(color_demo2). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,start,0}}]). -export([start/0,init/0]). diff --git a/lib/gs/examples/distrib_draw.erl b/lib/gs/examples/distrib_draw.erl index ecb1386c25..8f76bc6650 100644 --- a/lib/gs/examples/distrib_draw.erl +++ b/lib/gs/examples/distrib_draw.erl @@ -43,6 +43,11 @@ %% -module(distrib_draw). +-compile([{nowarn_deprecated_function,{gs,canvas,3}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,line,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). -export([start/2,init/0]). diff --git a/lib/gs/examples/entry_demo.erl b/lib/gs/examples/entry_demo.erl index a5ecfbc4d3..4bb64e949e 100644 --- a/lib/gs/examples/entry_demo.erl +++ b/lib/gs/examples/entry_demo.erl @@ -23,6 +23,12 @@ %% ------------------------------------------------------------ -module(entry_demo). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -export([start/0,init/1]). diff --git a/lib/gs/examples/event_test.erl b/lib/gs/examples/event_test.erl index f6fcc9b4b9..8c0a109df4 100644 --- a/lib/gs/examples/event_test.erl +++ b/lib/gs/examples/event_test.erl @@ -21,6 +21,9 @@ %% Demo for testing some events -module(event_test). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -export([start/0,init/0]). diff --git a/lib/gs/examples/file_dialog.erl b/lib/gs/examples/file_dialog.erl index ff20321374..c1ef6ed8b1 100644 --- a/lib/gs/examples/file_dialog.erl +++ b/lib/gs/examples/file_dialog.erl @@ -23,6 +23,11 @@ %% ------------------------------------------------------------ -module(file_dialog). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}]). -export([start/0,start/1,start/2,fs_init/3]). diff --git a/lib/gs/examples/focus_demo.erl b/lib/gs/examples/focus_demo.erl index b9d86866e6..71ca9c6ff5 100644 --- a/lib/gs/examples/focus_demo.erl +++ b/lib/gs/examples/focus_demo.erl @@ -23,6 +23,11 @@ %% ------------------------------------------------------------ -module(focus_demo). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -export([start/0,init/0]). diff --git a/lib/gs/examples/frac.erl b/lib/gs/examples/frac.erl index 139a4be310..46af83de8a 100644 --- a/lib/gs/examples/frac.erl +++ b/lib/gs/examples/frac.erl @@ -21,6 +21,9 @@ %% Purpose : Fractal trees -module(frac). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,start,0}}]). -export([start/0, go/0, test/0, grow/2, expand/3, subst/2]). diff --git a/lib/gs/examples/line_demo.erl b/lib/gs/examples/line_demo.erl index c8a6a69e2e..ba88605118 100644 --- a/lib/gs/examples/line_demo.erl +++ b/lib/gs/examples/line_demo.erl @@ -24,6 +24,12 @@ %% ------------------------------------------------------------ -module(line_demo). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,canvas,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,line,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -export([start/0,init/0,line/3]). diff --git a/lib/gs/examples/man.erl b/lib/gs/examples/man.erl index a0ffd3364e..bddd6930ab 100644 --- a/lib/gs/examples/man.erl +++ b/lib/gs/examples/man.erl @@ -23,6 +23,15 @@ %% ------------------------------------------------------------ -module(man). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,entry,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,listbox,2}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). -export([start/0,init/0]). -export([man_list/0]). diff --git a/lib/gs/examples/menu_demo.erl b/lib/gs/examples/menu_demo.erl index c95fc33152..6b2fc4113a 100644 --- a/lib/gs/examples/menu_demo.erl +++ b/lib/gs/examples/menu_demo.erl @@ -19,6 +19,12 @@ %% -module(menu_demo). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -compile(export_all). diff --git a/lib/gs/examples/rubber.erl b/lib/gs/examples/rubber.erl index ba263f07ac..da4aa57391 100644 --- a/lib/gs/examples/rubber.erl +++ b/lib/gs/examples/rubber.erl @@ -23,6 +23,14 @@ %% ------------------------------------------------------------ -module(rubber). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,canvas,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,radiobutton,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -export([start/0, init/0]). diff --git a/lib/gs/src/gs.erl b/lib/gs/src/gs.erl index 3e9a1c4b8b..92dce12580 100644 --- a/lib/gs/src/gs.erl +++ b/lib/gs/src/gs.erl @@ -24,7 +24,13 @@ %% -module(gs). - +-deprecated(module). +-compile([{nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,create_tree,2}}, + {nowarn_deprecated_function,{gs,foreach,3}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,1}}]). %% ----- Exports ----- -export([start/0, stop/0, start/1]). diff --git a/lib/gs/src/gs_frontend.erl b/lib/gs/src/gs_frontend.erl index 009b264e69..73954baa8d 100644 --- a/lib/gs/src/gs_frontend.erl +++ b/lib/gs/src/gs_frontend.erl @@ -24,6 +24,8 @@ %% -module(gs_frontend). +-compile([{nowarn_deprecated_function,{gs,assq,2}}, + {nowarn_deprecated_function,{gs,error,2}}]). -export([create/2, config/2, diff --git a/lib/gs/src/gs_make.erl b/lib/gs/src/gs_make.erl index e41183f9bf..bf8a66001f 100644 --- a/lib/gs/src/gs_make.erl +++ b/lib/gs/src/gs_make.erl @@ -19,6 +19,7 @@ %% -module(gs_make). +-compile([{nowarn_deprecated_function,{gs,assq,2}}]). -export([start/0]). diff --git a/lib/gs/src/gse.erl b/lib/gs/src/gse.erl index b3ea2af4d4..c62badcc27 100644 --- a/lib/gs/src/gse.erl +++ b/lib/gs/src/gse.erl @@ -23,6 +23,68 @@ %%%---------------------------------------------------------------------- -module(gse). +-compile([{nowarn_deprecated_function,{gs,arc,2}}, + {nowarn_deprecated_function,{gs,arc,3}}, + {nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,button,3}}, + {nowarn_deprecated_function,{gs,canvas,2}}, + {nowarn_deprecated_function,{gs,canvas,3}}, + {nowarn_deprecated_function,{gs,checkbutton,2}}, + {nowarn_deprecated_function,{gs,checkbutton,3}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,create_tree,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,editor,2}}, + {nowarn_deprecated_function,{gs,editor,3}}, + {nowarn_deprecated_function,{gs,entry,2}}, + {nowarn_deprecated_function,{gs,entry,3}}, + {nowarn_deprecated_function,{gs,frame,2}}, + {nowarn_deprecated_function,{gs,frame,3}}, + {nowarn_deprecated_function,{gs,grid,2}}, + {nowarn_deprecated_function,{gs,grid,3}}, + {nowarn_deprecated_function,{gs,gridline,2}}, + {nowarn_deprecated_function,{gs,gridline,3}}, + {nowarn_deprecated_function,{gs,image,2}}, + {nowarn_deprecated_function,{gs,image,3}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,label,3}}, + {nowarn_deprecated_function,{gs,line,2}}, + {nowarn_deprecated_function,{gs,line,3}}, + {nowarn_deprecated_function,{gs,listbox,2}}, + {nowarn_deprecated_function,{gs,listbox,3}}, + {nowarn_deprecated_function,{gs,menu,2}}, + {nowarn_deprecated_function,{gs,menu,3}}, + {nowarn_deprecated_function,{gs,menubar,2}}, + {nowarn_deprecated_function,{gs,menubar,3}}, + {nowarn_deprecated_function,{gs,menubutton,2}}, + {nowarn_deprecated_function,{gs,menubutton,3}}, + {nowarn_deprecated_function,{gs,menuitem,2}}, + {nowarn_deprecated_function,{gs,menuitem,3}}, + {nowarn_deprecated_function,{gs,message,2}}, + {nowarn_deprecated_function,{gs,message,3}}, + {nowarn_deprecated_function,{gs,oval,2}}, + {nowarn_deprecated_function,{gs,oval,3}}, + {nowarn_deprecated_function,{gs,polygon,2}}, + {nowarn_deprecated_function,{gs,polygon,3}}, + {nowarn_deprecated_function,{gs,prompter,2}}, + {nowarn_deprecated_function,{gs,prompter,3}}, + {nowarn_deprecated_function,{gs,radiobutton,2}}, + {nowarn_deprecated_function,{gs,radiobutton,3}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,rectangle,2}}, + {nowarn_deprecated_function,{gs,rectangle,3}}, + {nowarn_deprecated_function,{gs,scale,2}}, + {nowarn_deprecated_function,{gs,scale,3}}, + {nowarn_deprecated_function,{gs,scrollbar,2}}, + {nowarn_deprecated_function,{gs,scrollbar,3}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,start,1}}, + {nowarn_deprecated_function,{gs,text,2}}, + {nowarn_deprecated_function,{gs,text,3}}, + {nowarn_deprecated_function,{gs,window,2}}, + {nowarn_deprecated_function,{gs,window,3}}]). %%-compile(export_all). -export([ diff --git a/lib/gs/src/gstk.erl b/lib/gs/src/gstk.erl index 6f83cf8be4..ee974a5f63 100644 --- a/lib/gs/src/gstk.erl +++ b/lib/gs/src/gstk.erl @@ -20,6 +20,8 @@ %% -module(gstk). +-compile([{nowarn_deprecated_function,{gs,assq,2}}, + {nowarn_deprecated_function,{gs,creation_error,2}}]). -export([start_link/4, stop/1, diff --git a/lib/gs/src/gstk_arc.erl b/lib/gs/src/gstk_arc.erl index 8e80ef92b5..3c6fe54d36 100644 --- a/lib/gs/src/gstk_arc.erl +++ b/lib/gs/src/gstk_arc.erl @@ -23,6 +23,7 @@ %% ------------------------------------------------------------ -module(gstk_arc). +-compile([{nowarn_deprecated_function,{gs,creation_error,2}}]). %%----------------------------------------------------------------------------- %% ARC OPTIONS diff --git a/lib/gs/src/gstk_canvas.erl b/lib/gs/src/gstk_canvas.erl index 868b3020fe..5d15529995 100644 --- a/lib/gs/src/gstk_canvas.erl +++ b/lib/gs/src/gstk_canvas.erl @@ -23,6 +23,8 @@ %% ------------------------------------------------------------ -module(gstk_canvas). +-compile([{nowarn_deprecated_function,{gs,pair,2}}, + {nowarn_deprecated_function,{gs,val,2}}]). %%----------------------------------------------------------------------------- %% CANVAS OPTIONS diff --git a/lib/gs/src/gstk_editor.erl b/lib/gs/src/gstk_editor.erl index 6b90cee1d2..2686997036 100644 --- a/lib/gs/src/gstk_editor.erl +++ b/lib/gs/src/gstk_editor.erl @@ -23,6 +23,9 @@ %% ------------------------------------------------------------ -module(gstk_editor). +-compile([{nowarn_deprecated_function,{gs,assq,2}}, + {nowarn_deprecated_function,{gs,error,2}}, + {nowarn_deprecated_function,{gs,val,2}}]). %%------------------------------------------------------------------------------ %% CANVAS OPTIONS diff --git a/lib/gs/src/gstk_entry.erl b/lib/gs/src/gstk_entry.erl index 14f7831151..432ccd5fde 100644 --- a/lib/gs/src/gstk_entry.erl +++ b/lib/gs/src/gstk_entry.erl @@ -23,6 +23,7 @@ %% ------------------------------------------------------------ -module(gstk_entry). +-compile([{nowarn_deprecated_function,{gs,error,2}}]). %%------------------------------------------------------------------------------ %% ENTRY OPTIONS diff --git a/lib/gs/src/gstk_generic.erl b/lib/gs/src/gstk_generic.erl index 8fe19b428c..50c3da8dc5 100644 --- a/lib/gs/src/gstk_generic.erl +++ b/lib/gs/src/gstk_generic.erl @@ -20,6 +20,7 @@ %% -module(gstk_generic). +-compile([{nowarn_deprecated_function,{gs,assq,2}}]). -export([out_opts/8, read_option/5, diff --git a/lib/gs/src/gstk_grid.erl b/lib/gs/src/gstk_grid.erl index 4189246822..f703dad074 100644 --- a/lib/gs/src/gstk_grid.erl +++ b/lib/gs/src/gstk_grid.erl @@ -19,6 +19,7 @@ %% -module(gstk_grid). +-compile([{nowarn_deprecated_function,{gs,val,2}}]). -export([event/5,create/3,config/3,option/5,read/3,delete/2,destroy/2, mk_create_opts_for_child/4,read_option/5]). diff --git a/lib/gs/src/gstk_gridline.erl b/lib/gs/src/gstk_gridline.erl index c1dd5a1443..4585c7e043 100644 --- a/lib/gs/src/gstk_gridline.erl +++ b/lib/gs/src/gstk_gridline.erl @@ -19,6 +19,8 @@ %% -module(gstk_gridline). +-compile([{nowarn_deprecated_function,{gs,val,2}}, + {nowarn_deprecated_function,{gs,val,3}}]). -export([event/5,create/3,config/3,option/5,read/3,delete/2,destroy/3, read_option/5]). diff --git a/lib/gs/src/gstk_image.erl b/lib/gs/src/gstk_image.erl index 53789b312d..2b7a324e28 100644 --- a/lib/gs/src/gstk_image.erl +++ b/lib/gs/src/gstk_image.erl @@ -23,6 +23,7 @@ %% ------------------------------------------------------------ -module(gstk_image). +-compile([{nowarn_deprecated_function,{gs,pair,2}}]). %%----------------------------------------------------------------------------- %% BITMAP OPTIONS diff --git a/lib/gs/src/gstk_menu.erl b/lib/gs/src/gstk_menu.erl index 3957951a35..e878669de6 100644 --- a/lib/gs/src/gstk_menu.erl +++ b/lib/gs/src/gstk_menu.erl @@ -23,6 +23,7 @@ %%------------------------------------------------------------------------------ -module(gstk_menu). +-compile([{nowarn_deprecated_function,{gs,error,2}}]). %%------------------------------------------------------------------------------ %% MENU OPTIONS diff --git a/lib/gs/src/gstk_menuitem.erl b/lib/gs/src/gstk_menuitem.erl index 36a9253598..8abf5d13aa 100644 --- a/lib/gs/src/gstk_menuitem.erl +++ b/lib/gs/src/gstk_menuitem.erl @@ -23,6 +23,7 @@ %% ------------------------------------------------------------ -module(gstk_menuitem). +-compile([{nowarn_deprecated_function,{gs,error,2}}]). %%----------------------------------------------------------------------------- %% MENUITEM OPTIONS diff --git a/lib/gs/src/gstk_port_handler.erl b/lib/gs/src/gstk_port_handler.erl index 93f3e58dc2..c6ca2c0f5b 100644 --- a/lib/gs/src/gstk_port_handler.erl +++ b/lib/gs/src/gstk_port_handler.erl @@ -34,6 +34,7 @@ %% ------------------------------------------------------------ -module(gstk_port_handler). +-compile([{nowarn_deprecated_function,{gs,error,2}}]). -include("gstk.hrl"). diff --git a/lib/gs/src/gstk_rectangle.erl b/lib/gs/src/gstk_rectangle.erl index 1e02977c9a..14be16c990 100644 --- a/lib/gs/src/gstk_rectangle.erl +++ b/lib/gs/src/gstk_rectangle.erl @@ -23,6 +23,7 @@ %% ------------------------------------------------------------ -module(gstk_rectangle). +-compile([{nowarn_deprecated_function,{gs,pair,2}}]). %%----------------------------------------------------------------------------- %% RECTANGLE OPTIONS diff --git a/lib/gs/src/gstk_window.erl b/lib/gs/src/gstk_window.erl index acac452ed1..4b4706eb88 100644 --- a/lib/gs/src/gstk_window.erl +++ b/lib/gs/src/gstk_window.erl @@ -23,6 +23,7 @@ %% ------------------------------------------------------------ -module(gstk_window). +-compile([{nowarn_deprecated_function,{gs,destroy,1}}]). %%------------------------------------------------------------------------------ %% WINDOW OPTIONS diff --git a/lib/gs/src/tcl2erl.erl b/lib/gs/src/tcl2erl.erl index 8845cf0b9a..d159681c5c 100644 --- a/lib/gs/src/tcl2erl.erl +++ b/lib/gs/src/tcl2erl.erl @@ -25,6 +25,7 @@ %% ------------------------------------------------------------ -module(tcl2erl). +-compile([{nowarn_deprecated_function,{gs,error,2}}]). -export([parse_event/1, ret_int/1, diff --git a/lib/gs/src/tool_file_dialog.erl b/lib/gs/src/tool_file_dialog.erl index 6b2c2e8c81..cfcfcd1bf6 100644 --- a/lib/gs/src/tool_file_dialog.erl +++ b/lib/gs/src/tool_file_dialog.erl @@ -19,6 +19,16 @@ %% -module(tool_file_dialog). +-compile([{nowarn_deprecated_function,{gs,button,3}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,entry,3}}, + {nowarn_deprecated_function,{gs,frame,3}}, + {nowarn_deprecated_function,{gs,label,3}}, + {nowarn_deprecated_function,{gs,listbox,3}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). + -export([start/1]). -record(opts, {type, % open | save | multiselect diff --git a/lib/gs/src/tool_utils.erl b/lib/gs/src/tool_utils.erl index f1b93c1af8..69919b18bd 100644 --- a/lib/gs/src/tool_utils.erl +++ b/lib/gs/src/tool_utils.erl @@ -19,6 +19,11 @@ %% -module(tool_utils). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,read,2}}]). + -include_lib("kernel/include/file.hrl"). %%%--------------------------------------------------------------------- diff --git a/lib/gs/vsn.mk b/lib/gs/vsn.mk index 4894c6c13a..41a2561809 100644 --- a/lib/gs/vsn.mk +++ b/lib/gs/vsn.mk @@ -1,2 +1,2 @@ -GS_VSN = 1.5.14 +GS_VSN = 1.5.15 diff --git a/lib/hipe/cerl/cerl_hipe_primops.hrl b/lib/hipe/cerl/cerl_hipe_primops.hrl index 36b1b62901..1d82f7bfc7 100644 --- a/lib/hipe/cerl/cerl_hipe_primops.hrl +++ b/lib/hipe/cerl/cerl_hipe_primops.hrl @@ -59,7 +59,6 @@ -define(PRIMOP_IS_ATOM, 'is_atom'). % arity 1 -define(PRIMOP_IS_BIGNUM, 'is_bignum'). % arity 1 -define(PRIMOP_IS_BINARY, 'is_binary'). % arity 1 --define(PRIMOP_IS_CONSTANT, 'is_constant'). % arity 1 -define(PRIMOP_IS_FIXNUM, 'is_fixnum'). % arity 1 -define(PRIMOP_IS_FLOAT, 'is_float'). % arity 1 -define(PRIMOP_IS_FUNCTION, 'is_function'). % arity 1 diff --git a/lib/hipe/cerl/cerl_hipeify.erl b/lib/hipe/cerl/cerl_hipeify.erl index 8f6c3561c9..89b4ec147d 100644 --- a/lib/hipe/cerl/cerl_hipeify.erl +++ b/lib/hipe/cerl/cerl_hipeify.erl @@ -392,7 +392,6 @@ call_to_primop(erlang, '=<', 2) -> {yes, ?PRIMOP_LE}; call_to_primop(erlang, '>=', 2) -> {yes, ?PRIMOP_GE}; call_to_primop(erlang, is_atom, 1) -> {yes, ?PRIMOP_IS_ATOM}; call_to_primop(erlang, is_binary, 1) -> {yes, ?PRIMOP_IS_BINARY}; -call_to_primop(erlang, is_constant, 1) -> {yes, ?PRIMOP_IS_CONSTANT}; call_to_primop(erlang, is_float, 1) -> {yes, ?PRIMOP_IS_FLOAT}; call_to_primop(erlang, is_function, 1) -> {yes, ?PRIMOP_IS_FUNCTION}; call_to_primop(erlang, is_integer, 1) -> {yes, ?PRIMOP_IS_INTEGER}; diff --git a/lib/hipe/cerl/cerl_messagean.erl b/lib/hipe/cerl/cerl_messagean.erl index 6dd93adaa3..b9f82f2a43 100644 --- a/lib/hipe/cerl/cerl_messagean.erl +++ b/lib/hipe/cerl/cerl_messagean.erl @@ -1083,7 +1083,6 @@ is_imm_op(erlang, is_alive, 0) -> true; is_imm_op(erlang, is_atom, 1) -> true; is_imm_op(erlang, is_binary, 1) -> true; is_imm_op(erlang, is_builtin, 3) -> true; -is_imm_op(erlang, is_constant, 1) -> true; is_imm_op(erlang, is_float, 1) -> true; is_imm_op(erlang, is_function, 1) -> true; is_imm_op(erlang, is_integer, 1) -> true; diff --git a/lib/hipe/cerl/cerl_to_icode.erl b/lib/hipe/cerl/cerl_to_icode.erl index 362c427cbe..089e3f021e 100644 --- a/lib/hipe/cerl/cerl_to_icode.erl +++ b/lib/hipe/cerl/cerl_to_icode.erl @@ -88,7 +88,6 @@ -define(TYPE_IS_ATOM, atom). -define(TYPE_IS_BIGNUM, bignum). -define(TYPE_IS_BINARY, binary). --define(TYPE_IS_CONSTANT, constant). -define(TYPE_IS_FIXNUM, fixnum). -define(TYPE_IS_FLOAT, float). -define(TYPE_IS_FUNCTION, function). @@ -2051,7 +2050,6 @@ is_record_test(T, A, N, True, False, Ctxt, Env, S) -> type_test(?PRIMOP_IS_ATOM) -> ?TYPE_IS_ATOM; type_test(?PRIMOP_IS_BIGNUM) -> ?TYPE_IS_BIGNUM; type_test(?PRIMOP_IS_BINARY) -> ?TYPE_IS_BINARY; -type_test(?PRIMOP_IS_CONSTANT) -> ?TYPE_IS_CONSTANT; type_test(?PRIMOP_IS_FIXNUM) -> ?TYPE_IS_FIXNUM; type_test(?PRIMOP_IS_FLOAT) -> ?TYPE_IS_FLOAT; type_test(?PRIMOP_IS_FUNCTION) -> ?TYPE_IS_FUNCTION; @@ -2082,7 +2080,6 @@ is_bool_op(Op, A) when is_atom(Op), is_integer(A) -> false. is_type_test(?PRIMOP_IS_ATOM, 1) -> true; is_type_test(?PRIMOP_IS_BIGNUM, 1) -> true; is_type_test(?PRIMOP_IS_BINARY, 1) -> true; -is_type_test(?PRIMOP_IS_CONSTANT, 1) -> true; is_type_test(?PRIMOP_IS_FIXNUM, 1) -> true; is_type_test(?PRIMOP_IS_FLOAT, 1) -> true; is_type_test(?PRIMOP_IS_FUNCTION, 1) -> true; diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index cee399e861..845df0ca61 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -54,7 +54,6 @@ t_cons/2, t_cons_hd/1, t_cons_tl/1, - t_constant/0, t_fixnum/0, t_non_neg_fixnum/0, t_pos_fixnum/0, @@ -81,7 +80,6 @@ t_is_bitstr/1, t_is_boolean/1, t_is_cons/1, - t_is_constant/1, t_is_float/1, t_is_float/1, t_is_fun/1, @@ -845,11 +843,6 @@ type(erlang, is_boolean, 1, Xs) -> strict(arg_types(erlang, is_boolean, 1), Xs, Fun); type(erlang, is_builtin, 3, Xs) -> strict(arg_types(erlang, is_builtin, 3), Xs, fun (_) -> t_boolean() end); -type(erlang, is_constant, 1, Xs) -> - Fun = fun (X) -> - check_guard(X, fun (Y) -> t_is_constant(Y) end, t_constant()) - end, - strict(arg_types(erlang, is_constant, 1), Xs, Fun); type(erlang, is_float, 1, Xs) -> Fun = fun (X) -> check_guard(X, fun (Y) -> t_is_float(Y) end, t_float()) @@ -1202,11 +1195,13 @@ type(erlang, process_flag, 2, Xs) -> case t_atom_vals(Flag) of ['error_handler'] -> t_atom(); ['min_heap_size'] -> t_non_neg_integer(); + ['min_bin_vheap_size'] -> t_non_neg_integer(); ['scheduler'] -> t_non_neg_integer(); ['monitor_nodes'] -> t_boolean(); ['priority'] -> t_process_priority_level(); ['save_calls'] -> t_non_neg_integer(); ['trap_exit'] -> t_boolean(); + ['sensitive'] -> t_boolean(); List when is_list(List) -> T_process_flag_returns; unknown -> @@ -1503,6 +1498,8 @@ type(erlang, system_flag, 2, Xs) -> t_non_neg_fixnum(); ['min_heap_size'] -> t_non_neg_fixnum(); + ['min_bin_vheap_size'] -> + t_non_neg_fixnum(); ['multi_scheduling'] -> t_system_multi_scheduling(); ['schedulers_online'] -> @@ -1546,8 +1543,12 @@ type(erlang, system_info, 1, Xs) -> t_list(t_tuple([t_atom(), t_list(t_tuple([t_atom(), t_any()]))]))]); + ['build_type'] -> + t_system_build_type_return(); ['break_ignored'] -> t_boolean(); + ['c_compiler_used'] -> + t_tuple([t_atom(), t_any()]); ['cpu_topology'] -> t_system_cpu_topology(); ['compat_rel'] -> @@ -1560,6 +1561,8 @@ type(erlang, system_info, 1, Xs) -> t_binary(); ['dist_ctrl'] -> t_list(t_tuple([t_atom(), t_sup([t_pid(), t_port])])); + ['driver_version'] -> + t_string(); %% elib_malloc is intentionally not included, %% because it scheduled for removal in R15. ['endian'] -> @@ -1573,7 +1576,9 @@ type(erlang, system_info, 1, Xs) -> ['heap_sizes'] -> t_list(t_integer()); ['heap_type'] -> - t_sup([t_atom('private'), t_atom('hybrid')]); + t_sup([t_atom('private'), + t_atom('shared'), + t_atom('hybrid')]); ['hipe_architecture'] -> t_atoms(['amd64', 'arm', 'powerpc', 'ppc64', 'undefined', 'ultrasparc', 'x86']); @@ -1581,12 +1586,20 @@ type(erlang, system_info, 1, Xs) -> t_binary(); ['internal_cpu_topology'] -> %% Undocumented internal feature t_internal_cpu_topology(); + ['kernel_poll'] -> + t_boolean(); ['loaded'] -> t_binary(); ['logical_processors'] -> t_non_neg_fixnum(); ['machine'] -> t_string(); + ['min_heap_size'] -> + t_tuple([t_atom('min_heap_size'), + t_non_neg_integer()]); + ['min_bin_vheap_size'] -> + t_tuple([t_atom('min_bin_vheap_size'), + t_non_neg_integer()]); ['multi_scheduling'] -> t_system_multi_scheduling(); ['multi_scheduling_blockers'] -> @@ -1601,6 +1614,8 @@ type(erlang, system_info, 1, Xs) -> t_non_neg_fixnum(), t_non_neg_fixnum()]), t_string()); + ['otp_release'] -> + t_string(); ['process_count'] -> t_non_neg_fixnum(); ['process_limit'] -> @@ -1630,6 +1645,8 @@ type(erlang, system_info, 1, Xs) -> t_non_neg_fixnum(); ['trace_control_word'] -> t_integer(); + ['update_cpu_info'] -> + t_sup([t_atom('changed'), t_atom('unchanged')]); ['version'] -> t_string(); ['wordsize'] -> @@ -3567,8 +3584,6 @@ arg_types(erlang, is_boolean, 1) -> [t_any()]; arg_types(erlang, is_builtin, 3) -> [t_atom(), t_atom(), t_arity()]; -arg_types(erlang, is_constant, 1) -> - [t_any()]; arg_types(erlang, is_float, 1) -> [t_any()]; arg_types(erlang, is_function, 1) -> @@ -3747,8 +3762,13 @@ arg_types(erlang, pre_loaded, 0) -> arg_types(erlang, process_display, 2) -> [t_pid(), t_atom('backtrace')]; arg_types(erlang, process_flag, 2) -> - [t_sup([t_atom('trap_exit'), t_atom('error_handler'), - t_atom('min_heap_size'), t_atom('priority'), t_atom('save_calls'), + [t_sup([t_atom('trap_exit'), + t_atom('error_handler'), + t_atom('min_heap_size'), + t_atom('min_bin_vheap_size'), + t_atom('priority'), + t_atom('save_calls'), + t_atom('sensitive'), t_atom('scheduler'), % undocumented t_atom('monitor_nodes'), % undocumented t_tuple([t_atom('monitor_nodes'), t_list()])]), % undocumented @@ -3861,6 +3881,7 @@ arg_types(erlang, system_flag, 2) -> t_atom('display_items'), % undocumented t_atom('fullsweep_after'), t_atom('min_heap_size'), + t_atom('min_bin_vheap_size'), t_atom('multi_scheduling'), t_atom('schedulers_online'), t_atom('scheduler_bind_type'), @@ -4733,6 +4754,7 @@ t_spawn_options() -> t_atom('monitor'), t_tuple([t_atom('priority'), t_process_priority_level()]), t_tuple([t_atom('min_heap_size'), t_fixnum()]), + t_tuple([t_atom('min_bin_vheap_size'), t_fixnum()]), t_tuple([t_atom('fullsweep_after'), t_fixnum()])]). t_spawn_opt_return(List) -> @@ -4821,6 +4843,17 @@ t_system_profile_return() -> t_sup(t_atom('undefined'), t_tuple([t_sup(t_pid(), t_port()), t_system_profile_options()])). +t_system_build_type_return() -> + t_sup([t_atom('opt'), + t_atom('debug'), + t_atom('purify'), + t_atom('quantify'), + t_atom('purecov'), + t_atom('gcov'), + t_atom('valgrind'), + t_atom('gprof'), + t_atom('lcnt')]). + %% ===================================================================== %% These are used for the built-in functions of 'ets' %% ===================================================================== diff --git a/lib/hipe/doc/src/notes.xml b/lib/hipe/doc/src/notes.xml index 6b601e3039..3f28cf9959 100644 --- a/lib/hipe/doc/src/notes.xml +++ b/lib/hipe/doc/src/notes.xml @@ -30,6 +30,83 @@ </header> <p>This document describes the changes made to HiPE.</p> +<section><title>Hipe 3.9</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + <list> <item><p>No warnings for underspecs with remote + types</p></item> <item><p> Fix crash in Typer</p></item> + <item><p>Fix Dialyzer's warning for its own + code</p></item> <item><p>Fix Dialyzer's warnings in + HiPE</p></item> <item><p>Add file/line info in a + particular Dialyzer crash</p></item> <item><p>Update + inets test results</p></item> </list></p> + <p> + Own Id: OTP-9758</p> + </item> + <item> + <p> + <list> <item><p>Correct callback spec in application + module</p></item> <item><p>Refine warning about callback + specs with extra ranges</p></item> <item><p>Cleanup + autoimport compiler directives</p></item> <item><p>Fix + Dialyzer's warnings in typer</p></item> <item><p>Fix + Dialyzer's warning for its own code</p></item> + <item><p>Fix bug in Dialyzer's behaviours + analysis</p></item> <item><p>Fix crash in + Dialyzer</p></item> <item><p>Variable substitution was + not generalizing any unknown variables.</p></item> + </list></p> + <p> + Own Id: OTP-9776</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Possible to run HiPE without floating point exceptions + (FPE). Useful on platforms that lack reliable FPE. Slower + float operations compared to HiPE with FPE.</p> + <p> + Own Id: OTP-9724</p> + </item> + <item> + <p> + HiPE compiler: The possibility to compile and load + selected functions from a module has been removed.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9751</p> + </item> + <item> + <p> + <c>filename:find_src/1,2</c> will now work on stripped + BEAM files (reported by Per Hedeland). The HiPE compiler + will also work on stripped BEAM files. The BEAM compiler + will no longer include compilation options given in the + source code itself in <c>M:module_info(compile)</c> + (because those options will be applied anyway if the + module is re-compiled).</p> + <p> + Own Id: OTP-9752</p> + </item> + <item> + <p> Optimize <c>erl_types:t_unify()</c>. </p> + <p> + Own Id: OTP-9768</p> + </item> + </list> + </section> + +</section> + <section><title>Hipe 3.8.1</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/hipe/flow/Makefile b/lib/hipe/flow/Makefile index 02f610587b..bbe8ef8666 100644 --- a/lib/hipe/flow/Makefile +++ b/lib/hipe/flow/Makefile @@ -65,7 +65,7 @@ DOC_FILES= $(MODULES:%=$(DOCS)/%.html) include ../native.mk -ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec +warn_untyped_record +ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec # +warn_untyped_record # ---------------------------------------------------- # Targets diff --git a/lib/hipe/icode/Makefile b/lib/hipe/icode/Makefile index eced90b0ec..bd6436c8b3 100644 --- a/lib/hipe/icode/Makefile +++ b/lib/hipe/icode/Makefile @@ -83,7 +83,7 @@ DOC_FILES= $(DOC_MODULES:%=$(DOCS)/%.html) include ../native.mk -ERL_COMPILE_FLAGS += +warn_unused_import +warn_missing_spec +warn_untyped_record +ERL_COMPILE_FLAGS += +warn_unused_import +warn_missing_spec # +warn_untyped_record # ---------------------------------------------------- # Targets diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl index 992f387bd5..2d2b414a70 100644 --- a/lib/hipe/icode/hipe_beam_to_icode.erl +++ b/lib/hipe/icode/hipe_beam_to_icode.erl @@ -465,10 +465,6 @@ trans_fun([{test,is_nil,{f,Lbl},[Arg]}|Instructions], Env) -> trans_fun([{test,is_binary,{f,Lbl},[Arg]}|Instructions], Env) -> {Code,Env1} = trans_type_test(binary,Lbl,Arg,Env), [Code | trans_fun(Instructions,Env1)]; -%%--- is_constant --- -trans_fun([{test,is_constant,{f,Lbl},[Arg]}|Instructions], Env) -> - {Code,Env1} = trans_type_test(constant,Lbl,Arg,Env), - [Code | trans_fun(Instructions,Env1)]; %%--- is_list --- trans_fun([{test,is_list,{f,Lbl},[Arg]}|Instructions], Env) -> {Code,Env1} = trans_type_test(list,Lbl,Arg,Env), diff --git a/lib/hipe/icode/hipe_icode_inline_bifs.erl b/lib/hipe/icode/hipe_icode_inline_bifs.erl index 27296dcad5..9a2fb7846a 100644 --- a/lib/hipe/icode/hipe_icode_inline_bifs.erl +++ b/lib/hipe/icode/hipe_icode_inline_bifs.erl @@ -29,7 +29,7 @@ %% Currently inlined BIFs: %% and, or, xor, not, <, >, >=, =<, ==, /=, =/=, =:= -%% is_atom, is_boolean, is_binary, is_constant, is_float, is_function, +%% is_atom, is_boolean, is_binary, is_float, is_function, %% is_integer, is_list, is_pid, is_port, is_reference, is_tuple -module(hipe_icode_inline_bifs). @@ -131,7 +131,6 @@ is_type_test(Name) -> is_boolean -> {true, boolean}; is_function -> {true, function}; is_reference -> {true, reference}; - is_constant -> {true, constant}; is_port -> {true, port}; _ -> false end. diff --git a/lib/hipe/icode/hipe_icode_type.erl b/lib/hipe/icode/hipe_icode_type.erl index 3f9488d7c3..cae4325b9e 100644 --- a/lib/hipe/icode/hipe_icode_type.erl +++ b/lib/hipe/icode/hipe_icode_type.erl @@ -899,9 +899,7 @@ test_type0(list, T) -> test_type0(cons, T) -> t_is_cons(T); test_type0(nil, T) -> - t_is_nil(T); -test_type0(constant, T) -> - t_is_constant(T). + t_is_nil(T). true_branch_info(integer) -> @@ -940,8 +938,6 @@ true_branch_info(nil) -> t_nil(); true_branch_info(boolean) -> t_boolean(); -true_branch_info(constant) -> - t_constant(); true_branch_info(T) -> exit({?MODULE,unknown_typetest,T}). diff --git a/lib/hipe/opt/Makefile b/lib/hipe/opt/Makefile index 74fde26c0b..4596201801 100644 --- a/lib/hipe/opt/Makefile +++ b/lib/hipe/opt/Makefile @@ -63,7 +63,7 @@ DOC_FILES= $(MODULES:%=$(DOCS)/%.html) include ../native.mk -ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec +warn_untyped_record +ERL_COMPILE_FLAGS += +warn_exported_vars +warn_missing_spec # +warn_untyped_record # ---------------------------------------------------- # Targets diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile index 690045b978..48086ec79f 100644 --- a/lib/hipe/rtl/Makefile +++ b/lib/hipe/rtl/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2011. All Rights Reserved. +# Copyright Ericsson AB 2001-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -139,27 +139,35 @@ hipe_literals.hrl: $(HIPE_MKLITERALS) ../main/hipe.hrl: ../vsn.mk ../main/hipe.hrl.src (cd ../main && $(MAKE) hipe.hrl) -$(EBIN)/hipe_rtl.beam: hipe_rtl.hrl ../main/hipe.hrl -$(EBIN)/hipe_rtl_arch.beam: hipe_rtl.hrl hipe_literals.hrl -$(EBIN)/hipe_rtl_binary.beam: hipe_rtl.hrl hipe_literals.hrl -$(EBIN)/hipe_rtl_bin_util.beam: hipe_rtl.hrl hipe_literals.hrl -$(EBIN)/hipe_rtl_cfg.beam: hipe_rtl.hrl ../flow/cfg.hrl ../flow/cfg.inc ../main/hipe.hrl -$(EBIN)/hipe_rtl_cleanup_const.beam: hipe_rtl.hrl -$(EBIN)/hipe_rtl_liveness.beam: hipe_rtl.hrl ../flow/cfg.hrl ../flow/liveness.inc -$(EBIN)/hipe_icode2rtl.beam: hipe_literals.hrl ../main/hipe.hrl ../icode/hipe_icode.hrl -$(EBIN)/hipe_tagscheme.beam: hipe_rtl.hrl hipe_literals.hrl -$(EBIN)/hipe_rtl_primops.beam: hipe_rtl.hrl ../icode/hipe_icode_primops.hrl hipe_literals.hrl ../main/hipe.hrl +# 2012-02-24. Please keep these dependencies up to date. They tend to rot. +# grep ^-include *.erl says a lot, but you need to dig further, e.g: +# grep ^-include ../flow/*.{hrl,inc} +$(EBIN)/hipe_icode2rtl.beam: \ + ../main/hipe.hrl ../icode/hipe_icode.hrl hipe_literals.hrl +$(EBIN)/hipe_rtl_arch.beam: hipe_literals.hrl $(EBIN)/hipe_rtl_arith_32.beam: ../main/hipe.hrl hipe_rtl_arith.inc $(EBIN)/hipe_rtl_arith_64.beam: ../main/hipe.hrl hipe_rtl_arith.inc -$(EBIN)/hipe_rtl_bs_ops.beam: hipe_literals.hrl ../main/hipe.hrl -$(EBIN)/hipe_rtl_cerl_bs_ops.beam: ../main/hipe.hrl hipe_literals.hrl hipe_rtl.hrl -$(EBIN)/hipe_rtl_exceptions.beam: hipe_literals.hrl ../main/hipe.hrl -$(EBIN)/hipe_rtl_inline_bs_ops.beam: hipe_rtl.hrl hipe_literals.hrl ../main/hipe.hrl +$(EBIN)/hipe_rtl_binary_construct.beam: \ + ../main/hipe.hrl hipe_rtl.hrl hipe_literals.hrl +$(EBIN)/hipe_rtl_binary_match.beam: hipe_literals.hrl +$(EBIN)/hipe_rtl_cfg.beam: \ + ../main/hipe.hrl hipe_rtl.hrl ../flow/cfg.hrl ../flow/cfg.inc +$(EBIN)/hipe_rtl_cleanup_const.beam: hipe_rtl.hrl +$(EBIN)/hipe_rtl.beam: ../main/hipe.hrl hipe_rtl.hrl +$(EBIN)/hipe_rtl_exceptions.beam: ../main/hipe.hrl hipe_literals.hrl +$(EBIN)/hipe_rtl_lcm.beam: ../main/hipe.hrl hipe_rtl.hrl ../flow/cfg.hrl +$(EBIN)/hipe_rtl_liveness.beam: hipe_rtl.hrl ../flow/cfg.hrl ../flow/liveness.inc $(EBIN)/hipe_rtl_mk_switch.beam: ../main/hipe.hrl -$(EBIN)/hipe_rtl_lcm.beam: ../flow/cfg.hrl hipe_rtl.hrl -$(EBIN)/hipe_rtl_symbolic.beam: hipe_rtl.hrl hipe_literals.hrl ../flow/cfg.hrl ../icode/hipe_icode_primops.hrl -$(EBIN)/hipe_rtl_varmap.beam: ../main/hipe.hrl ../icode/hipe_icode.hrl - -$(EBIN)/hipe_rtl_ssa.beam: ../ssa/hipe_ssa.inc ../main/hipe.hrl ../ssa/hipe_ssa_liveness.inc hipe_rtl.hrl -$(EBIN)/hipe_rtl_ssa_const_prop.beam: hipe_rtl.hrl ../main/hipe.hrl ../flow/cfg.hrl ../ssa/hipe_ssa_const_prop.inc -$(EBIN)/hipe_rtl_ssapre.beam: ../main/hipe.hrl ../flow/cfg.hrl hipe_rtl.hrl +$(EBIN)/hipe_rtl_primops.beam: ../main/hipe.hrl \ + ../icode/hipe_icode_primops.hrl hipe_rtl.hrl hipe_literals.hrl +$(EBIN)/hipe_rtl_ssa_avail_expr.beam: ../main/hipe.hrl hipe_rtl.hrl +$(EBIN)/hipe_rtl_ssa_const_prop.beam: ../main/hipe.hrl hipe_rtl.hrl \ + ../flow/cfg.hrl ../ssa/hipe_ssa_const_prop.inc +$(EBIN)/hipe_rtl_ssa.beam: hipe_rtl.hrl \ + ../main/hipe.hrl ../ssa/hipe_ssa_liveness.inc ../ssa/hipe_ssa.inc +$(EBIN)/hipe_rtl_ssapre.beam: ../main/hipe.hrl hipe_rtl.hrl +$(EBIN)/hipe_rtl_symbolic.beam: hipe_rtl.hrl hipe_literals.hrl \ + ../icode/hipe_icode_primops.hrl +$(EBIN)/hipe_rtl_varmap.beam: ../main/hipe.hrl \ + ../misc/hipe_consttab.hrl ../icode/hipe_icode.hrl +$(EBIN)/hipe_tagscheme.beam: hipe_rtl.hrl hipe_literals.hrl diff --git a/lib/hipe/tools/hipe_tool.erl b/lib/hipe/tools/hipe_tool.erl index 990805ceca..190a68ee56 100644 --- a/lib/hipe/tools/hipe_tool.erl +++ b/lib/hipe/tools/hipe_tool.erl @@ -30,6 +30,18 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -module(hipe_tool). +-compile([{nowarn_deprecated_function,{gs,button,3}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,editor,3}}, + {nowarn_deprecated_function,{gs,label,3}}, + {nowarn_deprecated_function,{gs,listbox,3}}, + {nowarn_deprecated_function,{gs,menu,3}}, + {nowarn_deprecated_function,{gs,menubar,3}}, + {nowarn_deprecated_function,{gs,menubutton,3}}, + {nowarn_deprecated_function,{gs,menuitem,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). -export([start/0]). diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk index 65e04ff7fa..347a0336cd 100644 --- a/lib/hipe/vsn.mk +++ b/lib/hipe/vsn.mk @@ -1 +1 @@ -HIPE_VSN = 3.8.1 +HIPE_VSN = 3.9 diff --git a/lib/ic/doc/src/notes.xml b/lib/ic/doc/src/notes.xml index ff289bd76c..6329bf1fb5 100644 --- a/lib/ic/doc/src/notes.xml +++ b/lib/ic/doc/src/notes.xml @@ -30,7 +30,25 @@ <file>notes.xml</file> </header> - <section> + <section><title>IC 4.2.29</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + </list> + </section> + +</section> + +<section> <title>IC 4.2.28</title> <section> diff --git a/lib/ic/vsn.mk b/lib/ic/vsn.mk index 703c8d29eb..e21fc8fbb2 100644 --- a/lib/ic/vsn.mk +++ b/lib/ic/vsn.mk @@ -1 +1 @@ -IC_VSN = 4.2.28 +IC_VSN = 4.2.29 diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml index 369762d0c6..cfc58b8ddb 100644 --- a/lib/inets/doc/src/notes.xml +++ b/lib/inets/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2002</year><year>2011</year> + <year>2002</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -32,6 +32,58 @@ <file>notes.xml</file> </header> + + <section><title>Inets 5.8.1</title> + <section><title>Improvements and New Features</title> + <p>-</p> + +<!-- + <list> + <item> + <p>[httpc|httpd] Added support for IPv6 with ssl. </p> + <p>Own Id: OTP-5566</p> + </item> + + </list> +--> + + </section> + + <section><title>Fixed Bugs and Malfunctions</title> +<!-- + <p>-</p> +--> + + <list> + <item> + <p>[ftp] Fails to open IPv6 connection due to badly formatted + IPv6 address in EPRT command. The address part of the command + incorrectly contained decimal elements instead of hexadecimal. </p> + <p>Own Id: OTP-9827</p> + <p>Aux Id: Seq 11970 </p> + </item> + + <item> + <p>[httpc] Bad Keep Alive Mode. When selecting a session, + the "state" of the session (specifically if the server has + responded) was not taken into account. </p> + <p>Own Id: OTP-9847</p> + </item> + + <item> + <p>[httpc] The client incorrectly streams 404 responses. + The documentation specifies that only 200 and 206 responses + shall be streamed. </p> + <p>Shane Evens</p> + <p>Own Id: OTP-9860</p> + </item> + + </list> + </section> + + </section> <!-- 5.8.1 --> + + <section><title>Inets 5.8</title> <section><title>Improvements and New Features</title> diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl index b6da92947c..560ee55271 100644 --- a/lib/inets/src/ftp/ftp.erl +++ b/lib/inets/src/ftp/ftp.erl @@ -1987,17 +1987,14 @@ setup_ctrl_connection(Host, Port, Timeout, State) -> setup_data_connection(#state{mode = active, caller = Caller, csock = CSock} = State) -> - IntToString = fun(Element) -> integer_to_list(Element) end, - case (catch inet:sockname(CSock)) of {ok, {{_, _, _, _, _, _, _, _} = IP, _}} -> {ok, LSock} = gen_tcp:listen(0, [{ip, IP}, {active, false}, inet6, binary, {packet, 0}]), {ok, Port} = inet:port(LSock), - Cmd = mk_cmd("EPRT |2|~s:~s:~s:~s:~s:~s:~s:~s|~s|", - lists:map(IntToString, - tuple_to_list(IP) ++ [Port])), + IpAddress = inet_parse:ntoa(IP), + Cmd = mk_cmd("EPRT |2|~s|~p|", [IpAddress, Port]), send_ctrl_message(State, Cmd), activate_ctrl_connection(State), {noreply, State#state{caller = {setup_data_connection, diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index 587e24cc8d..bfe9b14ef6 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -157,12 +157,12 @@ info(Pid) -> %% memory in vain.) %%-------------------------------------------------------------------- %% Request should not be streamed -stream(BodyPart, Request = #request{stream = none}, _) -> +stream(BodyPart, #request{stream = none} = Request, _) -> ?hcrt("stream - none", []), {BodyPart, Request}; %% Stream to caller -stream(BodyPart, Request = #request{stream = Self}, Code) +stream(BodyPart, #request{stream = Self} = Request, Code) when ((Code =:= 200) orelse (Code =:= 206)) andalso ((Self =:= self) orelse (Self =:= {self, once})) -> ?hcrt("stream - self", [{stream, Self}, {code, Code}]), @@ -170,17 +170,10 @@ stream(BodyPart, Request = #request{stream = Self}, Code) {Request#request.id, stream, BodyPart}), {<<>>, Request}; -stream(BodyPart, Request = #request{stream = Self}, 404) - when (Self =:= self) orelse (Self =:= {self, once}) -> - ?hcrt("stream - self with 404", [{stream, Self}]), - httpc_response:send(Request#request.from, - {Request#request.id, stream, BodyPart}), - {<<>>, Request}; - %% Stream to file %% This has been moved to start_stream/3 %% We keep this for backward compatibillity... -stream(BodyPart, Request = #request{stream = Filename}, Code) +stream(BodyPart, #request{stream = Filename} = Request, Code) when ((Code =:= 200) orelse (Code =:= 206)) andalso is_list(Filename) -> ?hcrt("stream - filename", [{stream, Filename}, {code, Code}]), case file:open(Filename, [write, raw, append, delayed_write]) of @@ -192,7 +185,7 @@ stream(BodyPart, Request = #request{stream = Filename}, Code) end; %% Stream to file -stream(BodyPart, Request = #request{stream = Fd}, Code) +stream(BodyPart, #request{stream = Fd} = Request, Code) when ((Code =:= 200) orelse (Code =:= 206)) -> ?hcrt("stream to file", [{stream, Fd}, {code, Code}]), case file:write(Fd, BodyPart) of @@ -295,7 +288,7 @@ handle_call(#request{address = Addr} = Request, _, %% Queue + current queue:len(NewPipeline) + 1, client_close = ClientClose}, - httpc_manager:insert_session(NewSession, ProfileName), + insert_session(NewSession, ProfileName), ?hcrd("session updated", []), {reply, ok, State#state{pipeline = NewPipeline, session = NewSession, @@ -363,7 +356,7 @@ handle_call(#request{address = Addr} = Request, _, %% Queue + current queue:len(NewKeepAlive) + 1, client_close = ClientClose}, - httpc_manager:insert_session(NewSession, ProfileName), + insert_session(NewSession, ProfileName), ?hcrd("session updated", []), {reply, ok, State#state{keep_alive = NewKeepAlive, session = NewSession, @@ -377,7 +370,7 @@ handle_call(#request{address = Addr} = Request, _, NewSession = Session#session{queue_length = 1, client_close = ClientClose}, - httpc_manager:insert_session(NewSession, ProfileName), + insert_session(NewSession, ProfileName), Relaxed = (Request#request.settings)#http_options.relaxed, MFA = {httpc_response, parse, @@ -766,23 +759,52 @@ deliver_answer(Request) -> %% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState} %% Purpose: Convert process state when code is changed %%-------------------------------------------------------------------- -%% code_change(_, #state{request = Request, pipeline = Queue} = State, -%% [{from, '5.0.1'}, {to, '5.0.2'}]) -> -%% Settings = new_http_options(Request#request.settings), -%% NewRequest = Request#request{settings = Settings}, -%% NewQueue = new_queue(Queue, fun new_http_options/1), -%% {ok, State#state{request = NewRequest, pipeline = NewQueue}}; - -%% code_change(_, #state{request = Request, pipeline = Queue} = State, -%% [{from, '5.0.2'}, {to, '5.0.1'}]) -> -%% Settings = old_http_options(Request#request.settings), -%% NewRequest = Request#request{settings = Settings}, -%% NewQueue = new_queue(Queue, fun old_http_options/1), -%% {ok, State#state{request = NewRequest, pipeline = NewQueue}}; + +code_change(_, + #state{session = OldSession, + profile_name = ProfileName} = State, + upgrade_from_pre_5_8_1) -> + case OldSession of + {session, + Id, ClientClose, Scheme, Socket, SocketType, QueueLen, Type} -> + NewSession = #session{id = Id, + client_close = ClientClose, + scheme = Scheme, + socket = Socket, + socket_type = SocketType, + queue_length = QueueLen, + type = Type}, + insert_session(NewSession, ProfileName), + {ok, State#state{session = NewSession}}; + _ -> + {ok, State} + end; + +code_change(_, + #state{session = OldSession, + profile_name = ProfileName} = State, + downgrade_to_pre_5_8_1) -> + case OldSession of + #session{id = Id, + client_close = ClientClose, + scheme = Scheme, + socket = Socket, + socket_type = SocketType, + queue_length = QueueLen, + type = Type} -> + NewSession = {session, + Id, ClientClose, Scheme, Socket, SocketType, + QueueLen, Type}, + insert_session(NewSession, ProfileName), + {ok, State#state{session = NewSession}}; + _ -> + {ok, State} + end; code_change(_, State, _) -> {ok, State}. + %% new_http_options({http_options, TimeOut, AutoRedirect, SslOpts, %% Auth, Relaxed}) -> %% {http_options, "HTTP/1.1", TimeOut, AutoRedirect, SslOpts, @@ -1181,7 +1203,7 @@ handle_pipeline(#state{status = pipeline, case queue:out(State#state.pipeline) of {empty, _} -> - ?hcrd("epmty pipeline queue", []), + ?hcrd("pipeline queue empty", []), %% The server may choose too teminate an idle pipeline %% in this case we want to receive the close message @@ -1191,9 +1213,8 @@ handle_pipeline(#state{status = pipeline, %% If a pipeline that has been idle for some time is not %% closed by the server, the client may want to close it. - NewState = activate_queue_timeout(TimeOut, State), - NewSession = Session#session{queue_length = 0}, - httpc_manager:insert_session(NewSession, ProfileName), + NewState = activate_queue_timeout(TimeOut, State), + update_session(ProfileName, Session, #session.queue_length, 0), %% Note mfa will be initilized when a new request %% arrives. {noreply, @@ -1203,6 +1224,7 @@ handle_pipeline(#state{status = pipeline, headers = undefined, body = undefined}}; {{value, NextRequest}, Pipeline} -> + ?hcrd("pipeline queue non-empty", []), case lists:member(NextRequest#request.id, State#state.canceled) of true -> @@ -1218,7 +1240,7 @@ handle_pipeline(#state{status = pipeline, Session#session{queue_length = %% Queue + current queue:len(Pipeline) + 1}, - httpc_manager:insert_session(NewSession, ProfileName), + insert_session(NewSession, ProfileName), Relaxed = (NextRequest#request.settings)#http_options.relaxed, MFA = {httpc_response, @@ -1257,7 +1279,7 @@ handle_keep_alive_queue( case queue:out(State#state.keep_alive) of {empty, _} -> - ?hcrd("empty keep_alive queue", []), + ?hcrd("keep_alive queue empty", []), %% The server may choose too terminate an idle keep_alive session %% in this case we want to receive the close message %% at once and not when trying to send the next @@ -1266,8 +1288,7 @@ handle_keep_alive_queue( %% If a keep_alive session has been idle for some time is not %% closed by the server, the client may want to close it. NewState = activate_queue_timeout(TimeOut, State), - NewSession = Session#session{queue_length = 0}, - httpc_manager:insert_session(NewSession, ProfileName), + update_session(ProfileName, Session, #session.queue_length, 0), %% Note mfa will be initilized when a new request %% arrives. {noreply, @@ -1279,6 +1300,7 @@ handle_keep_alive_queue( } }; {{value, NextRequest}, KeepAlive} -> + ?hcrd("keep_alive queue non-empty", []), case lists:member(NextRequest#request.id, State#state.canceled) of true -> @@ -1388,10 +1410,10 @@ try_to_enable_pipeline_or_keep_alive( case (is_pipeline_enabled_client(Session) andalso httpc_request:is_idempotent(Method)) of true -> - httpc_manager:insert_session(Session, ProfileName), + insert_session(Session, ProfileName), State#state{status = pipeline}; false -> - httpc_manager:insert_session(Session, ProfileName), + insert_session(Session, ProfileName), %% Make sure type is keep_alive in session %% as it in this case might be pipeline NewSession = Session#session{type = keep_alive}, @@ -1403,7 +1425,9 @@ try_to_enable_pipeline_or_keep_alive( end. answer_request(#request{id = RequestId, from = From} = Request, Msg, - #state{timers = Timers, profile_name = ProfileName} = State) -> + #state{session = Session, + timers = Timers, + profile_name = ProfileName} = State) -> ?hcrt("answer request", [{request, Request}, {msg, Msg}]), httpc_response:send(From, Msg), RequestTimers = Timers#timers.request_timers, @@ -1412,12 +1436,20 @@ answer_request(#request{id = RequestId, from = From} = Request, Msg, Timer = {RequestId, TimerRef}, cancel_timer(TimerRef, {timeout, Request#request.id}), httpc_manager:request_done(RequestId, ProfileName), - + NewSession = maybe_make_session_available(ProfileName, Session), + Timers2 = Timers#timers{request_timers = lists:delete(Timer, + RequestTimers)}, State#state{request = Request#request{from = answer_sent}, - timers = - Timers#timers{request_timers = - lists:delete(Timer, RequestTimers)}}. - + session = NewSession, + timers = Timers2}. + +maybe_make_session_available(ProfileName, + #session{available = false} = Session) -> + update_session(ProfileName, Session, #session.available, true), + Session#session{available = true}; +maybe_make_session_available(_ProfileName, Session) -> + Session. + cancel_timers(#timers{request_timers = ReqTmrs, queue_timer = QTmr}) -> cancel_timer(QTmr, timeout_queue), CancelTimer = fun({_, Timer}) -> cancel_timer(Timer, timeout) end, @@ -1656,6 +1688,28 @@ send_raw(SocketType, Socket, ProcessBody, Acc) -> end. +%% --------------------------------------------------------------------- +%% Session wrappers +%% --------------------------------------------------------------------- + +insert_session(Session, ProfileName) -> + httpc_manager:insert_session(Session, ProfileName). + + +update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) -> + try + begin + httpc_manager:update_session(ProfileName, SessionId, Pos, Value) + end + catch + error:undef -> % This could happen during code upgrade + Session2 = erlang:setelement(Pos, Session, Value), + insert_session(Session2, ProfileName) + end. + + +%% --------------------------------------------------------------------- + call(Msg, Pid) -> Timeout = infinity, call(Msg, Pid, Timeout). diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl index 1fbbaa8d13..8af752546c 100644 --- a/lib/inets/src/http_client/httpc_internal.hrl +++ b/lib/inets/src/http_client/httpc_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. +%% Copyright Ericsson AB 2005-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -115,17 +115,37 @@ } ). + -record(session, { - id, % {{Host, Port}, HandlerPid} - client_close, % true | false - scheme, % http (HTTP/TCP) | https (HTTP/SSL/TCP) - socket, % Open socket, used by connection - socket_type, % socket-type, used by connection - queue_length = 1, % Current length of pipeline or keep-alive queue - type % pipeline | keep_alive (wait for response before sending new request) + %% {{Host, Port}, HandlerPid} + id, + + %% true | false + client_close, + + %% http (HTTP/TCP) | https (HTTP/SSL/TCP) + scheme, + + %% Open socket, used by connection + socket, + + %% socket-type, used by connection + socket_type, + + %% Current length of pipeline or keep-alive queue + queue_length = 1, + + %% pipeline | keep_alive (wait for response before sending new request) + type, + + %% true | false + %% This will be true, when a response has been received for + %% the first request. See type above. + available = false }). + -record(http_cookie, { domain, diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl index a97cbb83f1..453081da21 100644 --- a/lib/inets/src/http_client/httpc_manager.erl +++ b/lib/inets/src/http_client/httpc_manager.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2011. All Rights Reserved. +%% Copyright Ericsson AB 2002-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -34,6 +34,7 @@ retry_request/2, redirect_request/2, insert_session/2, + update_session/4, delete_session/2, set_options/2, store_cookies/3, @@ -193,6 +194,27 @@ insert_session(Session, ProfileName) -> %%-------------------------------------------------------------------- +%% Function: update_session(ProfileName, SessionId, Pos, Value) -> _ +%% Session - #session{} +%% ProfileName - atom() +%% +%% Description: Update, only one field (Pos) of the session record +%% identified by the SessionId, the session information +%% of the httpc manager table <ProfileName>_session_db. +%% Intended to be called by the httpc request handler process. +%%-------------------------------------------------------------------- + +update_session(ProfileName, SessionId, Pos, Value) -> + SessionDbName = session_db_name(ProfileName), + ?hcrt("update session", + [{id, SessionId}, + {pos, Pos}, + {value, Value}, + {profile, ProfileName}]), + ets:update_element(SessionDbName, SessionId, {Pos, Value}). + + +%%-------------------------------------------------------------------- %% Function: delete_session(SessionId, ProfileName) -> _ %% SessionId - {{Host, Port}, HandlerPid} %% ProfileName - atom() @@ -559,9 +581,70 @@ terminate(_, State) -> %% Func: code_change(_OldVsn, State, Extra) -> {ok, NewState} %% Purpose: Convert process state when code is changed %%-------------------------------------------------------------------- -code_change(_OldVsn, State, _Extra) -> +code_change(_, + #state{session_db = SessionDB} = State, + upgrade_from_pre_5_8_1) -> + Upgrade = + fun({session, + Id, ClientClose, Scheme, Socket, SocketType, QueueLen, Type}) -> + {ok, #session{id = Id, + client_close = ClientClose, + scheme = Scheme, + socket = Socket, + socket_type = SocketType, + queue_length = QueueLen, + type = Type}}; + (_) -> % Already upgraded (by handler) + ignore + end, + (catch update_session_table(SessionDB, Upgrade)), + {ok, State}; + +code_change(_, + #state{session_db = SessionDB} = State, + downgrade_to_pre_5_8_1) -> + Downgrade = + fun(#session{id = Id, + client_close = ClientClose, + scheme = Scheme, + socket = Socket, + socket_type = SocketType, + queue_length = QueueLen, + type = Type}) -> + {ok, {session, + Id, ClientClose, Scheme, Socket, SocketType, + QueueLen, Type}}; + (_) -> % Already downgraded (by handler) + ignore + end, + (catch update_session_table(SessionDB, Downgrade)), + {ok, State}; + +code_change(_, State, _) -> {ok, State}. +%% This function is to catch everything that calls through the cracks... +update_session_table(SessionDB, Transform) -> + ets:safe_fixtable(SessionDB, true), + update_session_table(SessionDB, ets:first(SessionDB), Transform), + ets:safe_fixtable(SessionDB, false). + +update_session_table(_SessionDB, '$end_of_table', _Transform) -> + ok; +update_session_table(SessionDB, Key, Transform) -> + case ets:lookup(SessionDB, Key) of + [OldSession] -> + case Transform(OldSession) of + {ok, NewSession} -> + ets:insert(SessionDB, NewSession); + ignore -> + ok + end; + _ -> + ok + end, + update_session_table(SessionDB, ets:next(SessionDB, Key), Transform). + %%-------------------------------------------------------------------- %% Internal functions @@ -690,6 +773,7 @@ select_session(Method, HostPort, Scheme, SessionType, scheme = Scheme, queue_length = '$2', type = SessionType, + available = true, _ = '_'}, %% {'_', {HostPort, '$1'}, false, Scheme, '_', '$2', SessionTyp}, Candidates = ets:match(SessionDb, Pattern), @@ -727,7 +811,7 @@ pipeline_or_keep_alive(Request, HandlerPid, State) -> ets:insert(State#state.handler_db, {Request#request.id, HandlerPid, Request#request.from}); - _ -> %timeout pipelining failed + _ -> % timeout pipelining failed start_handler(Request, State) end. diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src index 779dd8e439..e80cb2a23b 100644 --- a/lib/inets/src/inets_app/inets.appup.src +++ b/lib/inets/src/inets_app/inets.appup.src @@ -1,7 +1,7 @@ %% This is an -*- erlang -*- file. %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -18,6 +18,15 @@ {"%VSN%", [ + {"5.8", + [ + {load_module, ftp, soft_purge, soft_purge, []}, + {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1}, + soft_purge, soft_purge, []}, + {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1}, + soft_purge, soft_purge, [httpc_handler]} + ] + }, {"5.7.2", [ {restart_application, inets} @@ -40,6 +49,15 @@ } ], [ + {"5.8", + [ + {load_module, ftp, soft_purge, soft_purge, []}, + {update, httpc_handler, {advanced, upgrade_from_pre_5_8_1}, + soft_purge, soft_purge, []}, + {update, httpc_manager, {advanced, upgrade_from_pre_5_8_1}, + soft_purge, soft_purge, [httpc_handler]} + ] + }, {"5.7.2", [ {restart_application, inets} diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 6e69c9a469..881266b70a 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -90,6 +90,7 @@ all() -> parse_url, options, headers_as_is, + selecting_session, {group, proxy}, {group, ssl}, {group, stream}, @@ -252,7 +253,7 @@ init_per_testcase(Case, Timeout, Config) -> %% inets:enable_trace(max, io, httpd), %% inets:enable_trace(max, io, httpc), - inets:enable_trace(max, io, all), + %% inets:enable_trace(max, io, all), NewConfig = case atom_to_list(Case) of @@ -1765,6 +1766,7 @@ http_stream(Config) when is_list(Config) -> %%------------------------------------------------------------------------- + http_stream_once(doc) -> ["Test the option stream for asynchrony requests"]; http_stream_once(suite) -> @@ -1772,12 +1774,12 @@ http_stream_once(suite) -> http_stream_once(Config) when is_list(Config) -> p("http_stream_once -> entry with" "~n Config: ~p", [Config]), - + p("http_stream_once -> set ipfamily to inet", []), ok = httpc:set_options([{ipfamily, inet}]), p("http_stream_once -> start dummy server", []), {DummyServerPid, Port} = dummy_server(ipv4), - + PortStr = integer_to_list(Port), p("http_stream_once -> once", []), once(?URL_START ++ PortStr ++ "/once.html"), @@ -1785,14 +1787,14 @@ http_stream_once(Config) when is_list(Config) -> once(?URL_START ++ PortStr ++ "/once_chunked.html"), p("http_stream_once -> dummy", []), once(?URL_START ++ PortStr ++ "/dummy.html"), - + p("http_stream_once -> stop dummy server", []), DummyServerPid ! stop, p("http_stream_once -> set ipfamily to inet6fb4", []), ok = httpc:set_options([{ipfamily, inet6fb4}]), p("http_stream_once -> done", []), ok. - + once(URL) -> p("once -> issue sync request for ~p", [URL]), {ok, {{_,200,_}, [_ | _], Body}} = @@ -2001,6 +2003,7 @@ ipv6(SocketType, Scheme, HTTPOptions, Extra, Config) -> %%------------------------------------------------------------------------- + headers_as_is(doc) -> ["Test the option headers_as_is"]; headers_as_is(suite) -> @@ -2018,6 +2021,321 @@ headers_as_is(Config) when is_list(Config) -> %%------------------------------------------------------------------------- + +selecting_session(doc) -> + ["Test selection of sessions - OTP-9847"]; +selecting_session(suite) -> + []; +selecting_session(Config) when is_list(Config) -> + tsp("selecting_session -> entry with" + "~n Config: ~p", [Config]), + + tsp("selecting_session -> set ipfamily to inet"), + ok = httpc:set_options([{ipfamily, inet}]), + + tsp("selecting_session -> start server"), + {ServerPid, Port} = otp_9847_server(), + + PortStr = integer_to_list(Port), + URL = ?URL_START ++ PortStr ++ "/index.html", + + tsp("selecting_session -> issue the first batch (three) requests"), + lists:foreach(fun(P) -> + tsp("selecting_session:fun1 -> " + "send stop request to ~p", [P]), + P ! stop + end, + reqs(URL, ServerPid, 3, 3, false)), + tsp("selecting_session -> sleep some (1) to make sure nothing lingers"), + ?SLEEP(5000), + tsp("selecting_session -> " + "instruct the server to reply to the first request"), + ServerPid ! {answer, true}, + receive + {answer, true} -> + tsp("selecting_session -> " + "received ack from server to reply to the first request"), + ok + end, + tsp("selecting_session -> issue the second batch (four) requests"), + lists:foreach(fun(P) -> + tsp("selecting_session:fun2 -> " + "send stop request to ~p", [P]), + P ! stop + end, + reqs(URL, ServerPid, 4, 1, true)), + tsp("selecting_session -> sleep some (2) to make sure nothing lingers"), + ?SLEEP(5000), + + tsp("selecting_session -> stop server"), + ServerPid ! stop, + tsp("selecting_session -> set ipfamily (back) to inet6fb4"), + ok = httpc:set_options([{ipfamily, inet6fb4}]), + tsp("selecting_session -> done"), + ok. + +reqs(URL, ServerPid, NumReqs, NumHandlers, InitialSync) -> + tsp("reqs -> entry with" + "~n URL: ~p" + "~n ServerPid: ~w" + "~n NumReqs: ~w" + "~n NumHandlers: ~w" + "~n InitialSync: ~w", + [URL, ServerPid, NumReqs, NumHandlers, InitialSync]), + Handlers = reqs2(URL, NumReqs, [], InitialSync), + tsp("reqs -> " + "~n Handlers: ~w", [Handlers]), + case length(Handlers) of + NumHandlers -> + tsp("reqs -> " + "~n NumHandlers: ~w", [NumHandlers]), + ServerPid ! num_handlers, + receive + {num_handlers, NumHandlers} -> + tsp("reqs -> received num_handlers with" + "~n NumHandlers: ~w", [NumHandlers]), + Handlers; + {num_handlers, WrongNumHandlers} -> + tsp("reqs -> received num_handlers with" + "~n WrongNumHandlers: ~w", [WrongNumHandlers]), + exit({wrong_num_handlers1, WrongNumHandlers, NumHandlers}) + end; + WrongNumHandlers -> + tsp("reqs -> " + "~n WrongNumHandlers: ~w", [WrongNumHandlers]), + exit({wrong_num_handlers2, WrongNumHandlers, NumHandlers}) + end. + + +reqs2(_URL, 0, Acc, _Sync) -> + lists:reverse(Acc); +reqs2(URL, Num, Acc, Sync) -> + tsp("reqs2 -> entry with" + "~n Num: ~w" + "~n Sync: ~w", [Num, Sync]), + case httpc:request(get, {URL, []}, [], [{sync, Sync}]) of + {ok, _Reply} -> + tsp("reqs2 -> successful request: ~p", [_Reply]), + receive + {handler, Handler, _Manager} -> + %% This is when a new handler is created + tsp("reqs2 -> received handler: ~p", [Handler]), + case lists:member(Handler, Acc) of + true -> + tsp("reqs2 -> duplicate handler"), + exit({duplicate_handler, Handler, Num, Acc}); + false -> + tsp("reqs2 -> wait for data ack"), + receive + {data_received, Handler} -> + tsp("reqs2 -> " + "received data ack from ~p", [Handler]), + case Sync of + true -> + reqs2(URL, Num-1, [Handler|Acc], + false); + false -> + reqs2(URL, Num-1, [Handler|Acc], + Sync) + end + end + end; + + {data_received, Handler} -> + tsp("reqs2 -> " + "received data ack from ~p", [Handler]), + reqs2(URL, Num-1, Acc, false) + + end; + + {error, Reason} -> + tsp("reqs2 -> request ~w failed: ~p", [Num, Reason]), + exit({request_failed, Reason, Num, Acc}) + end. + +otp_9847_server() -> + TC = self(), + Pid = spawn_link(fun() -> otp_9847_server_init(TC) end), + receive + {port, Port} -> + {Pid, Port} + end. + +otp_9847_server_init(TC) -> + tsp("otp_9847_server_init -> entry with" + "~n TC: ~p", [TC]), + {ok, ListenSocket} = + gen_tcp:listen(0, [binary, inet, {packet, 0}, + {reuseaddr,true}, + {active, false}]), + tsp("otp_9847_server_init -> listen socket created: " + "~n ListenSocket: ~p", [ListenSocket]), + {ok, Port} = inet:port(ListenSocket), + tsp("otp_9847_server_init -> Port: ~p", [Port]), + TC ! {port, Port}, + otp_9847_server_main(TC, ListenSocket, false, []). + +otp_9847_server_main(TC, ListenSocket, Answer, Handlers) -> + tsp("otp_9847_server_main -> entry with" + "~n TC: ~p" + "~n ListenSocket: ~p" + "~n Answer: ~p" + "~n Handlers: ~p", [TC, ListenSocket, Answer, Handlers]), + case gen_tcp:accept(ListenSocket, 1000) of + {ok, Sock} -> + tsp("otp_9847_server_main -> accepted" + "~n Sock: ~p", [Sock]), + {Handler, Mon, Port} = otp_9847_handler(TC, Sock, Answer), + tsp("otp_9847_server_main -> handler ~p created for ~w", + [Handler, Port]), + gen_tcp:controlling_process(Sock, Handler), + tsp("otp_9847_server_main -> control transfer"), + Handler ! owner, + tsp("otp_9847_server_main -> " + "handler ~p informed of owner transfer", [Handler]), + TC ! {handler, Handler, self()}, + tsp("otp_9847_server_main -> " + "TC ~p informed of handler ~p", [TC, Handler]), + otp_9847_server_main(TC, ListenSocket, Answer, + [{Handler, Mon, Sock, Port}|Handlers]); + + {error, timeout} -> + tsp("otp_9847_server_main -> timeout"), + receive + {answer, true} -> + tsp("otp_9847_server_main -> received answer request"), + TC ! {answer, true}, + otp_9847_server_main(TC, ListenSocket, true, Handlers); + + {'DOWN', _Mon, process, Pid, _Reason} -> + %% Could be one of the handlers + tsp("otp_9847_server_main -> received DOWN for ~p", [Pid]), + otp_9847_server_main(TC, ListenSocket, Answer, + lists:keydelete(Pid, 1, Handlers)); + + num_handlers -> + tsp("otp_9847_server_main -> " + "received request for number of handlers (~w)", + [length(Handlers)]), + TC ! {num_handlers, length(Handlers)}, + otp_9847_server_main(TC, ListenSocket, Answer, Handlers); + + stop -> + tsp("otp_9847_server_main -> received stop request"), + %% Stop all handlers (just in case) + Pids = [Handler || {Handler, _, _} <- Handlers], + lists:foreach(fun(Pid) -> Pid ! stop end, Pids), + exit(normal); + + Any -> + tsp("otp_9847_server_main -> received" + "~n Any: ~p", [Any]), + exit({crap, Any}) + + after 0 -> + tsp("otp_9847_server_main -> nothing in queue"), + otp_9847_server_main(TC, ListenSocket, Answer, Handlers) + end; + + Error -> + exit(Error) + end. + + +otp_9847_handler(TC, Sock, Answer) -> + tsp("otp_9847_handler -> entry with" + "~n TC: ~p" + "~n Sock: ~p" + "~n Answer: ~p", [TC, Sock, Answer]), + Self = self(), + {Pid, Mon} = + spawn_opt(fun() -> + otp_9847_handler_init(TC, Self, Sock, Answer) + end, + [monitor]), + receive + {port, Port} -> + tsp("otp_9847_handler -> received port message (from ~p)" + "~n Port: ~p", [Pid, Port]), + {Pid, Mon, Port} + end. + + +otp_9847_handler_init(TC, Server, Sock, Answer) -> + tsp("otp_9847_handler_init -> entry with" + "~n TC: ~p" + "~n Server: ~p" + "~n Sock: ~p" + "~n Answer: ~p", [TC, Server, Sock, Answer]), + {ok, Port} = inet:port(Sock), + Server ! {port, Port}, + receive + owner -> + tsp("otp_9847_handler_init -> " + "received owner message - activate socket"), + inet:setopts(Sock, [{active, true}]), + otp_9847_handler_main(TC, Server, Sock, Answer, [?HTTP_MAX_HEADER_SIZE]) + end. + +otp_9847_handler_main(TC, Server, Sock, Answer, ParseArgs) -> + tsp("otp_9847_handler_main -> entry with" + "~n TC: ~p" + "~n Server: ~p" + "~n Sock: ~p" + "~n Answer: ~p" + "~n ParseArgs: ~p", [TC, Server, Sock, Answer, ParseArgs]), + receive + stop -> + tsp("otp_9847_handler_main -> received stop request"), + exit(normal); + + {tcp, Sock, _Data} when Answer =:= false -> + tsp("otp_9847_handler_main -> received tcp data - no answer"), + TC ! {data_received, self()}, + inet:setopts(Sock, [{active, true}]), + %% Ignore all data + otp_9847_handler_main(TC, Server, Sock, Answer, ParseArgs); + + {tcp, Sock, Data} when Answer =:= true -> + tsp("otp_9847_handler_main -> received tcp data - answer"), + TC ! {data_received, self()}, + inet:setopts(Sock, [{active, true}]), + NewParseArgs = otp_9847_handler_request(Sock, [Data|ParseArgs]), + otp_9847_handler_main(TC, Server, Sock, Answer, NewParseArgs); + + {tcp_closed, Sock} -> + tsp("otp_9847_handler_main -> received tcp socket closed"), + exit(normal); + + {tcp_error, Sock, Reason} -> + tsp("otp_9847_handler_main -> socket error: ~p", [Reason]), + (catch gen_tcp:close(Sock)), + exit(normal) + + %% after 30000 -> + %% gen_tcp:close(Sock), + %% exit(normal) + end. + +otp_9847_handler_request(Sock, Args) -> + Msg = + case httpd_request:parse(Args) of + {ok, {_, "/index.html" = _RelUrl, _, _, _}} -> + B = + "<HTML><BODY>" ++ + "...some body part..." ++ + "</BODY></HTML>", + Len = integer_to_list(length(B)), + "HTTP/1.1 200 ok\r\n" ++ + "Content-Length:" ++ Len ++ "\r\n\r\n" ++ B + end, + gen_tcp:send(Sock, Msg), + [?HTTP_MAX_HEADER_SIZE]. + + + +%%------------------------------------------------------------------------- + options(doc) -> ["Test the option parameters."]; options(suite) -> @@ -2042,6 +2360,7 @@ options(Config) when is_list(Config) -> %%------------------------------------------------------------------------- + http_invalid_http(doc) -> ["Test parse error"]; http_invalid_http(suite) -> @@ -2855,6 +3174,7 @@ otp_8739_dummy_server_main(_Parent, ListenSocket) -> exit(Error) end. + %%------------------------------------------------------------------------- initial_server_connect(doc) -> diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl index 5b571a9649..a4bb8f7159 100644 --- a/lib/inets/test/httpd_SUITE.erl +++ b/lib/inets/test/httpd_SUITE.erl @@ -2227,6 +2227,7 @@ ticket_5865(doc) -> ticket_5865(suite) -> []; ticket_5865(Config) -> + ?SKIP(as_of_r15_behaviour_of_calendar_has_changed), Host = ?config(host,Config), ServerRoot = ?config(server_root, Config), DocRoot = filename:join([ServerRoot, "htdocs"]), diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl index 1c7bb512cc..2f5867559a 100644 --- a/lib/inets/test/httpd_test_lib.erl +++ b/lib/inets/test/httpd_test_lib.erl @@ -80,14 +80,18 @@ %% API %%------------------------------------------------------------------ verify_request(SocketType, Host, Port, Node, RequestStr, Options) -> - verify_request(SocketType, Host, Port, Node, RequestStr, Options, 30000). + verify_request(SocketType, Host, Port, Node, RequestStr, + Options, 30000). verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options) when is_list(TranspOpts) -> - verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, 30000); + verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, + Options, 30000); verify_request(SocketType, Host, Port, Node, RequestStr, Options, TimeOut) when (is_integer(TimeOut) orelse (TimeOut =:= infinity)) -> - verify_request(SocketType, Host, Port, [], Node, RequestStr, Options, TimeOut). -verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, Options, TimeOut) -> + verify_request(SocketType, Host, Port, [], Node, RequestStr, + Options, TimeOut). +verify_request(SocketType, Host, Port, TranspOpts, Node, RequestStr, + Options, TimeOut) -> tsp("verify_request -> entry with" "~n SocketType: ~p" "~n Host: ~p" @@ -259,10 +263,10 @@ validate(RequestStr, #state{status_line = {Version, StatusCode, _}, headers = Headers, body = Body}, Options, N, P) -> - %% tsp("validate -> entry with" - %% "~n StatusCode: ~p" - %% "~n Headers: ~p" - %% "~n Body: ~p", [StatusCode, Headers, Body]), + tsp("validate -> entry with" + "~n StatusCode: ~p" + "~n Headers: ~p" + "~n Body: ~p", [StatusCode, Headers, Body]), check_version(Version, Options), case lists:keysearch(statuscode, 1, Options) of @@ -320,9 +324,9 @@ do_validate(Header, [{header, HeaderField}|Rest], N, P) -> {value, {LowerHeaderField, _Value}} -> ok; false -> - test_server:fail({missing_header_field, LowerHeaderField, Header}); + tsf({missing_header_field, LowerHeaderField, Header}); _ -> - test_server:fail({missing_header_field, LowerHeaderField, Header}) + tsf({missing_header_field, LowerHeaderField, Header}) end, do_validate(Header, Rest, N, P); do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) -> @@ -331,18 +335,15 @@ do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) -> {value, {LowerHeaderField, Value}} -> ok; false -> - test_server:fail({wrong_header_field_value, LowerHeaderField, - Header}); + tsf({wrong_header_field_value, LowerHeaderField, Header}); _ -> - test_server:fail({wrong_header_field_value, LowerHeaderField, - Header}) + tsf({wrong_header_field_value, LowerHeaderField, Header}) end, do_validate(Header, Rest, N, P); do_validate(Header,[{no_last_modified, HeaderField}|Rest],N,P) -> case lists:keysearch(HeaderField,1,Header) of {value,_} -> - test_server:fail({wrong_header_field_value, HeaderField, - Header}); + tsf({wrong_header_field_value, HeaderField, Header}); _ -> ok end, diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk index 1df4558e45..77eb43a7ed 100644 --- a/lib/inets/vsn.mk +++ b/lib/inets/vsn.mk @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 2001-2011. All Rights Reserved. +# Copyright Ericsson AB 2001-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -18,7 +18,7 @@ # %CopyrightEnd% APPLICATION = inets -INETS_VSN = 5.8 +INETS_VSN = 5.8.1 PRE_VSN = APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)" diff --git a/lib/inviso/doc/src/notes.xml b/lib/inviso/doc/src/notes.xml index 7c2c3c3bde..661284e786 100644 --- a/lib/inviso/doc/src/notes.xml +++ b/lib/inviso/doc/src/notes.xml @@ -31,7 +31,28 @@ <p>This document describes the changes made to the Inviso application.</p> - <section><title>Inviso 0.6.2</title> + <section><title>Inviso 0.6.3</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>The <c>inviso</c> application has been deprecated and + will be removed in the R16 release.</p> + <p> + Own Id: OTP-9798</p> + </item> + <item> + <p> + Eliminate use of deprecated regexp module</p> + <p> + Own Id: OTP-9810</p> + </item> + </list> + </section> + +</section> + +<section><title>Inviso 0.6.2</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/inviso/test/inviso_tool_SUITE.erl b/lib/inviso/test/inviso_tool_SUITE.erl index 6b16e506eb..f8a9cea47f 100644 --- a/lib/inviso/test/inviso_tool_SUITE.erl +++ b/lib/inviso/test/inviso_tool_SUITE.erl @@ -52,7 +52,12 @@ end_per_group(_GroupName, Config) -> %% -----------------------------------------------------------------------------
init_per_suite(Config) ->
- Config.
+ case test_server:is_native(lists) of + true -> + {skip,"Native libs -- tracing doesn't work"}; + false -> + Config + end. %% -----------------------------------------------------------------------------
end_per_suite(_Config) ->
diff --git a/lib/inviso/vsn.mk b/lib/inviso/vsn.mk index 79093597fe..c6b0398bde 100644 --- a/lib/inviso/vsn.mk +++ b/lib/inviso/vsn.mk @@ -1 +1 @@ -INVISO_VSN = 0.6.2 +INVISO_VSN = 0.6.3 diff --git a/lib/jinterface/doc/src/notes.xml b/lib/jinterface/doc/src/notes.xml index 11fcc5f387..bf94077114 100644 --- a/lib/jinterface/doc/src/notes.xml +++ b/lib/jinterface/doc/src/notes.xml @@ -30,6 +30,27 @@ </header> <p>This document describes the changes made to the Jinterface application.</p> +<section><title>Jinterface 1.5.5</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + JInterface: improve OtpOutputStream buffer allocation</p> + <p> + Previously, the buffer was increased linearly by 2048 + bytes. I now propose to use an exponential increase + function (similar to Javas ArrayList, e.g. always at + least +50%). This significantly increases performance of + e.g. doRPC for large parameters. (Thanks to Nico Kruber)</p> + <p> + Own Id: OTP-9806</p> + </item> + </list> + </section> + +</section> + <section><title>Jinterface 1.5.4</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangAtom.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangAtom.java index 4d53447164..60eef7a126 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangAtom.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangAtom.java @@ -53,7 +53,7 @@ public class OtpErlangAtom extends OtpErlangObject implements Serializable, if (atom.length() > maxAtomLength) { throw new java.lang.IllegalArgumentException("Atom may not exceed " - + maxAtomLength + " characters"); + + maxAtomLength + " characters: " + atom); } this.atom = atom; } diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java index 8cd900aada..be8b7c5c12 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java @@ -154,13 +154,16 @@ public class OtpErlangString extends OtpErlangObject implements Serializable, * Unicode code points */ - public static int[] stringToCodePoints(final String s) { - final int m = s.codePointCount(0, s.length()); - final int [] codePoints = new int[m]; - for (int i = 0, j = 0; j < m; i = s.offsetByCodePoints(i, 1), j++) { - codePoints[j] = s.codePointAt(i); - } - return codePoints; + public static int[] stringToCodePoints(final String s) { + final int m = s.codePointCount(0, s.length()); + final int[] codePoints = new int[m]; + int j = 0; + for (int offset = 0; offset < s.length();) { + final int codepoint = s.codePointAt(offset); + codePoints[j++] = codepoint; + offset += Character.charCount(codepoint); + } + return codePoints; } /** diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java index 71a419497a..b0b64e6953 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpMbox.java @@ -31,7 +31,7 @@ package com.ericsson.otp.erlang; * the recipient of the message. When sending messages to other mailboxes, the * recipient can only respond if the sender includes the pid as part of the * message contents. The sender can determine his own pid by calling - * {@link #self self()}. + * {@link #self() self()}. * </p> * * <p> @@ -141,7 +141,7 @@ public class OtpMbox { * Get the registered name of this mailbox. * * @return the registered name of this mailbox, or null if the mailbox had - * no registerd name. + * no registered name. */ public String getName() { return name; diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java index d499fae3fb..be7c8e5b1a 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpNode.java @@ -182,7 +182,7 @@ public class OtpNode extends OtpLocalNode { * Create an unnamed {@link OtpMbox mailbox} that can be used to send and * receive messages with other, similar mailboxes and with Erlang processes. * Messages can be sent to this mailbox by using its associated - * {@link OtpMbox#self pid}. + * {@link OtpMbox#self() pid}. * * @return a mailbox. */ @@ -248,7 +248,7 @@ public class OtpNode extends OtpLocalNode { * Create an named mailbox that can be used to send and receive messages * with other, similar mailboxes and with Erlang processes. Messages can be * sent to this mailbox by using its registered name or the associated - * {@link OtpMbox#self pid}. + * {@link OtpMbox#self() pid}. * * @param name * a name to register for this mailbox. The name must be unique diff --git a/lib/jinterface/test/nc_SUITE.erl b/lib/jinterface/test/nc_SUITE.erl index da54f5bf51..9c88400c2a 100644 --- a/lib/jinterface/test/nc_SUITE.erl +++ b/lib/jinterface/test/nc_SUITE.erl @@ -296,7 +296,8 @@ lists_roundtrip_2(Config) when is_list(Config) -> {[z,23|24],tail3}, {[z|25],tail3}, {"abc123",sub3atom}, - {"abc",sub3atom} + {"abc",sub3atom}, + {"abcdefg",codepointBug} ], Trans = fun ([_|T], tail) -> @@ -308,7 +309,9 @@ lists_roundtrip_2(Config) when is_list(Config) -> (L, tail3) when is_list(L) -> null; ([_,_,_|L], sub3atom) -> - list_to_atom(L) + list_to_atom(L); + (L, codepointBug) -> + L end, OutTrans = fun ({L,Twist}) -> diff --git a/lib/jinterface/test/nc_SUITE_data/echo_server.java b/lib/jinterface/test/nc_SUITE_data/echo_server.java index 0550e4beb1..5ecb5b72a7 100644 --- a/lib/jinterface/test/nc_SUITE_data/echo_server.java +++ b/lib/jinterface/test/nc_SUITE_data/echo_server.java @@ -202,6 +202,12 @@ public class echo_server { final OtpErlangAtom o = new OtpErlangAtom(s.stringValue() .substring(3)); return o; + } else if (atomValue.equals("codepointBug") + && i instanceof OtpErlangString) { + final OtpErlangString s = (OtpErlangString) i; + final String ss = s.stringValue().substring(3, 6); + final int[] cps = OtpErlangString.stringToCodePoints(ss); + return s; } else if (atomValue.equals("utf8")) { if (i instanceof OtpErlangString) { final OtpErlangString s = (OtpErlangString) i; diff --git a/lib/jinterface/vsn.mk b/lib/jinterface/vsn.mk index 9d75a653e3..9d8229e9fa 100644 --- a/lib/jinterface/vsn.mk +++ b/lib/jinterface/vsn.mk @@ -1 +1 @@ -JINTERFACE_VSN = 1.5.4 +JINTERFACE_VSN = 1.5.5 diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml index ec57b03bd9..9121186631 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -30,6 +30,241 @@ </header> <p>This document describes the changes made to the Kernel application.</p> +<section><title>Kernel 2.15</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> Calls to <c>global:whereis_name/1</c> have been + substituted for calls to + <c>global:safe_whereis_name/1</c> since the latter is not + safe at all.</p> + <p>The reason for not doing this earlier is that setting + a global lock masked out a bug concerning the restart of + supervised children. The bug has now been fixed by a + modification of <c>global:whereis_name/1</c>. (Thanks to + Ulf Wiger for code contribution.)</p> + <p>A minor race conditions in <c>gen_fsm:start*</c> has + been fixed: if one of these functions returned <c>{error, + Reason}</c> or ignore, the name could still be registered + (either locally or in <c>global</c>. (This is the same + modification as was done for gen_server in OTP-7669.)</p> + <p>The undocumented function + <c>global:safe_whereis_name/1</c> has been removed. </p> + <p> + Own Id: OTP-9212 Aux Id: seq7117, OTP-4174 </p> + </item> + <item> + <p> + Honor option <c>packet_size</c> for http packet parsing + by both TCP socket and <c>erlang:decode_packet</c>. This + gives the ability to accept HTTP headers larger than the + default setting, but also avoid DoS attacks by accepting + lines only up to whatever length you wish to allow. For + consistency, packet type <c>line</c> also honor option + <c>packet_size</c>. (Thanks to Steve Vinoski)</p> + <p> + Own Id: OTP-9389</p> + </item> + <item> + <p> <c>disk_log:reopen/2,3</c> and + <c>disk_log:breopen/3</c> could return the error reason + from <c>file:rename/2</c> rather than the reason + <c>{file_error, Filename, Reason}</c>. This bug has been + fixed. </p> <p> The message <c>{disk_log, Node, {error, + disk_log_stopped}}</c> which according the documentation + is sent upon failure to truncate or reopen a disk log was + sometimes turned into a reply. This bug has been fixed. + </p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9508</p> + </item> + <item> + <p> + Environment variable 'shutdown_timeout' is added to + kernel application. Earlier, application_controller would + hang forever if an application top supervisor did not + terminate upon a shutdown request. If this new + environment variable is set to a positive integer T, then + application controller will now give up after T + milliseconds and instead brutally kill the application. + For backwards compatibility, the default value for + shutdown_timeout is 'infinity'.</p> + <p> + Own Id: OTP-9540</p> + </item> + <item> + <p> + Add '-callback' attributes in stdlib's behaviours</p> + <p> + Replace the behaviour_info(callbacks) export in stdlib's + behaviours with -callback' attributes for all the + callbacks. Update the documentation with information on + the callback attribute Automatically generate + 'behaviour_info' function from '-callback' attributes</p> + <p> + 'behaviour_info(callbacks)' is a special function that is + defined in a module which describes a behaviour and + returns a list of its callbacks.</p> + <p> + This function is now automatically generated using the + '-callback' specs. An error is returned by lint if user + defines both '-callback' attributes and the + behaviour_info/1 function. If no type info is needed for + a callback use a generic spec for it. Add '-callback' + attribute to language syntax</p> + <p> + Behaviours may define specs for their callbacks using the + familiar spec syntax, replacing the '-spec' keyword with + '-callback'. Simple lint checks are performed to ensure + that no callbacks are defined twice and all types + referred are declared.</p> + <p> + These attributes can be then used by tools to provide + documentation to the behaviour or find discrepancies in + the callback definitions in the callback module.</p> + <p> + Add callback specs into 'application' module in kernel + Add callback specs to tftp module following internet + documentation Add callback specs to inets_service module + following possibly deprecated comments</p> + <p> + Own Id: OTP-9621</p> + </item> + <item> + <p> + make tab completion work in remote shells (Thanks to Mats + Cronqvist)</p> + <p> + Own Id: OTP-9673</p> + </item> + <item> + <p> + Add missing parenthesis in heart doc.</p> + <p> + Add missing spaces in the Reference Manual distributed + section.</p> + <p> + In the HTML version of the doc those spaces are necessary + to separate those words.</p> + <p> + Own Id: OTP-9693</p> + </item> + <item> + <p> + Fixes net_kernel:get_net_ticktime() doc</p> + <p> + Adds missing description when `ignored' is returned. + (Thanks to Ricardo Catalinas Jim�nez )</p> + <p> + Own Id: OTP-9713</p> + </item> + <item> + <p> While <c>disk_log</c> eagerly collects logged terms + for better performance, collecting too much data may + choke the system and cause huge binaries to be written. + In order to remedy the situation a (small) limit on the + amount of data that is collected before writing to disk + has been introduced. </p> + <p> + Own Id: OTP-9764</p> + </item> + <item> + <p> + <list> <item><p>Correct callback spec in application + module</p></item> <item><p>Refine warning about callback + specs with extra ranges</p></item> <item><p>Cleanup + autoimport compiler directives</p></item> <item><p>Fix + Dialyzer's warnings in typer</p></item> <item><p>Fix + Dialyzer's warning for its own code</p></item> + <item><p>Fix bug in Dialyzer's behaviours + analysis</p></item> <item><p>Fix crash in + Dialyzer</p></item> <item><p>Variable substitution was + not generalizing any unknown variables.</p></item> + </list></p> + <p> + Own Id: OTP-9776</p> + </item> + <item> + <p> + Fix a crash when file:change_time/2,3 are called with + invalid dates</p> + <p> + Calling file:change_time/2,3 with an invalid date tuple + (e.g file:change_time("file.txt", {undefined, + undefined})) will cause file_server_2 to crash. + error_logger will shutdown and the whole VM will stop. + Change behavior to validate given dates on system + boundaries. (i.e before issuing a server call).(Thanks to + Ahmed Omar)</p> + <p> + Own Id: OTP-9785</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> An option list argument can now be passed to + <c>file:read_file_info/2, file:read_link_info/2</c> and + <c>file:write_file_info/3</c> and set time type + information in the call. Valid options are <c>{time, + local}, {time, universal}</c> and <c>{time, posix}</c>. + In the case of <c>posix</c> time no conversions are made + which makes the operation a bit faster. </p> + <p> + Own Id: OTP-7687</p> + </item> + <item> + <p><c>file:list_dir/1,2</c> will now fill an buffer + entire with filenames from the efile driver before + sending it to an erlang process. This will speed up this + file operation in most cases.</p> + <p> + Own Id: OTP-9023</p> + </item> + <item> + <p>gen_sctp:open/0-2 may now return + {error,eprotonosupport} if SCTP is not supported</p> + <p>gen_sctp:peeloff/1 has been implemented and creates a + one-to-one socket which also are supported now</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9239</p> + </item> + <item> + <p> + Sendfile has been added to the file module's API. + sendfile/2 is used to read data from a file and send it + to a tcp socket using a zero copying mechanism if + available on that OS.</p> + <p> + Thanks to Tuncer Ayaz and Steve Vinovski for original + implementation</p> + <p> + Own Id: OTP-9240</p> + </item> + <item> + <p> + Tuple funs (a two-element tuple with a module name and a + function) are now officially deprecated and will be + removed in R16. Use '<c>fun M:F/A</c>' instead. To make + you aware that your system uses tuple funs, the very + first time a tuple fun is applied, a warning will be sent + to the error logger.</p> + <p> + Own Id: OTP-9649</p> + </item> + </list> + </section> + +</section> + <section><title>Kernel 2.14.5</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index 32a12e2b52..5d4f2eb70c 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -1317,15 +1317,21 @@ int_list([H|T]) when is_integer(H) -> int_list(T); int_list([_|_]) -> false; int_list([]) -> true. +load_file(Mod0, {From,_}=Caller, St0) -> + Mod = to_atom(Mod0), + case pending_on_load(Mod, From, St0) of + no -> load_file_1(Mod, Caller, St0); + {yes,St} -> {noreply,St} + end. -load_file(Mod, Caller, #state{path=Path,cache=no_cache}=St) -> +load_file_1(Mod, Caller, #state{path=Path,cache=no_cache}=St) -> case mod_to_bin(Path, Mod) of error -> {reply,{error,nofile},St}; {Mod,Binary,File} -> try_load_module(File, Mod, Binary, Caller, St) end; -load_file(Mod, Caller, #state{cache=Cache}=St0) -> +load_file_1(Mod, Caller, #state{cache=Cache}=St0) -> Key = {obj,Mod}, case ets:lookup(Cache, Key) of [] -> diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl index 77ca26b845..d8954f0cf7 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -314,7 +314,7 @@ eof_or_abort(S, AssocId, Action) -> -spec send(Socket, SndRcvInfo, Data) -> ok | {error, Reason} when Socket :: sctp_socket(), SndRcvInfo :: #sctp_sndrcvinfo{}, - Data :: binary | iolist(), + Data :: binary() | iolist(), Reason :: term(). %% Full-featured send. Rarely needed. @@ -331,7 +331,7 @@ send(S, SRI, Data) -> Socket :: sctp_socket(), Assoc :: #sctp_assoc_change{} | assoc_id(), Stream :: integer(), - Data :: binary | iolist(), + Data :: binary() | iolist(), Reason :: term(). send(S, #sctp_assoc_change{assoc_id=AssocId}, Stream, Data) diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 10ab3e4370..99b0cd2ffb 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -30,9 +30,9 @@ load_cached/1, start_node_with_cache/1, add_and_rehash/1, where_is_file_cached/1, where_is_file_no_cache/1, purge_stacktrace/1, mult_lib_roots/1, bad_erl_libs/1, - code_archive/1, code_archive2/1, on_load/1, - big_boot_embedded/1, - on_load_embedded/1, on_load_errors/1, native_early_modules/1]). + code_archive/1, code_archive2/1, on_load/1, on_load_binary/1, + on_load_embedded/1, on_load_errors/1, big_boot_embedded/1, + native_early_modules/1]). -export([init_per_testcase/2, end_per_testcase/2, init_per_suite/1, end_per_suite/1, @@ -55,8 +55,8 @@ all() -> add_and_rehash, where_is_file_no_cache, where_is_file_cached, purge_stacktrace, mult_lib_roots, bad_erl_libs, code_archive, code_archive2, on_load, - on_load_embedded, big_boot_embedded, on_load_errors, - native_early_modules]. + on_load_binary, on_load_embedded, on_load_errors, + big_boot_embedded, native_early_modules]. groups() -> []. @@ -1286,6 +1286,45 @@ on_load_wait_for_all([Ref|T]) -> end; on_load_wait_for_all([]) -> ok. +on_load_binary(_) -> + Master = on_load_binary_test_case_process, + register(Master, self()), + + %% Construct, compile and pretty-print. + Mod = on_load_binary, + File = atom_to_list(Mod) ++ ".erl", + Forms = [{attribute,1,file,{File,1}}, + {attribute,1,module,Mod}, + {attribute,2,export,[{ok,0}]}, + {attribute,3,on_load,{init,0}}, + {function,5,init,0, + [{clause,5,[],[], + [{op,6,'!', + {atom,6,Master}, + {tuple,6,[{atom,6,Mod},{call,6,{atom,6,self},[]}]}}, + {'receive',7,[{clause,8,[{atom,8,go}],[],[{atom,8,ok}]}]}]}]}, + {function,11,ok,0,[{clause,11,[],[],[{atom,11,true}]}]}], + {ok,Mod,Bin} = compile:forms(Forms, [report]), + [io:put_chars(erl_pp:form(F)) || F <- Forms], + + {Pid1,Ref1} = spawn_monitor(fun() -> + code:load_binary(Mod, File, Bin), + true = on_load_binary:ok() + end), + receive {Mod,OnLoadPid} -> ok end, + {Pid2,Ref2} = spawn_monitor(fun() -> + true = on_load_binary:ok() + end), + erlang:yield(), + OnLoadPid ! go, + receive {'DOWN',Ref1,process,Pid1,Exit1} -> ok end, + receive {'DOWN',Ref2,process,Pid2,Exit2} -> ok end, + normal = Exit1, + normal = Exit2, + true = code:delete(on_load_binary), + false = code:purge(on_load_binary), + ok. + on_load_embedded(Config) when is_list(Config) -> try on_load_embedded_1(Config) diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl index 7599a89779..d0d52c5ea7 100644 --- a/lib/kernel/test/erl_prim_loader_SUITE.erl +++ b/lib/kernel/test/erl_prim_loader_SUITE.erl @@ -175,10 +175,10 @@ wait_really_started(Node, N) -> inet_disconnects(doc) -> ["Start a node using the 'inet' loading method, ", "then lose the connection."]; inet_disconnects(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "VxWorks: tested separately"}; - _ -> + case test_server:is_native(erl_boot_server) of + true -> + {skip,"erl_boot_server is native"}; + false -> ?line Name = erl_prim_test_inet_disconnects, ?line Host = host(), ?line Cookie = atom_to_list(erlang:get_cookie()), diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 85346762ac..2b6af7e1fb 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -78,7 +78,7 @@ -export([altname/1]). --export([large_file/1]). +-export([large_file/1, large_write/1]). -export([read_line_1/1, read_line_2/1, read_line_3/1,read_line_4/1]). @@ -92,6 +92,8 @@ -export([bytes/2, iterate/3]). +%% System probe functions that might be handy to check from the shell +-export([disc_free/1, memsize/0]). -include_lib("test_server/include/test_server.hrl"). -include_lib("kernel/include/file.hrl"). @@ -106,7 +108,7 @@ all() -> {group, compression}, {group, links}, copy, delayed_write, read_ahead, segment_read, segment_write, ipread, pid2name, interleaved_read_write, otp_5814, - large_file, read_line_1, read_line_2, read_line_3, + large_file, large_write, read_line_1, read_line_2, read_line_3, read_line_4, standard_io]. groups() -> @@ -143,6 +145,13 @@ end_per_group(_GroupName, Config) -> init_per_suite(Config) when is_list(Config) -> + SaslConfig = case application:start(sasl) of + {error, {already_started, sasl}} -> + []; + ok -> + [{sasl,started}] + end, + ok = application:start(os_mon), case os:type() of {win32, _} -> Priv = ?config(priv_dir, Config), @@ -154,9 +163,9 @@ init_per_suite(Config) when is_list(Config) -> {ok, _} -> [] end, - ?FILE_INIT(HasAccessTime++Config); + ?FILE_INIT(HasAccessTime++Config++SaslConfig); _ -> - ?FILE_INIT(Config) + ?FILE_INIT(Config++SaslConfig) end. end_per_suite(Config) when is_list(Config) -> @@ -166,6 +175,13 @@ end_per_suite(Config) when is_list(Config) -> _ -> ok end, + application:stop(os_mon), + case proplists:get_value(sasl, Config) of + started -> + application:stop(sasl); + _Else -> + ok + end, ?FILE_FINI(Config). init_per_testcase(_Func, Config) -> @@ -394,6 +410,7 @@ make_del_dir(Config) when is_list(Config) -> %% Don't worry ;-) the parent directory should never be empty, right? ?line case ?FILE_MODULE:del_dir('..') of {error, eexist} -> ok; + {error, eacces} -> ok; %OpenBSD {error, einval} -> ok %FreeBSD end, ?line {error, enoent} = ?FILE_MODULE:del_dir(""), @@ -3287,50 +3304,13 @@ large_file(suite) -> large_file(doc) -> ["Tests positioning in large files (> 4G)"]; large_file(Config) when is_list(Config) -> - case {os:type(),os:version()} of - {{win32,nt},_} -> - do_large_file(Config); - {{unix,sunos},{A,B,C}} - when A == 5, B == 5, C >= 1; A == 5, B >= 6; A >= 6 -> - do_large_file(Config); - {{unix,Unix},_} when Unix =/= sunos -> - N = unix_free(Config), - io:format("Free: ~w KByte~n", [N]), - if N < 5 * (1 bsl 20) -> - %% Less than 5 GByte free - {skipped,"Less than 5 GByte free"}; - true -> - do_large_file(Config) - end; - _ -> - {skipped,"Only supported on Win32, Unix or SunOS >= 5.5.1"} - end. + run_large_file_test(Config, + fun(Name) -> do_large_file(Name) end, + "_large_file"). -unix_free(Config) -> - Cmd = ["df -k '",?config(priv_dir, Config),"'"], - DF0 = os:cmd(Cmd), - io:format("$ ~s~n~s", [Cmd,DF0]), - [$\n|DF1] = lists:dropwhile(fun ($\n) -> false; (_) -> true end, DF0), - {ok,[N],_} = io_lib:fread(" ~*s ~d", DF1), - N. +do_large_file(Name) -> + ?line Watchdog = ?t:timetrap(?t:minutes(20)), -do_large_file(Config) -> - ?line Watchdog = ?t:timetrap(?t:minutes(5)), - %% - ?line Name = filename:join(?config(priv_dir, Config), - ?MODULE_STRING ++ "_large_file"), - ?line Tester = self(), - Deleter = - spawn( - fun() -> - Mref = erlang:monitor(process, Tester), - receive - {'DOWN',Mref,_,_,_} -> ok; - {Tester,done} -> ok - end, - ?FILE_MODULE:delete(Name) - end), - %% ?line S = "1234567890", L = length(S), R = lists:reverse(S), @@ -3366,15 +3346,36 @@ do_large_file(Config) -> ?line {ok,R} = ?FILE_MODULE:read(F1, L+1), ?line ok = ?FILE_MODULE:close(F1), %% - ?line Mref = erlang:monitor(process, Deleter), - ?line Deleter ! {Tester,done}, - ?line receive {'DOWN',Mref,_,_,_} -> ok end, - %% ?line ?t:timetrap_cancel(Watchdog), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +large_write(Config) when is_list(Config) -> + run_large_file_test(Config, + fun(Name) -> do_large_write(Name) end, + "_large_write"). + +do_large_write(Name) -> + Memsize = memsize(), + io:format("Memsize = ~w Bytes~n", [Memsize]), + case {erlang:system_info(wordsize),Memsize} of + {4,_} -> + {skip,"Needs a 64-bit emulator"}; + {8,N} when N < 6 bsl 30 -> + {skip, + "This machine has < 6 GB memory: " + ++integer_to_list(N)}; + {8,_} -> + Size = 4*1024*1024*1024+1, + Bin = <<0:Size/unit:8>>, + ok = file:write_file(Name, Bin), + {ok,#file_info{size=Size}} = file:read_file_info(Name), + ok + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + response_analysis(Module, Function, Arguments) -> @@ -3950,3 +3951,67 @@ flush(Msgs) -> after 0 -> lists:reverse(Msgs) end. + +%%% +%%% Support for testing large files. +%%% + +run_large_file_test(Config, Run, Name) -> + case {os:type(),os:version()} of + {{win32,nt},_} -> + do_run_large_file_test(Config, Run, Name); + {{unix,sunos},OsVersion} when OsVersion < {5,5,1} -> + {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"}; + {{unix,_},_} -> + N = disc_free(?config(priv_dir, Config)), + io:format("Free disk: ~w KByte~n", [N]), + if N < 5 * (1 bsl 20) -> + %% Less than 5 GByte free + {skip,"Less than 5 GByte free"}; + true -> + do_run_large_file_test(Config, Run, Name) + end; + _ -> + {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"} + end. + + +do_run_large_file_test(Config, Run, Name0) -> + Name = filename:join(?config(priv_dir, Config), + ?MODULE_STRING ++ Name0), + + %% Set up a process that will delete this file. + Tester = self(), + Deleter = + spawn( + fun() -> + Mref = erlang:monitor(process, Tester), + receive + {'DOWN',Mref,_,_,_} -> ok; + {Tester,done} -> ok + end, + ?FILE_MODULE:delete(Name) + end), + + %% Run the test case. + Res = Run(Name), + + %% Delete file and finish deleter process. + Mref = erlang:monitor(process, Deleter), + Deleter ! {Tester,done}, + receive {'DOWN',Mref,_,_,_} -> ok end, + + Res. + +disc_free(Path) -> + Data = disksup:get_disk_data(), + {_,Tot,Perc} = hd(lists:filter( + fun({P,_Size,_Full}) -> + lists:prefix(filename:nativename(P), + filename:nativename(Path)) + end, lists:reverse(lists:sort(Data)))), + round(Tot * (1-(Perc/100))). + +memsize() -> + {Tot,_Used,_} = memsup:get_memory_data(), + Tot. diff --git a/lib/kernel/test/inet_res_SUITE_data/run-named b/lib/kernel/test/inet_res_SUITE_data/run-named index eeca680ab5..211d2c7af7 100755 --- a/lib/kernel/test/inet_res_SUITE_data/run-named +++ b/lib/kernel/test/inet_res_SUITE_data/run-named @@ -2,7 +2,7 @@ ## ## %CopyrightBegin% ## -## Copyright Ericsson AB 2009-2011. All Rights Reserved. +## Copyright Ericsson AB 2009-2012. All Rights Reserved. ## ## The contents of this file are subject to the Erlang Public License, ## Version 1.1, (the "License"); you may not use this file except in @@ -47,7 +47,6 @@ CONF_FILE=named.conf INC_FILE=named_inc.conf PID_FILE=named.pid LOG_FILE=named.log -EXIT_FILE=named.exit error () { r=$? @@ -150,7 +149,6 @@ cat >>"$CONF_FILE" <<-CONF_FILE ( cd "$SRCDIR" && ls -1 ) | while read f; do cp -fp "$SRCDIR/$f" . done -rm -f "$EXIT_FILE" # Start nameserver echo "Cwd: `pwd`" @@ -158,19 +156,20 @@ echo "Nameserver: $NAMED_VER" echo "Port: $2" echo "ZoneDir: $3" echo "Command: $NAMED $NAMED_FG -c $CONF_FILE" -($NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 </dev/null; \ - echo "$?" >"$EXIT_FILE")& +$NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 </dev/null & NAMED_PID=$! -trap "kill -TERM $NAMED_PID >/dev/null 2>&1; wait $NAMED_PID >/dev/null 2>&1" \ +echo "Pid: $NAMED_PID" +trap "kill $NAMED_PID >/dev/null 2>&1; wait $NAMED_PID >/dev/null 2>&1" \ 0 1 2 3 15 + sleep 5 # Give name server time to load its zone files -if [ -f "$EXIT_FILE" ]; then - ERROR="`cat "$EXIT_FILE"`" - (exit "$ERROR")& error "$NAMED returned $ERROR on start" -else + +if ps -p $NAMED_PID >/dev/null 2>&1 || ps p $NAMED_PID >/dev/null 2>&1; then echo "Running: Enter \`\`quit'' to terminate nameserver[$NAMED_PID]..." while read LINE; do test :"$LINE" = :'quit' && break done + echo "Closing: Terminating nameserver..." +else + error "$NAMED failed to start" fi -echo "Closing: Terminating nameserver..." diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index ccf26ee034..3e2202922c 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -52,6 +52,10 @@ list_dir_limit/1]). -export([advise/1]). +-export([large_write/1]). + +%% System probe functions that might be handy to check from the shell +-export([unix_free/1]). -include_lib("test_server/include/test_server.hrl"). -include_lib("kernel/include/file.hrl"). @@ -83,7 +87,7 @@ groups() -> cur_dir_1a, cur_dir_1b]}, {files, [], [{group, open}, {group, pos}, {group, file_info}, - truncate, sync, datasync, advise]}, + truncate, sync, datasync, advise, large_write]}, {open, [], [open1, modes, close, access, read_write, pread_write, append, exclusive]}, @@ -290,6 +294,7 @@ make_del_dir(Config, Handle, Suffix) -> %% Don't worry ;-) the parent directory should never be empty, right? ?line case ?PRIM_FILE_call(del_dir, Handle, [".."]) of {error, eexist} -> ok; + {error, eacces} -> ok; %OpenBSD {error, einval} -> ok %FreeBSD end, ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]), @@ -1322,6 +1327,41 @@ advise(Config) when is_list(Config) -> ?line test_server:timetrap_cancel(Dog), ok. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +large_write(Config) when is_list(Config) -> + run_large_file_test(Config, + fun(Name) -> do_large_write(Name) end, + "_large_write"). + +do_large_write(Name) -> + Dog = test_server:timetrap(test_server:minutes(60)), + ChunkSize = (256 bsl 20) + 1, % 256 M + 1 + Chunks = 16, % times 16 -> 4 G + 16 + Base = 100, + Interleave = lists:seq(Base+1, Base+Chunks), + Chunk = <<0:ChunkSize/unit:8>>, + Data = zip_data(lists:duplicate(Chunks, Chunk), Interleave), + Size = Chunks * ChunkSize + Chunks, % 4 G + 32 + Wordsize = erlang:system_info(wordsize), + case prim_file:write_file(Name, Data) of + ok when Wordsize =:= 8 -> + {ok,#file_info{size=Size}} = file:read_file_info(Name), + {ok,Fd} = prim_file:open(Name, [read]), + check_large_write(Dog, Fd, ChunkSize, 0, Interleave); + {error,einval} when Wordsize =:= 4 -> + ok + end. + +check_large_write(Dog, Fd, ChunkSize, Pos, [X|Interleave]) -> + Pos1 = Pos + ChunkSize, + {ok,Pos1} = prim_file:position(Fd, {cur,ChunkSize}), + {ok,[X]} = prim_file:read(Fd, 1), + check_large_write(Dog, Fd, ChunkSize, Pos1+1, Interleave); +check_large_write(Dog, Fd, _, _, []) -> + eof = prim_file:read(Fd, 1), + test_server:timetrap_cancel(Dog), + ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2044,3 +2084,70 @@ list_dir_limit_cleanup(Dir, Handle, N, Cnt) -> ?PRIM_FILE:delete(Handle, filename:join(Dir, Name)), list_dir_limit_cleanup(Dir, Handle, N, Cnt+1). +%%% +%%% Support for testing large files. +%%% + +run_large_file_test(Config, Run, Name) -> + case {os:type(),os:version()} of + {{win32,nt},_} -> + do_run_large_file_test(Config, Run, Name); + {{unix,sunos},OsVersion} when OsVersion < {5,5,1} -> + {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"}; + {{unix,_},_} -> + N = unix_free(?config(priv_dir, Config)), + io:format("Free disk: ~w KByte~n", [N]), + if N < 5 bsl 20 -> + %% Less than 5 GByte free + {skip,"Less than 5 GByte free disk"}; + true -> + do_run_large_file_test(Config, Run, Name) + end; + _ -> + {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"} + end. + + +do_run_large_file_test(Config, Run, Name0) -> + Name = filename:join(?config(priv_dir, Config), + ?MODULE_STRING ++ Name0), + + %% Set up a process that will delete this file. + Tester = self(), + Deleter = + spawn( + fun() -> + Mref = erlang:monitor(process, Tester), + receive + {'DOWN',Mref,_,_,_} -> ok; + {Tester,done} -> ok + end, + prim_file:delete(Name) + end), + + %% Run the test case. + Res = Run(Name), + + %% Delete file and finish deleter process. + Mref = erlang:monitor(process, Deleter), + Deleter ! {Tester,done}, + receive {'DOWN',Mref,_,_,_} -> ok end, + + Res. + +unix_free(Path) -> + Cmd = ["df -k '",Path,"'"], + DF0 = os:cmd(Cmd), + io:format("$ ~s~n~s", [Cmd,DF0]), + Lines = re:split(DF0, "\n", [trim,{return,list}]), + Last = lists:last(Lines), + RE = "^[^\\s]*\\s+\\d+\\s+\\d+\\s+(\\d+)", + {match,[Avail]} = re:run(Last, RE, [{capture,all_but_first,list}]), + list_to_integer(Avail). + +zip_data([A|As], [B|Bs]) -> + [[A,B]|zip_data(As, Bs)]; +zip_data([], Bs) -> + Bs; +zip_data(As, []) -> + As. diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index 76c62ece67..76d3003ff4 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 2.15 +KERNEL_VSN = 2.15.1 diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml index 1bb80f8fe3..a300fcc12d 100644 --- a/lib/mnesia/doc/src/notes.xml +++ b/lib/mnesia/doc/src/notes.xml @@ -38,7 +38,61 @@ thus constitutes one section in this document. The title of each section is the version number of Mnesia.</p> - <section><title>Mnesia 4.5.1</title> + <section><title>Mnesia 4.6</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Reduce calls to phash in key_to_frag_number</p> + <p> + Original code calls phash 1..2 times, based on which + fragment the hashed key targets and how many fragments + exist. New code always calls phash only once.</p> + <p> + Add mnesia_frag_hash test (Thanks to Philip Robinson)</p> + <p> + Own Id: OTP-9722</p> + </item> + <item> + <p> + Fixed a sticky lock bug which caused mnesia:read(Tab, + Key, write) return undefined.</p> + <p> + Own Id: OTP-9786</p> + </item> + <item> + <p> + Use the synchronous log_terms instead of alog_terms in + mnesia_log:ets2dcd()</p> + <p> + This avoids the situation where mnesia could dump a very + large ets table in its entirety into the message queue of + the disk_log process, causing memory blowup and choking + the disk logger. (Thanks to Richard Carlsson)</p> + <p> + Own Id: OTP-9804</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Implemented a new option to mnesia:create_table/2 which + allows the user to assign 'ets' and 'dets' options not + available in mnesia.</p> + <p> + Own Id: OTP-8970</p> + </item> + </list> + </section> + +</section> + +<section><title>Mnesia 4.5.1</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl index de4811f8e4..a22c95d454 100644 --- a/lib/mnesia/src/mnesia_locker.erl +++ b/lib/mnesia/src/mnesia_locker.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -66,7 +66,7 @@ -record(queue, {oid, tid, op, pid, lucky}). -%% mnesia_held_locks: contain {Oid, Op, Tid} entries (bag) +%% mnesia_held_locks: contain {Oid, MaxLock, [{Op, Tid}]} entries -define(match_oid_held_locks(Oid), {Oid, '_', '_'}). %% mnesia_tid_locks: contain {Tid, Oid, Op} entries (bag) -define(match_oid_tid_locks(Tid), {Tid, '_', '_'}). @@ -83,7 +83,7 @@ start() -> init(Parent) -> register(?MODULE, self()), process_flag(trap_exit, true), - ?ets_new_table(mnesia_held_locks, [bag, private, named_table]), + ?ets_new_table(mnesia_held_locks, [ordered_set, private, named_table]), ?ets_new_table(mnesia_tid_locks, [bag, private, named_table]), ?ets_new_table(mnesia_sticky_locks, [set, private, named_table]), ?ets_new_table(mnesia_lock_queue, [bag, private, named_table, {keypos, 2}]), @@ -235,10 +235,17 @@ loop(State) -> loop(State) end. -set_lock(Tid, Oid, Op) -> - ?dbg("Granted ~p ~p ~p~n", [Tid,Oid,Op]), - ?ets_insert(mnesia_held_locks, {Oid, Op, Tid}), - ?ets_insert(mnesia_tid_locks, {Tid, Oid, Op}). +set_lock(Tid, Oid, Op, []) -> + ?ets_insert(mnesia_tid_locks, {Tid, Oid, Op}), + ?ets_insert(mnesia_held_locks, {Oid, Op, [{Op, Tid}]}); +set_lock(Tid, Oid, read, [{Oid, Prev, Items}]) -> + ?ets_insert(mnesia_tid_locks, {Tid, Oid, read}), + ?ets_insert(mnesia_held_locks, {Oid, Prev, [{read, Tid}|Items]}); +set_lock(Tid, Oid, write, [{Oid, _Prev, Items}]) -> + ?ets_insert(mnesia_tid_locks, {Tid, Oid, write}), + ?ets_insert(mnesia_held_locks, {Oid, write, [{write, Tid}|Items]}); +set_lock(Tid, Oid, Op, undefined) -> + set_lock(Tid, Oid, Op, ?ets_lookup(mnesia_held_locks, Oid)). %%%%%%%%%%%%%%%%%%%%%%%%%%% %% Acquire locks @@ -261,14 +268,14 @@ try_lock(Tid, Op, Pid, Oid) -> try_lock(Tid, Op, SimpleOp, Lock, Pid, Oid) -> case can_lock(Tid, Lock, Oid, {no, bad_luck}) of - yes -> - Reply = grant_lock(Tid, SimpleOp, Lock, Oid), + {yes, Default} -> + Reply = grant_lock(Tid, SimpleOp, Lock, Oid, Default), reply(Pid, Reply); - {no, Lucky} -> + {{no, Lucky},_} -> C = #cyclic{op = SimpleOp, lock = Lock, oid = Oid, lucky = Lucky}, ?dbg("Rejected ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]), reply(Pid, {not_granted, C}); - {queue, Lucky} -> + {{queue, Lucky},_} -> ?dbg("Queued ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]), %% Append to queue: Nice place for trace output ?ets_insert(mnesia_lock_queue, @@ -277,16 +284,16 @@ try_lock(Tid, Op, SimpleOp, Lock, Pid, Oid) -> ?ets_insert(mnesia_tid_locks, {Tid, Oid, {queued, Op}}) end. -grant_lock(Tid, read, Lock, Oid = {Tab, Key}) +grant_lock(Tid, read, Lock, Oid = {Tab, Key}, Default) when Key /= ?ALL, Tab /= ?GLOBAL -> case node(Tid#tid.pid) == node() of true -> - set_lock(Tid, Oid, Lock), + set_lock(Tid, Oid, Lock, Default), {granted, lookup_in_client}; false -> try Val = mnesia_lib:db_get(Tab, Key), %% lookup as well - set_lock(Tid, Oid, Lock), + set_lock(Tid, Oid, Lock, Default), {granted, Val} catch _:_Reason -> %% Table has been deleted from this node, @@ -296,19 +303,19 @@ grant_lock(Tid, read, Lock, Oid = {Tab, Key}) {not_granted, C} end end; -grant_lock(Tid, {ix_read,IxKey,Pos}, Lock, Oid = {Tab, _}) -> +grant_lock(Tid, {ix_read,IxKey,Pos}, Lock, Oid = {Tab, _}, Default) -> try Res = ix_read_res(Tab, IxKey,Pos), - set_lock(Tid, Oid, Lock), + set_lock(Tid, Oid, Lock, Default), {granted, Res, [?ALL]} catch _:_ -> {not_granted, {no_exists, Tab, {index, [Pos]}}} end; -grant_lock(Tid, read, Lock, Oid) -> - set_lock(Tid, Oid, Lock), +grant_lock(Tid, read, Lock, Oid, Default) -> + set_lock(Tid, Oid, Lock, Default), {granted, ok}; -grant_lock(Tid, write, Lock, Oid) -> - set_lock(Tid, Oid, Lock), +grant_lock(Tid, write, Lock, Oid, Default) -> + set_lock(Tid, Oid, Lock, Default), granted. %% 1) Impose an ordering on all transactions favour old (low tid) transactions @@ -318,55 +325,40 @@ grant_lock(Tid, write, Lock, Oid) -> %% 3) TabLocks is the problem :-) They should not starve and not deadlock %% handle tablocks in queue as they had locks on unlocked records. -can_lock(Tid, read, {Tab, Key}, AlreadyQ) when Key /= ?ALL -> - %% The key is bound, no need for the other BIF - Oid = {Tab, Key}, - ObjLocks = ?ets_match_object(mnesia_held_locks, {Oid, write, '_'}), - TabLocks = ?ets_match_object(mnesia_held_locks, {{Tab, ?ALL}, write, '_'}), - check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, read); +can_lock(Tid, read, Oid = {Tab, Key}, AlreadyQ) when Key /= ?ALL -> + ObjLocks = ?ets_lookup(mnesia_held_locks, Oid), + TabLocks = ?ets_lookup(mnesia_held_locks, {Tab, ?ALL}), + {check_lock(Tid, Oid, + filter_write(ObjLocks), + filter_write(TabLocks), + yes, AlreadyQ, read), + ObjLocks}; can_lock(Tid, read, Oid, AlreadyQ) -> % Whole tab Tab = element(1, Oid), ObjLocks = ?ets_match_object(mnesia_held_locks, {{Tab, '_'}, write, '_'}), - check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, read); + {check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, read), undefined}; -can_lock(Tid, write, {Tab, Key}, AlreadyQ) when Key /= ?ALL -> - Oid = {Tab, Key}, +can_lock(Tid, write, Oid = {Tab, Key}, AlreadyQ) when Key /= ?ALL -> ObjLocks = ?ets_lookup(mnesia_held_locks, Oid), TabLocks = ?ets_lookup(mnesia_held_locks, {Tab, ?ALL}), - check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, write); + {check_lock(Tid, Oid, ObjLocks, TabLocks, yes, AlreadyQ, write), ObjLocks}; can_lock(Tid, write, Oid, AlreadyQ) -> % Whole tab Tab = element(1, Oid), ObjLocks = ?ets_match_object(mnesia_held_locks, ?match_oid_held_locks({Tab, '_'})), - check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, write). + {check_lock(Tid, Oid, ObjLocks, [], yes, AlreadyQ, write), undefined}. + +filter_write([{_, read, _}]) -> []; +filter_write(Res) -> Res. %% Check held locks for conflicting locks -check_lock(Tid, Oid, [Lock | Locks], TabLocks, X, AlreadyQ, Type) -> - case element(3, Lock) of - Tid -> - check_lock(Tid, Oid, Locks, TabLocks, X, AlreadyQ, Type); - WaitForTid -> - Queue = allowed_to_be_queued(WaitForTid,Tid), - if Queue == true -> - check_lock(Tid, Oid, Locks, TabLocks, {queue, WaitForTid}, AlreadyQ, Type); - Tid#tid.pid == WaitForTid#tid.pid -> - dbg_out("Spurious lock conflict ~w ~w: ~w -> ~w~n", - [Oid, Lock, Tid, WaitForTid]), - %% Test.. - {Tab, _Key} = Oid, - HaveQ = (ets:lookup(mnesia_lock_queue, Oid) /= []) - orelse (ets:lookup(mnesia_lock_queue,{Tab,?ALL}) /= []), - if - HaveQ -> - {no, WaitForTid}; - true -> - check_lock(Tid,Oid,Locks,TabLocks,{queue,WaitForTid},AlreadyQ,Type) - end; - %%{no, WaitForTid}; Safe solution - true -> - {no, WaitForTid} - end +check_lock(Tid, Oid, [{_, _, Lock} | Locks], TabLocks, _X, AlreadyQ, Type) -> + case can_queue(Lock, Tid, Oid, _X) of + {no, _} = Res -> + Res; + Res -> + check_lock(Tid, Oid, Locks, TabLocks, Res, AlreadyQ, Type) end; check_lock(_, _, [], [], X, {queue, bad_luck}, _) -> @@ -375,8 +367,7 @@ check_lock(_, _, [], [], X, {queue, bad_luck}, _) -> check_lock(_, _, [], [], X = {queue, _Tid}, _AlreadyQ, _) -> X; -check_lock(Tid, Oid, [], [], X, AlreadyQ, Type) -> - {Tab, Key} = Oid, +check_lock(Tid, Oid = {Tab, Key}, [], [], X, AlreadyQ, Type) -> if Type == write -> check_queue(Tid, Tab, X, AlreadyQ); @@ -403,6 +394,26 @@ check_lock(Tid, Oid, [], [], X, AlreadyQ, Type) -> check_lock(Tid, Oid, [], TabLocks, X, AlreadyQ, Type) -> check_lock(Tid, Oid, TabLocks, [], X, AlreadyQ, Type). +can_queue([{_Op, Tid}|Locks], Tid, Oid, Res) -> + can_queue(Locks, Tid, Oid, Res); +can_queue([{Op, WaitForTid}|Locks], Tid, Oid = {Tab, _}, _) -> + case allowed_to_be_queued(WaitForTid,Tid) of + true when Tid#tid.pid == WaitForTid#tid.pid -> + dbg_out("Spurious lock conflict ~w ~w: ~w -> ~w~n", + [Oid, Op, Tid, WaitForTid]), + HaveQ = (ets:lookup(mnesia_lock_queue, Oid) /= []) + orelse (ets:lookup(mnesia_lock_queue,{Tab,?ALL}) /= []), + case HaveQ of + true -> {no, WaitForTid}; + false -> can_queue(Locks, Tid, Oid, {queue, WaitForTid}) + end; + true -> + can_queue(Locks, Tid, Oid, {queue, WaitForTid}); + false -> + {no, WaitForTid} + end; +can_queue([], _, _, Res) -> Res. + %% True if WaitForTid > Tid -> % Important order allowed_to_be_queued(WaitForTid, Tid) -> case get(pid_sort_order) of @@ -456,14 +467,14 @@ set_read_lock_on_all_keys(Tid, From, Tab, IxKey, Pos) -> Op = {ix_read,IxKey, Pos}, Lock = read, case can_lock(Tid, Lock, Oid, {no, bad_luck}) of - yes -> - Reply = grant_lock(Tid, Op, Lock, Oid), + {yes, Default} -> + Reply = grant_lock(Tid, Op, Lock, Oid, Default), reply(From, Reply); - {no, Lucky} -> + {{no, Lucky},_} -> C = #cyclic{op = Op, lock = Lock, oid = Oid, lucky = Lucky}, ?dbg("Rejected ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]), reply(From, {not_granted, C}); - {queue, Lucky} -> + {{queue, Lucky},_} -> ?dbg("Queued ~p ~p ~p ~p ~n", [Tid, Oid, Lock, Lucky]), %% Append to queue: Nice place for trace output ?ets_insert(mnesia_lock_queue, @@ -520,14 +531,24 @@ release_locks([]) -> release_lock({Tid, Oid, {queued, _}}) -> ?ets_match_delete(mnesia_lock_queue, #queue{oid=Oid, tid = Tid, op = '_', pid = '_', lucky = '_'}); -release_lock({Tid, Oid, Op}) -> - if - Op == write -> - ?ets_delete(mnesia_held_locks, Oid); - Op == read -> - ets:delete_object(mnesia_held_locks, {Oid, Op, Tid}) +release_lock({_Tid, Oid, write}) -> + ?ets_delete(mnesia_held_locks, Oid); +release_lock({Tid, Oid, read}) -> + case ?ets_lookup(mnesia_held_locks, Oid) of + [{Oid, Prev, Locks0}] -> + case remove_tid(Locks0, Tid, []) of + [] -> ?ets_delete(mnesia_held_locks, Oid); + Locks -> ?ets_insert(mnesia_held_locks, {Oid, Prev, Locks}) + end; + [] -> ok end. +remove_tid([{_Op, Tid}|Ls], Tid, Acc) -> + remove_tid(Ls,Tid, Acc); +remove_tid([Keep|Ls], Tid, Acc) -> + remove_tid(Ls,Tid, [Keep|Acc]); +remove_tid([], _, Acc) -> Acc. + rearrange_queue([{_Tid, {Tab, Key}, _} | Locks]) -> if Key /= ?ALL-> @@ -592,18 +613,18 @@ try_waiter({queue, Oid, Tid, Op, ReplyTo, _}) -> try_waiter(Oid, Op, SimpleOp, Lock, ReplyTo, Tid) -> case can_lock(Tid, Lock, Oid, {queue, bad_luck}) of - yes -> + {yes, Default} -> %% Delete from queue: Nice place for trace output ?ets_match_delete(mnesia_lock_queue, #queue{oid=Oid, tid = Tid, op = Op, pid = ReplyTo, lucky = '_'}), - Reply = grant_lock(Tid, SimpleOp, Lock, Oid), + Reply = grant_lock(Tid, SimpleOp, Lock, Oid, Default), reply(ReplyTo,Reply), locked; - {queue, _Why} -> + {{queue, _Why}, _} -> ?dbg("Keep ~p ~p ~p ~p~n", [Tid, Oid, Lock, _Why]), queued; % Keep waiter in queue - {no, Lucky} -> + {{no, Lucky}, _} -> C = #cyclic{op = SimpleOp, lock = Lock, oid = Oid, lucky = Lucky}, verbose("** WARNING ** Restarted transaction, possible deadlock in lock queue ~w: cyclic = ~w~n", [Tid, C]), @@ -1116,11 +1137,23 @@ rec_requests([], _Oid, _Store) -> get_held_locks() -> ?MODULE ! {get_table, self(), mnesia_held_locks}, - receive {mnesia_held_locks, Locks} -> Locks end. + Locks = receive {mnesia_held_locks, Ls} -> Ls after 5000 -> [] end, + rewrite_locks(Locks, []). + +rewrite_locks([{Oid, _, Ls}|Locks], Acc0) -> + Acc = rewrite_locks(Ls, Oid, Acc0), + rewrite_locks(Locks, Acc); +rewrite_locks([], Acc) -> + lists:reverse(Acc). + +rewrite_locks([{Op, Tid}|Ls], Oid, Acc) -> + rewrite_locks(Ls, Oid, [{Oid, Op, Tid}|Acc]); +rewrite_locks([], _, Acc) -> + Acc. get_lock_queue() -> ?MODULE ! {get_table, self(), mnesia_lock_queue}, - Q = receive {mnesia_lock_queue, Locks} -> Locks end, + Q = receive {mnesia_lock_queue, Locks} -> Locks after 5000 -> [] end, [{Oid, Op, Pid, Tid, WFT} || {queue, Oid, Tid, Op, Pid, WFT} <- Q]. do_stop() -> diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk index ebf79dd2ae..080548acac 100644 --- a/lib/mnesia/vsn.mk +++ b/lib/mnesia/vsn.mk @@ -1 +1 @@ -MNESIA_VSN = 4.5.1 +MNESIA_VSN = 4.6 diff --git a/lib/observer/doc/src/notes.xml b/lib/observer/doc/src/notes.xml index baa1354268..a9554a08f4 100644 --- a/lib/observer/doc/src/notes.xml +++ b/lib/observer/doc/src/notes.xml @@ -31,6 +31,125 @@ <p>This document describes the changes made to the Observer application.</p> +<section><title>Observer 1.0</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The following bugs in <c>ttb</c> have been corrected:</p> + <p> + <list> <item><c>ttb:tracer/2</c> would earlier crash when + trying to set up tracing for a diskless node to wrap + files, i.e. when option + <c>{file,{local,{wrap,Filename,Size,Count}}}</c> was + used.</item> <item><c>ttb:stop([fetch])</c> would + sometimes silently fail if multiple nodes with different + current working directories were traced.</item> + <item><c>ttb:stop([fetch])</c> would crash if the tracer + was started with option + <c>{file,{local,Filename}}</c></item> <item>A deadlock + would sometimes occur due to an information printout from + the <c>ttb_control</c> process when <c>ttb</c> was + stopped.</item> </list></p> + <p> + Own Id: OTP-9431</p> + </item> + <item> + <p> + The file trace port to which the IP trace client relays + all traces from diskless nodes was not flushed and closed + properly on ttb:stop. This has been corrected.</p> + <p> + Own Id: OTP-9665</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + A new GUI for Observer. Integrating pman, etop, appmon + and tv into observer with tracing facilities.</p> + <p> + Own Id: OTP-4779</p> + </item> + <item> + <p> + The following new features are added to <c>ttb</c>:</p> + <p> + <list> <item>A one-command trace setup is added, + <c>ttb:start_trace/4</c>.</item> <item>The following new + options are added to <c>ttb:tracer/2</c>: <list> + <item><em><c>shell</c></em> - Show trace messages on the + console in real time</item> <item><em><c>timer</c></em> - + Time constrained tracing</item> + <item><em><c>overload</c></em> - Overload + protection</item> <item><em><c>flush</c></em> - Flush + file trace port buffers with given frequency</item> + <item><em><c>resume</c></em> - Automatically resume + tracing after node restart</item> </list> </item> <item> + A new shortcut is added for common tracer settings + similar to using the <c>dbg</c> module directly, + <c>ttb:tracer(shell | dbg)</c>. </item> <item> Some + shortcuts are added for commonly used match + specifications in <c>ttb:tp</c> and <c>ttb:tpl</c>. + </item> <item> The <c>Options</c> argument to functions + <c>ttb:tracer</c>, <c>ttb:write_config</c>, + <c>ttb:stop</c> and <c>ttb:format</c> may now be one + single option instead of a list. </item> <item> The + history buffer of the last trace is now always + automatically dumped to the file <c>ttb_last_config</c> + when <c>ttb:stop</c> is called. </item> <item> The + following new options are added to <c>ttb:stop/1</c>: + <list> <item><em><c>fetch_dir</c></em> - Specify where to + store fetched logs</item> + <item><em><c>{format,FormatOpts}</c></em> - Specify + options to use when formatting the fetched logs</item> + <item><em><c>return_fetch_dir</c></em> - Indicate that + the return value from <c>ttb:stop/1</c> should include + the name of the directory where the fetched logs are + stored</item> </list> </item> <item> The option + <c>disable_sort</c> is added to <c>ttb:format/2</c>. When + this option is used, trace messages from different logs + are not merged according to timestamps, but just appended + one log after the other. </item> </list></p> + <p> + Own Id: OTP-9403</p> + </item> + <item> + <p> + The following non backwards compatible changes are done + in <c>ttb</c>:</p> + <p> + <list> <item> When setting up trace with ttb, the + 'timestamp' trace flag will now always be set. </item> + <item> The 'fetch' option to ttb:stop/1 is removed since + it is now default behavior that trace logs are fetched + when stopping ttb. Fetching can be disabled with the + 'nofetch' option to ttb:stop/1. </item> <item> The name + of the upload directory is changed from + ttb_upload-Timestamp to ttb_upload_FileName-Timestamp. + </item> <item> To format the output using 'et', you now + need to provide the option {handler,ttb:get_et_handler()} + instead of {handler,et}. </item> <item> When formatting a + trace log, the handler state was earlier reset after each + trace file, this is now changed so the handler state is + passed not only from one trace message to the next in the + same file, but also from one file to the next. </item> + </list></p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9430</p> + </item> + </list> + </section> + +</section> + <section><title>Observer 0.9.10</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/observer/src/etop_gui.erl b/lib/observer/src/etop_gui.erl index ff1b8078ad..9248d67344 100644 --- a/lib/observer/src/etop_gui.erl +++ b/lib/observer/src/etop_gui.erl @@ -17,6 +17,13 @@ %% %CopyrightEnd% %% -module(etop_gui). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}]). + -author('[email protected]'). -export([init/1,stop/1]). diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl index 967baa5c7a..5260861497 100644 --- a/lib/observer/src/observer_lib.erl +++ b/lib/observer/src/observer_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% Copyright Ericsson AB 2011-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -339,17 +339,37 @@ user_term(Parent, Title, Default) -> ?wxID_OK -> Str = wxTextEntryDialog:getValue(Dialog), wxTextEntryDialog:destroy(Dialog), - parse_string(Str); + parse_string(ensure_last_is_dot(Str)); ?wxID_CANCEL -> - wxTextEntryDialog:destroy(Dialog) + wxTextEntryDialog:destroy(Dialog), + cancel end. parse_string(Str) -> try - {ok, Tokens, _} = erl_scan:string(Str), - erl_parse:parse_term(Tokens) - catch _:{badmatch, {error, {_, _, Err}}} -> - {error, ["Parse error: ", Err]}; - _Err -> + Tokens = case erl_scan:string(Str) of + {ok, Ts, _} -> Ts; + {error, {_SLine, SMod, SError}, _} -> + throw(io_lib:format("~s", [SMod:format_error(SError)])) + end, + case erl_parse:parse_term(Tokens) of + {error, {_PLine, PMod, PError}} -> + throw(io_lib:format("~s", [PMod:format_error(PError)])); + Res -> Res + end + catch + throw:ErrStr -> + {error, ErrStr}; + _:_Err -> {error, ["Syntax error in: ", Str]} end. + +ensure_last_is_dot([]) -> + "."; +ensure_last_is_dot(String) -> + case lists:last(String) =:= $. of + true -> + String; + false -> + String ++ "." + end. diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl index a4c5914c49..ec08d3aff1 100644 --- a/lib/observer/src/observer_procinfo.erl +++ b/lib/observer/src/observer_procinfo.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% Copyright Ericsson AB 2011-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -124,9 +124,14 @@ code_change(_, _, State) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% init_process_page(Panel, Pid) -> - Fields = process_info_fields(Pid), - {FPanel, _, UpFields} = observer_lib:display_info(Panel, Fields), - {FPanel, fun() -> observer_lib:update_info(UpFields, process_info_fields(Pid)) end}. + Fields0 = process_info_fields(Pid), + {FPanel, _, UpFields} = observer_lib:display_info(Panel, Fields0), + {FPanel, fun() -> case process_info_fields(Pid) of + Fields when is_list(Fields) -> + observer_lib:update_info(UpFields, Fields); + _ -> ok + end + end}. init_text_page(Parent) -> Style = ?wxTE_MULTILINE bor ?wxTE_RICH2 bor ?wxTE_READONLY, @@ -144,16 +149,20 @@ init_message_page(Parent, Pid) -> Number+1} end, Update = fun() -> - {messages,RawMessages} = - observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, messages]), - {Messages,_} = lists:mapfoldl(Format, 1, RawMessages), - Last = wxTextCtrl:getLastPosition(Text), - wxTextCtrl:remove(Text, 0, Last), - case Messages =:= [] of - true -> - wxTextCtrl:writeText(Text, "No messages"); - false -> - wxTextCtrl:writeText(Text, Messages) + case observer_wx:try_rpc(node(Pid), erlang, process_info, + [Pid, messages]) + of + {messages,RawMessages} -> + {Messages,_} = lists:mapfoldl(Format, 1, RawMessages), + Last = wxTextCtrl:getLastPosition(Text), + wxTextCtrl:remove(Text, 0, Last), + case Messages =:= [] of + true -> + wxTextCtrl:writeText(Text, "No messages"); + false -> + wxTextCtrl:writeText(Text, Messages) + end; + _ -> ok end end, Update(), @@ -162,12 +171,15 @@ init_message_page(Parent, Pid) -> init_dict_page(Parent, Pid) -> Text = init_text_page(Parent), Update = fun() -> - {dictionary,RawDict} = - observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, dictionary]), - Dict = [io_lib:format("~-20.w ~p~n", [K, V]) || {K, V} <- RawDict], - Last = wxTextCtrl:getLastPosition(Text), - wxTextCtrl:remove(Text, 0, Last), - wxTextCtrl:writeText(Text, Dict) + case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, dictionary]) + of + {dictionary,RawDict} -> + Dict = [io_lib:format("~-20.w ~p~n", [K, V]) || {K, V} <- RawDict], + Last = wxTextCtrl:getLastPosition(Text), + wxTextCtrl:remove(Text, 0, Last), + wxTextCtrl:writeText(Text, Dict); + _ -> ok + end end, Update(), {Text, Update}. @@ -183,24 +195,29 @@ init_stack_page(Parent, Pid) -> wxListCtrl:setColumnWidth(LCtrl, 1, 300), wxListItem:destroy(Li), Update = fun() -> - {current_stacktrace,RawBt} = - observer_wx:try_rpc(node(Pid), erlang, process_info, - [Pid, current_stacktrace]), - wxListCtrl:deleteAllItems(LCtrl), - wx:foldl(fun({M, F, A, Info}, Row) -> - _Item = wxListCtrl:insertItem(LCtrl, Row, ""), - ?EVEN(Row) andalso - wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN), - wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str({M,F,A})), - FileLine = case Info of - [{file,File},{line,Line}] -> - io_lib:format("~s:~w", [File,Line]); - _ -> - [] - end, - wxListCtrl:setItem(LCtrl, Row, 1, FileLine), - Row+1 - end, 0, RawBt) + case observer_wx:try_rpc(node(Pid), erlang, process_info, + [Pid, current_stacktrace]) + of + {current_stacktrace,RawBt} -> + observer_wx:try_rpc(node(Pid), erlang, process_info, + [Pid, current_stacktrace]), + wxListCtrl:deleteAllItems(LCtrl), + wx:foldl(fun({M, F, A, Info}, Row) -> + _Item = wxListCtrl:insertItem(LCtrl, Row, ""), + ?EVEN(Row) andalso + wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN), + wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str({M,F,A})), + FileLine = case Info of + [{file,File},{line,Line}] -> + io_lib:format("~s:~w", [File,Line]); + _ -> + [] + end, + wxListCtrl:setItem(LCtrl, Row, 1, FileLine), + Row+1 + end, 0, RawBt); + _ -> ok + end end, Resize = fun(#wx{event=#wxSize{size={W,_}}},Ev) -> wxEvent:skip(Ev), @@ -216,7 +233,6 @@ create_menus(MenuBar) -> observer_lib:create_menus(Menus, MenuBar, new_window). process_info_fields(Pid) -> - RawInfo = observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, item_list()]), Struct = [{"Overview", [{"Initial Call", initial_call}, {"Current Function", current_function}, @@ -246,7 +262,12 @@ process_info_fields(Pid) -> {"GC Min Heap Size", {bytes, get_gc_info(min_heap_size)}}, {"GC FullSweep After", get_gc_info(fullsweep_after)} ]}], - observer_lib:fill_info(Struct, RawInfo). + case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, item_list()]) of + RawInfo when is_list(RawInfo) -> + observer_lib:fill_info(Struct, RawInfo); + _ -> + ok + end. item_list() -> [ %% backtrace, diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl index 31d5f3d632..f432173f57 100644 --- a/lib/observer/src/observer_tv_table.erl +++ b/lib/observer/src/observer_tv_table.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% Copyright Ericsson AB 2011-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -58,7 +58,7 @@ source, tab, attrs, - timer + timer={false, 30} }). -record(opt, @@ -268,8 +268,8 @@ handle_event(#wx{id=?ID_DELETE}, handle_event(#wx{id=?wxID_CLOSE}, State) -> {stop, normal, State}; -handle_event(Help = #wx{id=?wxID_HELP}, State = #state{parent=Parent}) -> - Parent ! Help, +handle_event(Help = #wx{id=?wxID_HELP}, State) -> + observer ! Help, {noreply, State}; handle_event(#wx{id=?GOTO_ENTRY, event=#wxCommand{cmdString=Str}}, @@ -374,40 +374,51 @@ handle_event(#wx{id=?ID_REFRESH_INTERVAL}, Timer = observer_lib:interval_dialog(Grid, Timer0, 10, 5*60), {noreply, State#state{timer=Timer}}; -handle_event(Event, State) -> - io:format("~p:~p, handle event ~p\n", [?MODULE, ?LINE, Event]), +handle_event(_Event, State) -> + %io:format("~p:~p, handle event ~p\n", [?MODULE, ?LINE, Event]), {noreply, State}. -handle_sync_event(Event, _Obj, _State) -> - io:format("~p:~p, handle sync_event ~p\n", [?MODULE, ?LINE, Event]), +handle_sync_event(_Event, _Obj, _State) -> + %io:format("~p:~p, handle sync_event ~p\n", [?MODULE, ?LINE, Event]), ok. -handle_call(Event, From, State) -> - io:format("~p:~p, handle call (~p) ~p\n", [?MODULE, ?LINE, From, Event]), +handle_call(_Event, _From, State) -> + %io:format("~p:~p, handle call (~p) ~p\n", [?MODULE, ?LINE, From, Event]), {noreply, State}. -handle_cast(Event, State) -> - io:format("~p:~p, handle cast ~p\n", [?MODULE, ?LINE, Event]), +handle_cast(_Event, State) -> + %io:format("~p:~p, handle cast ~p\n", [?MODULE, ?LINE, Event]), {noreply, State}. handle_info({no_rows, N}, State = #state{grid=Grid, status=StatusBar}) -> wxListCtrl:setItemCount(Grid, N), wxStatusBar:setStatusText(StatusBar, io_lib:format("Objects: ~w",[N])), {noreply, State}; + handle_info({new_cols, New}, State = #state{grid=Grid, columns=Cols0}) -> Cols = add_columns(Grid, Cols0, New), {noreply, State#state{columns=Cols}}; + handle_info({refresh, Min, Max}, State = #state{grid=Grid}) -> wxListCtrl:refreshItems(Grid, Min, Max), {noreply, State}; + +handle_info(refresh_interval, State = #state{pid=Pid}) -> + Pid ! refresh, + {noreply, State}; + handle_info({error, Error}, State = #state{frame=Frame}) -> - Dlg = wxMessageDialog:new(Frame, Error), + ErrorStr = + try io_lib:format("~ts", [Error]), Error + catch _:_ -> io_lib:format("~p", [Error]) + end, + Dlg = wxMessageDialog:new(Frame, ErrorStr), wxMessageDialog:showModal(Dlg), wxMessageDialog:destroy(Dlg), {noreply, State}; -handle_info(Event, State) -> - io:format("~p:~p, handle info ~p\n", [?MODULE, ?LINE, Event]), +handle_info(_Event, State) -> + %% io:format("~p:~p, handle info ~p\n", [?MODULE, ?LINE, _Event]), {noreply, State}. terminate(_Event, #state{pid=Pid, attrs=Attrs}) -> @@ -588,19 +599,22 @@ search([Str, Row, Dir0, CaseSens], true -> []; false -> [caseless] end, - {ok, Re} = re:compile(Str, Opt), Dir = case Dir0 of true -> 1; false -> -1 end, - Res = search(Row, Dir, Re, Table), + Res = case re:compile(Str, Opt) of + {ok, Re} -> + search(Row, Dir, Re, Table); + {error, _} -> false + end, Parent ! {self(), Res}, S#holder{search=Res}. search(Row, Dir, Re, Table) -> Res = try lists:nth(Row+1, Table) of Term -> - Str = io_lib:format("~w", [Term]), + Str = format(Term), re:run(Str, Re) catch _:_ -> no_more end, @@ -613,9 +627,9 @@ search(Row, Dir, Re, Table) -> get_row(From, Row, Col, Table) -> case lists:nth(Row+1, Table) of [Object|_] when Col =:= all -> - From ! {self(), io_lib:format("~w", [Object])}; + From ! {self(), format(Object)}; [Object|_] when tuple_size(Object) >= Col -> - From ! {self(), io_lib:format("~w", [element(Col, Object)])}; + From ! {self(), format(element(Col, Object))}; _ -> From ! {self(), ""} end. @@ -724,3 +738,58 @@ key_pos(Node, ets, TabId) -> KeyPos = rpc:call(Node, ets, info, [TabId, keypos]), is_integer(KeyPos) orelse throw(node_or_table_down), KeyPos. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +format(Tuple) when is_tuple(Tuple) -> + [${ |format_tuple(Tuple, 1, tuple_size(Tuple))]; +format(List) when is_list(List) -> + format_list(List); +format(Bin) when is_binary(Bin), byte_size(Bin) > 100 -> + io_lib:format("<<#Bin:~w>>", [byte_size(Bin)]); +format(Float) when is_float(Float) -> + io_lib:format("~.3g", [Float]); +format(Term) -> + io_lib:format("~w", [Term]). + +format_tuple(Tuple, I, Max) when I < Max -> + [format(element(I, Tuple)), $,|format_tuple(Tuple, I+1, Max)]; +format_tuple(Tuple, Max, Max) -> + [format(element(Max, Tuple)), $}]; +format_tuple(_Tuple, 1, 0) -> + [$}]. + +format_list([]) -> "[]"; +format_list(List) -> + case printable_list(List) of + true -> io_lib:format("\"~ts\"", [List]); + false -> [$[ | make_list(List)] + end. + +make_list([Last]) -> + [format(Last), $]]; +make_list([Head|Tail]) -> + [format(Head), $,|make_list(Tail)]. + +%% printable_list([Char]) -> bool() +%% Return true if CharList is a list of printable characters, else +%% false. + +printable_list([C|Cs]) when is_integer(C), C >= $ , C =< 255 -> + printable_list(Cs); +printable_list([$\n|Cs]) -> + printable_list(Cs); +printable_list([$\r|Cs]) -> + printable_list(Cs); +printable_list([$\t|Cs]) -> + printable_list(Cs); +printable_list([$\v|Cs]) -> + printable_list(Cs); +printable_list([$\b|Cs]) -> + printable_list(Cs); +printable_list([$\f|Cs]) -> + printable_list(Cs); +printable_list([$\e|Cs]) -> + printable_list(Cs); +printable_list([]) -> true; +printable_list(_Other) -> false. %Everything else is false diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl index ad3e8c14ab..b276965f83 100644 --- a/lib/observer/src/observer_tv_wx.erl +++ b/lib/observer/src/observer_tv_wx.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011. All Rights Reserved. +%% Copyright Ericsson AB 2011-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -313,7 +313,7 @@ display_table_info(Parent0, Node, Source, Table) -> list_to_strings([]) -> "None"; list_to_strings([A]) -> integer_to_list(A); -list_to_strings([A,B]) -> +list_to_strings([A|B]) -> integer_to_list(A) ++ " ," ++ list_to_strings(B). handle_error(Foo) -> diff --git a/lib/observer/test/etop_SUITE.erl b/lib/observer/test/etop_SUITE.erl index a0782ea809..a277453620 100644 --- a/lib/observer/test/etop_SUITE.erl +++ b/lib/observer/test/etop_SUITE.erl @@ -57,11 +57,14 @@ end_per_group(_GroupName, Config) -> Config. -text(suite) -> - []; -text(doc) -> - ["Start etop with text presentation"]; -text(Config) when is_list(Config) -> +%% Start etop with text presentation +text(_) -> + case test_server:is_native(lists) of + true -> {skip,"Native libs -- tracing does not work"}; + false -> text() + end. + +text() -> ?line {ok,Node} = ?t:start_node(node2,peer,[]), %% Must spawn this process, else the test case will never end. diff --git a/lib/observer/vsn.mk b/lib/observer/vsn.mk index 76e2f591fa..fa104ede01 100644 --- a/lib/observer/vsn.mk +++ b/lib/observer/vsn.mk @@ -1 +1 @@ -OBSERVER_VSN = 0.9.10 +OBSERVER_VSN = 1.0 diff --git a/lib/odbc/doc/src/notes.xml b/lib/odbc/doc/src/notes.xml index 9c6ca8a017..08763163b8 100644 --- a/lib/odbc/doc/src/notes.xml +++ b/lib/odbc/doc/src/notes.xml @@ -31,7 +31,43 @@ <p>This document describes the changes made to the odbc application. </p> - <section><title>ODBC 2.10.11</title> + <section><title>ODBC 2.10.12</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + An ODBC process should exit normally if its client exits + with 'shutdown'</p> + <p> + There is nothing strange about the client shutting down, + so the ODBC process should exit normally to avoid + generating a crash report for a non-problem. (Thanks to + Magnus Henoch)</p> + <p> + Own Id: OTP-9716</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + </list> + </section> + +</section> + +<section><title>ODBC 2.10.11</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk index 120ed9ee3d..fb6e208a52 100644 --- a/lib/odbc/vsn.mk +++ b/lib/odbc/vsn.mk @@ -1 +1 @@ -ODBC_VSN = 2.10.11 +ODBC_VSN = 2.10.12 diff --git a/lib/orber/doc/src/notes.xml b/lib/orber/doc/src/notes.xml index c8477d9252..35ee5e35dd 100644 --- a/lib/orber/doc/src/notes.xml +++ b/lib/orber/doc/src/notes.xml @@ -32,7 +32,51 @@ <file>notes.xml</file> </header> - <section><title>Orber 3.6.22</title> + <section><title>Orber 3.6.23</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> Remove usage of ssl:seed/1 in orber test cases. </p> + <p> + Own Id: OTP-9728</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + <item> + <p> The SSL option handling has been changed. There are + now two new orber options <c>ssl_server_options</c> and + <c>ssl_client_options</c> which takes a list of options + to the socket. </p> <p> The old options are now + deprecated and removed from the documentation but they + can still be used for backward compatibility as long as + the two new options not are used. </p> <p> If + <c>ssl_server_options</c> and <c>ssl_client_options</c> + contain an TCP option that <c>orber</c> needs to set to a + specific value it will be skipped and a warning will be + written to the error_log. </p> + <p> + Own Id: OTP-9773 Aux Id: seq11932 </p> + </item> + </list> + </section> + +</section> + +<section><title>Orber 3.6.22</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/orber/src/orber_ifr.erl b/lib/orber/src/orber_ifr.erl index c23374cd68..6799bc1db4 100644 --- a/lib/orber/src/orber_ifr.erl +++ b/lib/orber/src/orber_ifr.erl @@ -478,7 +478,7 @@ get_module(Id, Type) -> What -> orber:dbg("[~p] ~p:get_module(~p, ~p).~n" "Id doesn't exist, mismatch Id vs Type or DB error: ~p", - [?LINE, ?MODULE, Id, What], ?DEBUG_LEVEL), + [?LINE, ?MODULE, Id, Type, What], ?DEBUG_LEVEL), corba:raise(#'MARSHAL'{completion_status=?COMPLETED_MAYBE}) end. diff --git a/lib/orber/src/orber_tb.erl b/lib/orber/src/orber_tb.erl index eee67296d7..d3e3a8497d 100644 --- a/lib/orber/src/orber_tb.erl +++ b/lib/orber/src/orber_tb.erl @@ -209,7 +209,7 @@ check_illegal_tcp_options([binary |T], IllegalOpts) -> check_illegal_tcp_options(T,[binary |IllegalOpts]); check_illegal_tcp_options([{reuseaddr, V} |T], IllegalOpts) -> check_illegal_tcp_options(T,[{reuseaddr, V} |IllegalOpts]); -check_illegal_tcp_options([H|T], IllegalOpts) -> +check_illegal_tcp_options([_H|T], IllegalOpts) -> check_illegal_tcp_options(T, IllegalOpts). %%---------------------------------------------------------------------- diff --git a/lib/orber/test/orber_SUITE.erl b/lib/orber/test/orber_SUITE.erl index be6ffa201c..72b0db1e0d 100644 --- a/lib/orber/test/orber_SUITE.erl +++ b/lib/orber/test/orber_SUITE.erl @@ -20,7 +20,6 @@ -module(orber_SUITE). -include_lib("test_server/include/test_server.hrl"). - -define(default_timeout, ?t:minutes(15)). -define(application, orber). @@ -31,7 +30,11 @@ % Test cases must be exported. -export([app_test/1, undefined_functions/1, install_load_order/1, - install_local_content/1]). + install_local_content/1, + otp_9887/1]). + +%% Exporting error handler callbacks for use in otp_9887 +-export([init/1, handle_event/2]). %% %% all/1 @@ -40,7 +43,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [app_test, undefined_functions, install_load_order, - install_local_content]. + install_local_content, + otp_9887]. groups() -> []. @@ -76,6 +80,27 @@ app_test(_Config) -> ?line ok=?t:app_test(orber), ok. +otp_9887(_Config) -> + orber:jump_stop(), + application:set_env(orber, orber_debug_level, 10), + orber:jump_start([]), + + mnesia:create_table(orber_light_ifr, []), + + error_logger:add_report_handler(?MODULE,[self()]), + catch orber_ifr:get_module(foo, bar), + + receive + {stolen,Reason} -> + {error,_Pid1, {_Pid2, _ErrorString, ArgumentList}} = Reason, + 5 = length(ArgumentList) + after 500 -> + test_server:fail("OTP_9887 TIMED OUT") + end, + + orber:jump_stop(), + ok. + %% Install Orber using the load_order option. install_load_order(suite) -> []; @@ -192,5 +217,10 @@ key1search(Key, L) -> fail(Reason) -> exit({suite_failed, Reason}). +%% Error handler +init([Proc]) -> {ok,Proc}. +handle_event(Event, Proc) -> + Proc ! {stolen,Event}, + {ok,Proc}. diff --git a/lib/orber/test/orber_acl_SUITE.erl b/lib/orber/test/orber_acl_SUITE.erl index b43a00be19..49107cde84 100644 --- a/lib/orber/test/orber_acl_SUITE.erl +++ b/lib/orber/test/orber_acl_SUITE.erl @@ -80,7 +80,7 @@ end_per_group(_GroupName, Config) -> %%----------------------------------------------------------------- init_per_suite(Config) -> if - list(Config) -> + is_list(Config) -> Config; true -> exit("Config not a list") diff --git a/lib/os_mon/c_src/memsup.c b/lib/os_mon/c_src/memsup.c index 241e7718db..b6e417eaa0 100644 --- a/lib/os_mon/c_src/memsup.c +++ b/lib/os_mon/c_src/memsup.c @@ -327,27 +327,27 @@ get_mem_procfs(memory_ext *me){ /* Total and free is NEEDED! */ bp = strstr(buffer, "MemTotal:"); - if (sscanf(bp, "MemTotal: %lu kB\n", &(me->total))) me->flag |= F_MEM_TOTAL; + if (bp != NULL && sscanf(bp, "MemTotal: %lu kB\n", &(me->total))) me->flag |= F_MEM_TOTAL; bp = strstr(buffer, "MemFree:"); - if (sscanf(bp, "MemFree: %lu kB\n", &(me->free))) me->flag |= F_MEM_FREE; + if (bp != NULL && sscanf(bp, "MemFree: %lu kB\n", &(me->free))) me->flag |= F_MEM_FREE; /* Extensions */ bp = strstr(buffer, "Buffers:"); - if (sscanf(bp, "Buffers: %lu kB\n", &(me->buffered))) me->flag |= F_MEM_BUFFERS; + if (bp != NULL && sscanf(bp, "Buffers: %lu kB\n", &(me->buffered))) me->flag |= F_MEM_BUFFERS; bp = strstr(buffer, "Cached:"); - if (sscanf(bp, "Cached: %lu kB\n", &(me->cached))) me->flag |= F_MEM_CACHED; + if (bp != NULL && sscanf(bp, "Cached: %lu kB\n", &(me->cached))) me->flag |= F_MEM_CACHED; /* Swap */ bp = strstr(buffer, "SwapTotal:"); - if (sscanf(bp, "SwapTotal: %lu kB\n", &(me->total_swap))) me->flag |= F_SWAP_TOTAL; + if (bp != NULL && sscanf(bp, "SwapTotal: %lu kB\n", &(me->total_swap))) me->flag |= F_SWAP_TOTAL; bp = strstr(buffer, "SwapFree:"); - if (sscanf(bp, "SwapFree: %lu kB\n", &(me->free_swap))) me->flag |= F_SWAP_FREE; + if (bp != NULL && sscanf(bp, "SwapFree: %lu kB\n", &(me->free_swap))) me->flag |= F_SWAP_FREE; me->pagesize = 1024; /* procfs defines its size in kB */ diff --git a/lib/os_mon/doc/src/notes.xml b/lib/os_mon/doc/src/notes.xml index f641bbd828..b459e31fa5 100644 --- a/lib/os_mon/doc/src/notes.xml +++ b/lib/os_mon/doc/src/notes.xml @@ -30,6 +30,35 @@ </header> <p>This document describes the changes made to the OS_Mon application.</p> +<section><title>Os_Mon 2.2.8</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + <item> + <p> + Tuple funs (a two-element tuple with a module name and a + function) are now officially deprecated and will be + removed in R16. Use '<c>fun M:F/A</c>' instead. To make + you aware that your system uses tuple funs, the very + first time a tuple fun is applied, a warning will be sent + to the error logger.</p> + <p> + Own Id: OTP-9649</p> + </item> + </list> + </section> + +</section> + <section><title>Os_Mon 2.2.7</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/os_mon/src/cpu_sup.erl b/lib/os_mon/src/cpu_sup.erl index e414e2c10b..34251178ee 100644 --- a/lib/os_mon/src/cpu_sup.erl +++ b/lib/os_mon/src/cpu_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -764,8 +764,7 @@ port_receive_cpu_util_entries(_, _, Data) -> exit({data_mismatch, Data}). start_portprogram() -> - Command = filename:join([code:priv_dir(os_mon), "bin", "cpu_sup"]), - Port = open_port({spawn, Command}, [stream]), + Port = os_mon:open_port("cpu_sup", [stream]), port_command(Port, ?ping), 4711 = port_receive_uint32(Port, 5000), Port. diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl index ba07a529bc..49533da1f7 100644 --- a/lib/os_mon/src/memsup.erl +++ b/lib/os_mon/src/memsup.erl @@ -802,8 +802,7 @@ port_init() -> port_idle(Port). start_portprogram() -> - Command = filename:join([code:priv_dir(os_mon), "bin", "memsup"]), - open_port({spawn, Command}, [{packet, 1}]). + os_mon:open_port("memsup",[{packet,1}]). %% The connected process loops are a bit awkward (several different %% functions doing almost the same thing) as diff --git a/lib/os_mon/src/os_mon.erl b/lib/os_mon/src/os_mon.erl index ef368571db..3098c38808 100644 --- a/lib/os_mon/src/os_mon.erl +++ b/lib/os_mon/src/os_mon.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -22,7 +22,7 @@ -behaviour(supervisor). %% API --export([call/2, call/3, get_env/2]). +-export([call/2, call/3, get_env/2, open_port/2]). %% Application callbacks -export([start/2, stop/1]). @@ -79,6 +79,22 @@ get_env(Service, Param) -> Service:param_default(Param) end. +open_port(Name, Opts) -> + PrivDir = code:priv_dir(os_mon), + ReleasedPath = filename:join([PrivDir,"bin",Name]), + %% Check os_mon*/priv/bin/Name + case filelib:is_regular(ReleasedPath) of + true -> + erlang:open_port({spawn, ReleasedPath}, Opts); + false -> + %% Use os_mon*/priv/bin/Arch/Name + ArchPath = + filename:join( + [PrivDir,"bin",erlang:system_info(system_architecture),Name]), + erlang:open_port({spawn, ArchPath}, Opts) + end. + + %%%----------------------------------------------------------------- %%% Application callbacks %%%----------------------------------------------------------------- diff --git a/lib/os_mon/src/os_mon_sysinfo.erl b/lib/os_mon/src/os_mon_sysinfo.erl index 5d12bd95d1..080885d5d6 100644 --- a/lib/os_mon/src/os_mon_sysinfo.erl +++ b/lib/os_mon/src/os_mon_sysinfo.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -108,9 +108,7 @@ code_change(_OldVsn, State, _Extra) -> %%---------------------------------------------------------------------- start_portprogram() -> - Command = - filename:join([code:priv_dir(os_mon),"bin","win32sysinfo.exe"]), - Port = open_port({spawn,Command}, [{packet,1}]), + Port = os_mon:open_port("win32sysinfo.exe", [{packet,1}]), receive {Port, {data, [?OK]}} -> Port; diff --git a/lib/os_mon/vsn.mk b/lib/os_mon/vsn.mk index f000e24a8f..89dfa59dd9 100644 --- a/lib/os_mon/vsn.mk +++ b/lib/os_mon/vsn.mk @@ -1 +1 @@ -OS_MON_VSN = 2.2.7 +OS_MON_VSN = 2.2.8 diff --git a/lib/otp_mibs/doc/src/notes.xml b/lib/otp_mibs/doc/src/notes.xml index 94c1dd4228..71e33fceb9 100644 --- a/lib/otp_mibs/doc/src/notes.xml +++ b/lib/otp_mibs/doc/src/notes.xml @@ -31,6 +31,26 @@ <p>This document describes the changes made to the OTP_Mibs application.</p> +<section><title>Otp_Mibs 1.0.7</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Tuple funs (a two-element tuple with a module name and a + function) are now officially deprecated and will be + removed in R16. Use '<c>fun M:F/A</c>' instead. To make + you aware that your system uses tuple funs, the very + first time a tuple fun is applied, a warning will be sent + to the error logger.</p> + <p> + Own Id: OTP-9649</p> + </item> + </list> + </section> + +</section> + <section><title>Otp_Mibs 1.0.6</title> <section><title>Improvements and New Features</title> diff --git a/lib/otp_mibs/vsn.mk b/lib/otp_mibs/vsn.mk index c2fa7c9474..f070288032 100644 --- a/lib/otp_mibs/vsn.mk +++ b/lib/otp_mibs/vsn.mk @@ -1,4 +1,4 @@ -OTP_MIBS_VSN = 1.0.6 +OTP_MIBS_VSN = 1.0.7 # Note: The branch 'otp_mibs' is defunct as of otp_mibs-1.0.4 and # should NOT be used again. diff --git a/lib/parsetools/doc/src/notes.xml b/lib/parsetools/doc/src/notes.xml index cbeb89aa16..ac29cbb893 100644 --- a/lib/parsetools/doc/src/notes.xml +++ b/lib/parsetools/doc/src/notes.xml @@ -30,6 +30,26 @@ </header> <p>This document describes the changes made to the Parsetools application.</p> +<section><title>Parsetools 2.0.7</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Tuple funs (a two-element tuple with a module name and a + function) are now officially deprecated and will be + removed in R16. Use '<c>fun M:F/A</c>' instead. To make + you aware that your system uses tuple funs, the very + first time a tuple fun is applied, a warning will be sent + to the error logger.</p> + <p> + Own Id: OTP-9649</p> + </item> + </list> + </section> + +</section> + <section><title>Parsetools 2.0.6</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk index 093523f0e7..e2594564cb 100644 --- a/lib/parsetools/vsn.mk +++ b/lib/parsetools/vsn.mk @@ -1 +1 @@ -PARSETOOLS_VSN = 2.0.6 +PARSETOOLS_VSN = 2.0.7 diff --git a/lib/percept/doc/src/notes.xml b/lib/percept/doc/src/notes.xml index 95c2bbda56..1ac1a5ab62 100644 --- a/lib/percept/doc/src/notes.xml +++ b/lib/percept/doc/src/notes.xml @@ -32,6 +32,21 @@ </header> <p>This document describes the changes made to the Percept application.</p> +<section><title>Percept 0.8.6.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Miscellaneous documentation build updates</p> + <p> + Own Id: OTP-9813</p> + </item> + </list> + </section> + +</section> + <section><title>Percept 0.8.6</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/percept/vsn.mk b/lib/percept/vsn.mk index 3b4d9bbb64..9267a41055 100644 --- a/lib/percept/vsn.mk +++ b/lib/percept/vsn.mk @@ -1 +1 @@ -PERCEPT_VSN = 0.8.6 +PERCEPT_VSN = 0.8.6.1 diff --git a/lib/pman/doc/src/notes.xml b/lib/pman/doc/src/notes.xml index 27e3b5e5fe..407a10a50a 100644 --- a/lib/pman/doc/src/notes.xml +++ b/lib/pman/doc/src/notes.xml @@ -30,6 +30,21 @@ </header> <p>This document describes the changes made to the Pman application.</p> +<section><title>Pman 2.7.1.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Miscellaneous documentation build updates</p> + <p> + Own Id: OTP-9813</p> + </item> + </list> + </section> + +</section> + <section><title>Pman 2.7.1</title> <section><title>Improvements and New Features</title> diff --git a/lib/pman/doc/src/pman.xml b/lib/pman/doc/src/pman.xml index 84d5a5772a..5f95aecc04 100644 --- a/lib/pman/doc/src/pman.xml +++ b/lib/pman/doc/src/pman.xml @@ -32,6 +32,12 @@ <module>pman</module> <modulesummary>A graphical process manager.</modulesummary> <description> + <warning> + <p> + The Pman application has been superseded by the Observer application. + Pman will be removed in R16. + </p> + </warning> <p>A graphical tool used to inspect the Erlang processes executing either locally or on remote nodes. It is also possible to trace events in the individual processes.</p> diff --git a/lib/pman/doc/src/pman_chapter.xml b/lib/pman/doc/src/pman_chapter.xml index 141b488415..8668628bfa 100644 --- a/lib/pman/doc/src/pman_chapter.xml +++ b/lib/pman/doc/src/pman_chapter.xml @@ -32,6 +32,12 @@ <section> <title>Introduction</title> + <warning> + <p> + The Pman application has been superseded by the Observer application. + Pman will be removed in R16. + </p> + </warning> <p>The process manager Pman is a tool for viewing processes executing locally or on remote nodes. Its main purpose is to locate erroneous code by inspecting the state of the processes and by tracing diff --git a/lib/pman/src/pman_buf_converter.erl b/lib/pman/src/pman_buf_converter.erl index b6f560411c..c6cd8ec9ee 100644 --- a/lib/pman/src/pman_buf_converter.erl +++ b/lib/pman/src/pman_buf_converter.erl @@ -29,6 +29,7 @@ %%---------------------------------------------------------------------- -module(pman_buf_converter). +-compile([{nowarn_deprecated_function,{gs,start,0}}]). %%-compile(export_all). -export([init/2]). diff --git a/lib/pman/src/pman_buf_printer.erl b/lib/pman/src/pman_buf_printer.erl index 74e935171a..62407648d5 100644 --- a/lib/pman/src/pman_buf_printer.erl +++ b/lib/pman/src/pman_buf_printer.erl @@ -18,6 +18,8 @@ %% -module(pman_buf_printer). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,start,0}}]). %%-compile(export_all). -export([init/2]). diff --git a/lib/pman/src/pman_main.erl b/lib/pman/src/pman_main.erl index b68da1d2c3..adb5b65cd4 100644 --- a/lib/pman/src/pman_main.erl +++ b/lib/pman/src/pman_main.erl @@ -17,6 +17,8 @@ %% %CopyrightEnd% %% -module(pman_main). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,read,2}}]). %% Main process and window diff --git a/lib/pman/src/pman_module_info.erl b/lib/pman/src/pman_module_info.erl index cfd711a6e1..58f956aa42 100644 --- a/lib/pman/src/pman_module_info.erl +++ b/lib/pman/src/pman_module_info.erl @@ -17,6 +17,8 @@ %% %CopyrightEnd% %% -module(pman_module_info). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,start,1}}]). %% Window with module information (View->Module Info...) diff --git a/lib/pman/src/pman_shell.erl b/lib/pman/src/pman_shell.erl index 0b13890460..393ef5f84d 100644 --- a/lib/pman/src/pman_shell.erl +++ b/lib/pman/src/pman_shell.erl @@ -25,6 +25,10 @@ %% --------------------------------------------------------------- -module(pman_shell). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,start,1}}]). %% --------------------------------------------------------------- %% The user interface exports diff --git a/lib/pman/src/pman_tool.erl b/lib/pman/src/pman_tool.erl index 1d33fb9764..c548e17d00 100644 --- a/lib/pman/src/pman_tool.erl +++ b/lib/pman/src/pman_tool.erl @@ -17,6 +17,7 @@ %% %CopyrightEnd% %% -module(pman_tool). +-compile([{nowarn_deprecated_function,{gs,read,2}}]). %% Listbox selection window diff --git a/lib/pman/src/pman_win.erl b/lib/pman/src/pman_win.erl index 52d5a237cf..9dd446cd81 100644 --- a/lib/pman/src/pman_win.erl +++ b/lib/pman/src/pman_win.erl @@ -21,6 +21,16 @@ %% ------------------------------------------------------------ -module(pman_win). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,canvas,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,create,4}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,1}}, + {nowarn_deprecated_function,{gs,text,2}}, + {nowarn_deprecated_function,{gs,window,2}}]). %% --------------------------------------------------------------- %% The user interface exports diff --git a/lib/pman/vsn.mk b/lib/pman/vsn.mk index d190164053..a62a9d7c89 100644 --- a/lib/pman/vsn.mk +++ b/lib/pman/vsn.mk @@ -1 +1 @@ -PMAN_VSN = 2.7.1 +PMAN_VSN = 2.7.1.1 diff --git a/lib/public_key/.gitignore b/lib/public_key/.gitignore index db24906676..d30fe62c9d 100644 --- a/lib/public_key/.gitignore +++ b/lib/public_key/.gitignore @@ -1,7 +1,7 @@ # public_key -/lib/public_key/asn1/*.asn1db -/lib/public_key/asn1/*.erl -/lib/public_key/asn1/*.hrl -/lib/public_key/include/OTP-PUB-KEY.hrl -/lib/public_key/include/PKCS-FRAME.hrl +asn1/*.asn1db +asn1/*.erl +asn1/*.hrl +include/OTP-PUB-KEY.hrl +include/PKCS-FRAME.hrl diff --git a/lib/public_key/doc/src/notes.xml b/lib/public_key/doc/src/notes.xml index efd4a37eb9..c9a5561e3f 100644 --- a/lib/public_key/doc/src/notes.xml +++ b/lib/public_key/doc/src/notes.xml @@ -34,6 +34,28 @@ <file>notes.xml</file> </header> +<section><title>Public_Key 0.14</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + public_key, ssl and crypto now supports PKCS-8</p> + <p> + Own Id: OTP-9312</p> + </item> + <item> + <p> + The asn1 decoder/encoder now uses a runtime nif from the + asn1 application if it is available.</p> + <p> + Own Id: OTP-9414</p> + </item> + </list> + </section> + +</section> + <section><title>Public_Key 0.13</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml index 821e7a2300..0b6673e826 100644 --- a/lib/public_key/doc/src/public_key.xml +++ b/lib/public_key/doc/src/public_key.xml @@ -453,7 +453,7 @@ <desc> <p>Encodes a list of ssh file entries (public keys and attributes) to a binary. Possible attributes depends on the file type, see <seealso - marker="ssh_decode"> ssh_decode/2 </seealso></p> + marker="#ssh_decode-2"> ssh_decode/2 </seealso></p> </desc> </func> diff --git a/lib/public_key/src/pubkey_ssh.erl b/lib/public_key/src/pubkey_ssh.erl index f342eab159..f0c94e29a5 100644 --- a/lib/public_key/src/pubkey_ssh.erl +++ b/lib/public_key/src/pubkey_ssh.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2011-2011. All Rights Reserved. +%% Copyright Ericsson AB 2011-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -146,16 +146,7 @@ do_openssh_decode(auth_keys = FileType, [Line | Lines], Acc) -> Split = binary:split(Line, <<" ">>, [global]), case mend_split(Split, []) of %% ssh2 - [Options, KeyType, Base64Enc, Comment] when KeyType == <<"ssh-rsa">>; - KeyType == <<"ssh-dss">> -> - do_openssh_decode(FileType, Lines, - [{openssh_pubkey_decode(KeyType, Base64Enc), - [{comment, string_decode(Comment)}, - {options, comma_list_decode(Options)}]} - | Acc]); - - [KeyType, Base64Enc, Comment] when KeyType == <<"ssh-rsa">>; - KeyType == <<"ssh-dss">> -> + [KeyType, Base64Enc, Comment] -> do_openssh_decode(FileType, Lines, [{openssh_pubkey_decode(KeyType, Base64Enc), [{comment, string_decode(Comment)}]} | Acc]); @@ -166,44 +157,32 @@ do_openssh_decode(auth_keys = FileType, [Line | Lines], Acc) -> [{comment, string_decode(Comment)}, {options, comma_list_decode(Options)}, {bits, integer_decode(Bits)}]} | Acc]); - [Bits, Exponent, Modulus, Comment] -> - do_openssh_decode(FileType, Lines, - [{ssh1_rsa_pubkey_decode(Modulus, Exponent), - [{comment, string_decode(Comment)}, - {bits, integer_decode(Bits)}]} | Acc]) - end; + [A, B, C, D] -> + ssh_2_or_1(FileType, Lines, Acc, A,B,C,D) + end; do_openssh_decode(known_hosts = FileType, [Line | Lines], Acc) -> - case binary:split(Line, <<" ">>, [global]) of + Split = binary:split(Line, <<" ">>, [global]), + case mend_split(Split, []) of %% ssh 2 - [HostNames, KeyType, Base64Enc] when KeyType == <<"ssh-rsa">>; - KeyType == <<"ssh-dss">> -> + [HostNames, KeyType, Base64Enc] -> do_openssh_decode(FileType, Lines, [{openssh_pubkey_decode(KeyType, Base64Enc), [{hostnames, comma_list_decode(HostNames)}]}| Acc]); - [HostNames, KeyType, Base64Enc, Comment] when KeyType == <<"ssh-rsa">>; - KeyType == <<"ssh-dss">> -> - do_openssh_decode(FileType, Lines, - [{openssh_pubkey_decode(KeyType, Base64Enc), - [{comment, string_decode(Comment)}, - {hostnames, comma_list_decode(HostNames)}]} | Acc]); + [A, B, C, D] -> + ssh_2_or_1(FileType, Lines, Acc, A, B, C, D); %% ssh 1 [HostNames, Bits, Exponent, Modulus, Comment] -> do_openssh_decode(FileType, Lines, [{ssh1_rsa_pubkey_decode(Modulus, Exponent), [{comment, string_decode(Comment)}, {hostnames, comma_list_decode(HostNames)}, - {bits, integer_decode(Bits)}]} | Acc]); - [HostNames, Bits, Exponent, Modulus] -> - do_openssh_decode(FileType, Lines, - [{ssh1_rsa_pubkey_decode(Modulus, Exponent), - [{comment, []}, - {hostnames, comma_list_decode(HostNames)}, {bits, integer_decode(Bits)}]} | Acc]) end; do_openssh_decode(openssh_public_key = FileType, [Line | Lines], Acc) -> - case binary:split(Line, <<" ">>, [global]) of + Split = binary:split(Line, <<" ">>, [global]), + case mend_split(Split, []) of [KeyType, Base64Enc, Comment0] when KeyType == <<"ssh-rsa">>; KeyType == <<"ssh-dss">> -> Comment = string:strip(binary_to_list(Comment0), right, $\n), @@ -212,6 +191,46 @@ do_openssh_decode(openssh_public_key = FileType, [Line | Lines], Acc) -> [{comment, Comment}]} | Acc]) end. +ssh_2_or_1(known_hosts = FileType, Lines, Acc, A, B, C, D) -> + try integer_decode(B) of + Int -> + file_type_decode_ssh1(FileType, Lines, Acc, A, Int, C,D) + catch + error:badarg -> + file_type_decode_ssh2(FileType, Lines, Acc, A,B,C,D) + end; +ssh_2_or_1(auth_keys = FileType, Lines, Acc, A, B, C, D) -> + try integer_decode(A) of + Int -> + file_type_decode_ssh1(FileType, Lines, Acc, Int, B, C,D) + catch + error:badarg -> + file_type_decode_ssh2(FileType, Lines, Acc, A,B,C,D) + end. + +file_type_decode_ssh1(known_hosts = FileType, Lines, Acc, HostNames, Bits, Exponent, Modulus) -> + do_openssh_decode(FileType, Lines, + [{ssh1_rsa_pubkey_decode(Modulus, Exponent), + [{comment, []}, + {hostnames, comma_list_decode(HostNames)}, + {bits, Bits}]} | Acc]); +file_type_decode_ssh1(auth_keys = FileType, Lines, Acc, Bits, Exponent, Modulus, Comment) -> + do_openssh_decode(FileType, Lines, + [{ssh1_rsa_pubkey_decode(Modulus, Exponent), + [{comment, string_decode(Comment)}, + {bits, Bits}]} | Acc]). + +file_type_decode_ssh2(known_hosts = FileType, Lines, Acc, HostNames, KeyType, Base64Enc, Comment) -> + do_openssh_decode(FileType, Lines, + [{openssh_pubkey_decode(KeyType, Base64Enc), + [{comment, string_decode(Comment)}, + {hostnames, comma_list_decode(HostNames)}]} | Acc]); +file_type_decode_ssh2(auth_keys = FileType, Lines, Acc, Options, KeyType, Base64Enc, Comment) -> + do_openssh_decode(FileType, Lines, + [{openssh_pubkey_decode(KeyType, Base64Enc), + [{comment, string_decode(Comment)}, + {options, comma_list_decode(Options)}]} + | Acc]). openssh_pubkey_decode(<<"ssh-rsa">>, Base64Enc) -> <<?UINT32(StrLen), _:StrLen/binary, @@ -231,7 +250,9 @@ openssh_pubkey_decode(<<"ssh-dss">>, Base64Enc) -> {erlint(SizeY, Y), #'Dss-Parms'{p = erlint(SizeP, P), q = erlint(SizeQ, Q), - g = erlint(SizeG, G)}}. + g = erlint(SizeG, G)}}; +openssh_pubkey_decode(KeyType, Base64Enc) -> + {KeyType, base64:mime_decode(Base64Enc)}. erlint(MPIntSize, MPIntValue) -> Bits= MPIntSize * 8, @@ -412,6 +433,12 @@ is_key_field(<<"ssh-dss">>) -> true; is_key_field(<<"ssh-rsa">>) -> true; +is_key_field(<<"ecdsa-sha2-nistp256">>) -> + true; +is_key_field(<<"ecdsa-sha2-nistp384">>) -> + true; +is_key_field(<<"ecdsa-sha2-nistp521">>) -> + true; is_key_field(_) -> false. diff --git a/lib/reltool/doc/src/notes.xml b/lib/reltool/doc/src/notes.xml index 5304b996a4..cf2cf7f7bc 100644 --- a/lib/reltool/doc/src/notes.xml +++ b/lib/reltool/doc/src/notes.xml @@ -37,7 +37,23 @@ thus constitutes one section in this document. The title of each section is the version number of Reltool.</p> - <section><title>Reltool 0.5.7</title> + <section><title>Reltool 0.5.7.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Added recommendation about <c>RootDir</c> parameter to + <c>reltool:eval_target_spec/3</c>.</p> + <p> + Own Id: OTP-9742</p> + </item> + </list> + </section> + +</section> + +<section><title>Reltool 0.5.7</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/reltool/vsn.mk b/lib/reltool/vsn.mk index 751f9bb6db..3869284ee7 100644 --- a/lib/reltool/vsn.mk +++ b/lib/reltool/vsn.mk @@ -1 +1 @@ -RELTOOL_VSN = 0.5.7 +RELTOOL_VSN = 0.5.7.1 diff --git a/lib/runtime_tools/c_src/trace_ip_drv.c b/lib/runtime_tools/c_src/trace_ip_drv.c index 5396b8afa9..7ae6c1b329 100644 --- a/lib/runtime_tools/c_src/trace_ip_drv.c +++ b/lib/runtime_tools/c_src/trace_ip_drv.c @@ -212,11 +212,11 @@ static TraceIpData *lookup_data_by_port(int portno); static int set_nonblocking(SOCKET sock); static TraceIpMessage *make_buffer(int datasiz, unsigned char op, unsigned number); -static void enque_message(TraceIpData *data, unsigned char *buff, int bufflen, +static void enque_message(TraceIpData *data, char *buff, int bufflen, int byteswritten); static void clean_que(TraceIpData *data); static void close_client(TraceIpData *data); -static int trywrite(TraceIpData *data, unsigned char *buff, int bufflen); +static int trywrite(TraceIpData *data, char *buff, int bufflen); static SOCKET my_accept(SOCKET sock); static void close_unlink_port(TraceIpData *data); enum MySelectOp { SELECT_ON, SELECT_OFF, SELECT_CLOSE }; @@ -518,7 +518,7 @@ static void trace_ip_ready_output(ErlDrvData handle, ErlDrvEvent fd) tim = data->que[data->questart]; towrite = tim->siz - tim->written; while((res = write_until_done(data->fd, - tim->bin + tim->written, towrite)) + (char *)tim->bin + tim->written, towrite)) == towrite) { driver_free(tim); data->que[data->questart] = NULL; @@ -561,7 +561,7 @@ static ErlDrvSSizeT trace_ip_control(ErlDrvData handle, TraceIpData *data = (TraceIpData *) handle; ErlDrvBinary *b = my_alloc_binary(3); b->orig_bytes[0] = '\0'; /* OK */ - put_be16(data->listen_portno, &(b->orig_bytes[1])); + put_be16(data->listen_portno, (unsigned char *)&(b->orig_bytes[1])); *res = void_ptr = b; return 0; } @@ -696,7 +696,7 @@ static TraceIpMessage *make_buffer(int datasiz, unsigned char op, ** Add message to que, discarding in a politically correct way... ** The FLAG_DROP_OLDEST is currently ingored... */ -static void enque_message(TraceIpData *data, unsigned char *buff, int bufflen, +static void enque_message(TraceIpData *data, char *buff, int bufflen, int byteswritten) { int diff = data->questop - data->questart; @@ -763,13 +763,13 @@ static void close_client(TraceIpData *data) ** Try to write a message from erlang directly (only called when que is empty ** and client is connected) */ -static int trywrite(TraceIpData *data, unsigned char *buff, int bufflen) +static int trywrite(TraceIpData *data, char *buff, int bufflen) { - unsigned char op[5]; + char op[5]; int res; op[0] = OP_BINARY; - put_be32(bufflen, op + 1); + put_be32(bufflen, (unsigned char *)op + 1); if ((res = write_until_done(data->fd, op, 5)) < 0) { close_client(data); @@ -793,7 +793,11 @@ static int trywrite(TraceIpData *data, unsigned char *buff, int bufflen) static SOCKET my_accept(SOCKET sock) { struct sockaddr_in sin; - int sin_size = sizeof(sin); +#ifdef HAVE_SOCKLEN_T + socklen_t sin_size = sizeof(sin); +#else + int sin_size = (int) sizeof(sin); +#endif return accept(sock, (struct sockaddr *) &sin, &sin_size); } diff --git a/lib/runtime_tools/doc/src/notes.xml b/lib/runtime_tools/doc/src/notes.xml index 0bb76e1ea4..ccf11bf0fe 100644 --- a/lib/runtime_tools/doc/src/notes.xml +++ b/lib/runtime_tools/doc/src/notes.xml @@ -31,6 +31,56 @@ <p>This document describes the changes made to the Runtime_Tools application.</p> +<section><title>Runtime_Tools 1.8.7</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Earlier dbg:stop only did erlang:trace_delivered and did + not flush the trace file driver. Therefore there could + still be trace messages that were delivered to the driver + (guaranteed by erlang:trace_delivered) but not yet + written to the file when dbg:stop returned. Flushing is + now added on each node before the dbg process terminates.</p> + <p> + Own Id: OTP-9651</p> + </item> + <item> + <p> + File handles created by the trace_file_drv driver was + inherited to child processes. This is now corrected.</p> + <p> + Own Id: OTP-9658</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + <item> + <p> + Two new built-in trace pattern aliases have been added: + caller_trace (c) and caller_exception_trace (cx). See the + dbg:ltp/0 documentation for more info.</p> + <p> + Own Id: OTP-9458</p> + </item> + </list> + </section> + +</section> + <section><title>Runtime_Tools 1.8.6</title> <section><title>Improvements and New Features</title> diff --git a/lib/runtime_tools/test/inviso_SUITE.erl b/lib/runtime_tools/test/inviso_SUITE.erl index 758867cf45..33626ffd9e 100644 --- a/lib/runtime_tools/test/inviso_SUITE.erl +++ b/lib/runtime_tools/test/inviso_SUITE.erl @@ -66,13 +66,18 @@ end_per_group(_GroupName, Config) -> init_per_suite(Config) -> - %% No never know who skrewed up this node before this suite! :-) - erlang:trace_pattern({'_','_','_'},[],[local]), - erlang:trace_pattern({'_','_','_'},[],[global]), - erlang:trace(all,false,[all]), + case test_server:is_native(lists) of + true -> + {skip,"Native libs -- tracing doesn't work"}; + false -> + %% We never know who messed up this node before this suite! :-) + erlang:trace_pattern({'_','_','_'},[],[local]), + erlang:trace_pattern({'_','_','_'},[],[global]), + erlang:trace(all,false,[all]), - ?l ok=application:start(runtime_tools), - Config. + ok=application:start(runtime_tools), + Config + end. end_per_suite(_Config) -> ?l ok=application:stop(runtime_tools). diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk index 0bcd261861..3fbc1b3379 100644 --- a/lib/runtime_tools/vsn.mk +++ b/lib/runtime_tools/vsn.mk @@ -1 +1 @@ -RUNTIME_TOOLS_VSN = 1.8.6 +RUNTIME_TOOLS_VSN = 1.8.7 diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml index 195f9fe1d3..770b7c2492 100644 --- a/lib/sasl/doc/src/appup.xml +++ b/lib/sasl/doc/src/appup.xml @@ -332,7 +332,7 @@ restart_new_emulator <p>An info report will be written when the upgrade is completed. To programatically find out if the upgrade is complete, - call <seealso marker="release_handler#which_release/0"> + call <seealso marker="release_handler#which_releases/0"> release_handler:which_releases</seealso> and check if the expected release has status <c>current</c>.</p> <p>The new release must still be made permanent after the upgrade diff --git a/lib/sasl/doc/src/notes.xml b/lib/sasl/doc/src/notes.xml index 01cdc4b29e..2f22a8ec43 100644 --- a/lib/sasl/doc/src/notes.xml +++ b/lib/sasl/doc/src/notes.xml @@ -30,6 +30,71 @@ </header> <p>This document describes the changes made to the SASL application.</p> +<section><title>SASL 2.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix the mechanism for upgrading emulator.</p> + <p> + The appup files for kernel, stdlib and sasl do now + recognize two major releases back and include a + 'restart_new_emulator' instruction. </p> + <p> + Appup files can include regular expressions for matching + earlier releases.</p> + <p> + The mechanism for upgrading the emulator is changed so + 'restart_new_emulator' will be the first instruction + executed. The rest of the upgrade instruction will be + executed after the emulator restart.</p> + <p> + A new upgrade instruction 'restart_emulator' is added for + the case where the emulator shall be restarted after all + other upgrade instructions.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9438</p> + </item> + <item> + <p> + Add release_handler:which_releases/1</p> + <p> + This is an extension to which_releases that allows a user + to specify the status of the releases they wish to be + returned. For instance it allows for quickly determining + which release is 'permanent' without the need of parsing + the entire release list. (Thanks to Joe Williams)</p> + <p> + Own Id: OTP-9717</p> + </item> + <item> + <p> + Add copy of rel file in releases/Vsn in release tar file</p> + <p> + systool:make_tar stores the rel file in the releases + directory. When unpacking with + release_handler:unpack_release, the file is automatically + moved to releases/Vsn/. If, however, the tar file is + unpacked manually, the rel file might not be moved, and + the next release unpacked might overwrite the rel file. + To overcome this, systools:make_tar now stores a copy of + the rel file in releases/Vsn/ directly and it is not + longer necessary to move the file after unpacking.</p> + <p> + The reason for keeping the file in the releases directory + also is that is needs to be extracted separately before + the release version (Vsn) is known.</p> + <p> + Own Id: OTP-9746</p> + </item> + </list> + </section> + +</section> + <section><title>SASL 2.1.10</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml index 32c2149a8d..84fed0a25f 100644 --- a/lib/sasl/doc/src/systools.xml +++ b/lib/sasl/doc/src/systools.xml @@ -196,6 +196,10 @@ <p>The applications are sorted according to the dependencies between the applications. Where there are no dependencies, the order in the <c>.rel</c> file is kept.</p> + <p>The function will fail if the mandatory + applications <c>kernel</c> and <c>stdlib</c> are not + included in the <c>.rel</c> file and have start + type <c>permanent</c> (default).</p> <p>If <c>sasl</c> is not included as an application in the <c>.rel</c> file, a warning is emitted because such a release can not be used in an upgrade. To turn off this diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl index 522c7b496b..8d2b9c35d3 100644 --- a/lib/sasl/src/release_handler.erl +++ b/lib/sasl/src/release_handler.erl @@ -1572,7 +1572,7 @@ memlib(_Lib, []) -> false. %% recursively remove file or directory remove_file(File) -> - case file:read_file_info(File) of + case file:read_link_info(File) of {ok, Info} when Info#file_info.type==directory -> case file:list_dir(File) of {ok, Files} -> diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl index 8fd90c50f9..12ba2a5476 100644 --- a/lib/sasl/src/systools_make.erl +++ b/lib/sasl/src/systools_make.erl @@ -463,30 +463,35 @@ check_appl(Appl) -> end, Appl) of [] -> - {ok,Ws} = mandatory_applications(Appl), - {split_app_incl(Appl),Ws}; + {ApplsNoIncls,Incls} = split_app_incl(Appl), + {ok,Ws} = mandatory_applications(ApplsNoIncls,undefined, + undefined,undefined), + {{ApplsNoIncls,Incls},Ws}; Illegal -> throw({error, {illegal_applications,Illegal}}) end. -mandatory_applications(Appl) -> - AppNames = map(fun(AppT) -> element(1, AppT) end, - Appl), - Mand = mandatory_applications(), - case filter(fun(X) -> member(X, AppNames) end, Mand) of - Mand -> - case member(sasl,AppNames) of - true -> - {ok,[]}; - _ -> - {ok, [{warning,missing_sasl}]} - end; - _ -> - throw({error, {missing_mandatory_app, Mand}}) - end. - -mandatory_applications() -> - [kernel, stdlib]. +mandatory_applications([{kernel,_,Type}|Apps],undefined,Stdlib,Sasl) -> + mandatory_applications(Apps,Type,Stdlib,Sasl); +mandatory_applications([{stdlib,_,Type}|Apps],Kernel,undefined,Sasl) -> + mandatory_applications(Apps,Kernel,Type,Sasl); +mandatory_applications([{sasl,_,Type}|Apps],Kernel,Stdlib,undefined) -> + mandatory_applications(Apps,Kernel,Stdlib,Type); +mandatory_applications([_|Apps],Kernel,Stdlib,Sasl) -> + mandatory_applications(Apps,Kernel,Stdlib,Sasl); +mandatory_applications([],Type,_,_) when Type=/=permanent -> + error_mandatory_application(kernel,Type); +mandatory_applications([],_,Type,_) when Type=/=permanent -> + error_mandatory_application(sasl,Type); +mandatory_applications([],_,_,undefined) -> + {ok, [{warning,missing_sasl}]}; +mandatory_applications([],_,_,_) -> + {ok,[]}. + +error_mandatory_application(App,undefined) -> + throw({error, {missing_mandatory_app, App}}); +error_mandatory_application(App,Type) -> + throw({error, {mandatory_app, App, Type}}). split_app_incl(Appl) -> split_app_incl(Appl, [], []). @@ -1677,6 +1682,7 @@ add_system_files(Tar, RelName, Release, Path1) -> false -> ignore; Relup -> + check_relup(Relup), add_to_tar(Tar, Relup, filename:join(RelVsnDir, "relup")) end, @@ -1684,6 +1690,7 @@ add_system_files(Tar, RelName, Release, Path1) -> false -> ignore; Sys -> + check_sys_config(Sys), add_to_tar(Tar, Sys, filename:join(RelVsnDir, "sys.config")) end, @@ -1700,6 +1707,44 @@ lookup_file(Name, [Dir|Path]) -> lookup_file(_Name, []) -> false. +%% Check that relup can be parsed and has expected format +check_relup(File) -> + case file:consult(File) of + {ok,[{Vsn,UpFrom,DownTo}]} when is_list(Vsn), is_integer(hd(Vsn)), + is_list(UpFrom), is_list(DownTo) -> + ok; + {ok,_} -> + throw({error,{tar_error,{add,"relup",[invalid_format]}}}); + Other -> + throw({error,{tar_error,{add,"relup",[Other]}}}) + end. + +%% Check that sys.config can be parsed and has expected format +check_sys_config(File) -> + case file:consult(File) of + {ok,[SysConfig]} -> + case lists:all(fun({App,KeyVals}) when is_atom(App), + is_list(KeyVals)-> + true; + (OtherConfig) when is_list(OtherConfig), + is_integer(hd(OtherConfig)) -> + true; + (_) -> + false + end, + SysConfig) of + true -> + ok; + false -> + throw({error,{tar_error, + {add,"sys.config",[invalid_format]}}}) + end; + {ok,_} -> + throw({error,{tar_error,{add,"sys.config",[invalid_format]}}}); + Other -> + throw({error,{tar_error,{add,"sys.config",[Other]}}}) + end. + %%______________________________________________________________________ %% Add either a application located under a variable dir or all other %% applications to a tar file. @@ -2187,9 +2232,12 @@ format_error({missing_parameter,Par}) -> format_error({illegal_applications,Names}) -> io_lib:format("Illegal applications in the release file: ~p~n", [Names]); -format_error({missing_mandatory_app,Names}) -> - io_lib:format("Mandatory applications (~p) must be specified in the release file~n", - [Names]); +format_error({missing_mandatory_app,Name}) -> + io_lib:format("Mandatory application ~p must be specified in the release file~n", + [Name]); +format_error({mandatory_app,Name,Type}) -> + io_lib:format("Mandatory application ~p must be of type 'permanent' in the release file. Is '~p'.~n", + [Name,Type]); format_error({duplicate_register,Dups}) -> io_lib:format("Duplicated register names: ~n~s", [map(fun({{Reg,App1,_,_},{Reg,App2,_,_}}) -> diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl index ac616dab72..467d1226b3 100644 --- a/lib/sasl/test/release_handler_SUITE.erl +++ b/lib/sasl/test/release_handler_SUITE.erl @@ -59,7 +59,7 @@ win32_cases() -> cases() -> [otp_2740, otp_2760, otp_5761, otp_9402, otp_9417, otp_9395_check_old_code, otp_9395_check_and_purge, - otp_9395_update_many_mods, otp_9395_rm_many_mods, + otp_9395_update_many_mods, otp_9395_rm_many_mods, otp_9864, instructions, eval_appup, eval_appup_with_restart, supervisor_which_children_timeout, release_handler_which_releases, install_release_syntax_check, @@ -1205,6 +1205,60 @@ otp_9395_rm_many_mods(Conf) when is_list(Conf) -> otp_9395_rm_many_mods(cleanup,_Conf) -> stop_node(node_name(otp_9395_rm_many_mods)). +otp_9864(Conf) -> + %% Set some paths + PrivDir = priv_dir(Conf), + Dir = filename:join(PrivDir,"otp_9864"), + RelDir = filename:join(?config(data_dir, Conf), "app1_app2"), + LibDir1 = filename:join(RelDir, "lib1"), + LibDir2 = filename:join(RelDir, "lib2"), + + %% Create the releases + Rel1 = create_and_install_fake_first_release(Dir, + [{app1,"1.0",LibDir1}, + {app2,"1.0",LibDir1}]), + Rel2 = create_fake_upgrade_release(Dir, + "2", + [{app1,"2.0",LibDir2}, + {app2,"1.0",LibDir2}], + {[Rel1],[Rel1],[LibDir1]}), + Rel1Dir = filename:dirname(Rel1), + Rel2Dir = filename:dirname(Rel2), + + %% Start a slave node + {ok, Node} = t_start_node(otp_9864, Rel1, filename:join(Rel1Dir,"sys.config")), + + %% Unpack rel2 (make sure it does not work if an AppDir is bad) + LibDir3 = filename:join(RelDir, "lib3"), + {error, {no_such_directory, _}} = + rpc:call(Node, release_handler, set_unpacked, + [Rel2++".rel", [{app1,"2.0",LibDir2}, {app2,"1.0",LibDir3}]]), + {ok, RelVsn2} = + rpc:call(Node, release_handler, set_unpacked, + [Rel2++".rel", [{app1,"2.0",LibDir2}, {app2,"1.0",LibDir2}]]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "relup")]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "start.boot")]), + ok = rpc:call(Node, release_handler, install_file, + [RelVsn2, filename:join(Rel2Dir, "sys.config")]), + + %% Install RelVsn2 without {update_paths, true} option + {ok, RelVsn1, []} = + rpc:call(Node, release_handler, install_release, [RelVsn2]), + + %% Install RelVsn1 again + {ok, RelVsn1, []} = + rpc:call(Node, release_handler, install_release, [RelVsn1]), + + TempRel2Dir = filename:join(Dir,"releases/2"), + file:make_symlink(TempRel2Dir, filename:join(TempRel2Dir, "foo_symlink_dir")), + + %% This will fail if symlinks are not handled + ok = rpc:call(Node, release_handler, remove_release, [RelVsn2]), + + ok. + upgrade_supervisor(Conf) when is_list(Conf) -> %% Set some paths diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl index 43366d8917..4cf7364d74 100644 --- a/lib/sasl/test/systools_SUITE.erl +++ b/lib/sasl/test/systools_SUITE.erl @@ -46,9 +46,11 @@ included_script/1, included_override_script/1, included_fail_script/1, included_bug_script/1, exref_script/1, otp_3065_circular_dependenies/1]). --export([tar_options/1, normal_tar/1, no_mod_vsn_tar/1, variable_tar/1, - src_tests_tar/1, var_tar/1, - exref_tar/1, link_tar/1, otp_9507_path_ebin/1]). +-export([tar_options/1, normal_tar/1, no_mod_vsn_tar/1, system_files_tar/1, + system_files_tar/2, invalid_system_files_tar/1, + invalid_system_files_tar/2, variable_tar/1, + src_tests_tar/1, var_tar/1, exref_tar/1, link_tar/1, + otp_9507_path_ebin/1]). -export([normal_relup/1, restart_relup/1, abnormal_relup/1, no_sasl_relup/1, no_appup_relup/1, bad_appup_relup/1, app_start_type_relup/1, regexp_relup/1]). @@ -80,7 +82,8 @@ groups() -> included_fail_script, included_bug_script, exref_script, otp_3065_circular_dependenies]}, {tar, [], - [tar_options, normal_tar, no_mod_vsn_tar, variable_tar, + [tar_options, normal_tar, no_mod_vsn_tar, system_files_tar, + invalid_system_files_tar, variable_tar, src_tests_tar, var_tar, exref_tar, link_tar, otp_9507_path_ebin]}, {relup, [], [normal_relup, restart_relup, abnormal_relup, no_sasl_relup, @@ -146,7 +149,10 @@ init_per_testcase(_Case, Config) -> Dog = test_server:timetrap(?default_timeout), [{watchdog, Dog}|Config]. -end_per_testcase(_Case, Config) -> +end_per_testcase(Case, Config) -> + try apply(?MODULE,Case,[cleanup,Config]) + catch error:undef -> ok + end, Dog=?config(watchdog, Config), test_server:timetrap_cancel(Dog), case {?config(path,Config),?config(cwd,Config)} of @@ -483,9 +489,17 @@ crazy_script(Config) when is_list(Config) -> ok = file:set_cwd(LatestDir2), error = systools:make_script(LatestName2), - {error, _, {missing_mandatory_app,[kernel,stdlib]}} = + {error, _, {missing_mandatory_app,kernel}} = systools:make_script(LatestName2, [silent,{path,P}]), + %% Run with .rel file with non-permanent kernel + {LatestDir3, LatestName3} = create_script(latest_kernel_start_type, Config), + ok = file:set_cwd(LatestDir3), + + error = systools:make_script(LatestName3), + {error, _, {mandatory_app,kernel,load}} = + systools:make_script(LatestName3, [silent,{path,P}]), + ok = file:set_cwd(OldDir), ok. @@ -756,6 +770,102 @@ no_mod_vsn_tar(Config) when is_list(Config) -> ok = file:set_cwd(OldDir), ok. + +%% make_tar: Check that relup or sys.config are included if they exist +system_files_tar(Config) -> + {ok, OldDir} = file:get_cwd(), + + {LatestDir, LatestName} = create_script(latest,Config), + + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], + + ok = file:set_cwd(LatestDir), + + %% Add dummy relup and sys.config + ok = file:write_file("sys.config","[].\n"), + ok = file:write_file("relup","{\"LATEST\",[],[]}.\n"), + + {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]), + ok = systools:make_tar(LatestName, [{path, P}]), + ok = check_tar(fname(["releases","LATEST","sys.config"]), LatestName), + ok = check_tar(fname(["releases","LATEST","relup"]), LatestName), + {ok, _, _} = systools:make_tar(LatestName, [{path, P}, silent]), + ok = check_tar(fname(["releases","LATEST","sys.config"]), LatestName), + ok = check_tar(fname(["releases","LATEST","relup"]), LatestName), + + ok = file:set_cwd(OldDir), + + ok. + +system_files_tar(cleanup,Config) -> + Dir = ?privdir, + file:delete(filename:join(Dir,"sys.config")), + file:delete(filename:join(Dir,"relup")), + ok. + + +%% make_tar: Check that make_tar fails if relup or sys.config exist +%% but do not have valid content +invalid_system_files_tar(Config) -> + {ok, OldDir} = file:get_cwd(), + + {LatestDir, LatestName} = create_script(latest,Config), + + DataDir = filename:absname(?copydir), + LibDir = fname([DataDir, d_normal, lib]), + P = [fname([LibDir, 'db-2.1', ebin]), + fname([LibDir, 'fe-3.1', ebin])], + + ok = file:set_cwd(LatestDir), + + {ok, _, _} = systools:make_script(LatestName, [silent, {path, P}]), + + %% Add dummy relup and sys.config - faulty sys.config + ok = file:write_file("sys.config","[]\n"), %!!! syntax error - missing '.' + ok = file:write_file("relup","{\"LATEST\",[],[]}.\n"), + + error = systools:make_tar(LatestName, [{path, P}]), + {error,_,{tar_error,{add,"sys.config",[{error,_}]}}} = + systools:make_tar(LatestName, [{path, P}, silent]), + + %% Add dummy relup and sys.config - faulty sys.config + ok = file:write_file("sys.config","[x,y].\n"), %!!! faulty format + ok = file:write_file("relup","{\"LATEST\",[],[]}.\n"), + + error = systools:make_tar(LatestName, [{path, P}]), + {error,_,{tar_error,{add,"sys.config",[invalid_format]}}} = + systools:make_tar(LatestName, [{path, P}, silent]), + + %% Add dummy relup and sys.config - faulty relup + ok = file:write_file("sys.config","[]\n"), + ok = file:write_file("relup","{\"LATEST\"\n"), %!!! syntax error - truncated + + error = systools:make_tar(LatestName, [{path, P}]), + {error,_,{tar_error,{add,"relup",[{error,_}]}}} = + systools:make_tar(LatestName, [{path, P}, silent]), + + %% Add dummy relup and sys.config - faulty relup + ok = file:write_file("sys.config","[]\n"), + ok = file:write_file("relup","[].\n"), %!!! faulty format + + error = systools:make_tar(LatestName, [{path, P}]), + {error,_,{tar_error,{add,"relup",[invalid_format]}}} = + systools:make_tar(LatestName, [{path, P}, silent]), + + ok = file:set_cwd(OldDir), + + ok. + +invalid_system_files_tar(cleanup,Config) -> + Dir = ?privdir, + file:delete(filename:join(Dir,"sys.config")), + file:delete(filename:join(Dir,"relup")), + ok. + + %% make_tar: Use variable and create separate tar (included in generated tar). variable_tar(Config) when is_list(Config) -> {ok, OldDir} = file:get_cwd(), @@ -1915,6 +2025,9 @@ create_script(latest_small2,Config) -> create_script(latest_nokernel,Config) -> Apps = [{db,"2.1"},{fe,"3.1"}], do_create_script(latest_nokernel,Config,"4.4",Apps); +create_script(latest_kernel_start_type,Config) -> + Apps = [{kernel,"1.0",load},{db,"2.1"},{fe,"3.1"}], + do_create_script(latest_kernel_start_type,Config,"4.4",Apps); create_script(latest_app_start_type1,Config) -> Apps = core_apps(current), do_create_script(latest_app_start_type1,Config,current,Apps); diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml index 64a0d1a13f..704ff0a20f 100644 --- a/lib/snmp/doc/src/notes.xml +++ b/lib/snmp/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -34,7 +34,188 @@ <section> + <title>SNMP Development Toolkit 4.21.7</title> + <p>Version 4.21.7 supports code replacement in runtime from/to + version 4.21.6, 4.21.5, 4.21.4, 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1 and + 4.20. </p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>[agent] DoS attack using GET-BULK with large value of + MaxRepetitions. + A preventive method has been implementing by simply + limit the number of varbinds that can be included in + a Get-BULK response message. This is specified by the + new config option, + <seealso marker="snmp_app#agent_gb_max_vbs">gb_max_vbs</seealso>. + </p> + <p>Own Id: OTP-9700</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>[agent] Simultaneous + <seealso marker="snmpa#backup">snmpa:backup/1,2</seealso> + calls can interfere. + The master agent did not check if a backup was already in + progress when a backup request was accepted. </p> + <p>Own Id: OTP-9884</p> + <p>Aux Id: Seq 11995</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + + </section> <!-- 4.21.7 --> + + + <section> + <title>SNMP Development Toolkit 4.21.6</title> + <p>Version 4.21.6 supports code replacement in runtime from/to + version 4.21.5, 4.21.4, 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1 and + 4.20. </p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>[agent] DoS attack using GET-BULK with large value of + MaxRepetitions. + A preventive method has been implementing by simply + limit the number of varbinds that can be included in + a Get-BULK response message. This is specified by the + new config option, + <seealso marker="snmp_app#agent_gb_max_vbs">gb_max_vbs</seealso>. + </p> + <p>Own Id: OTP-9700</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>[agent] Mib server cache gclimit update function incorrectly calls + age update function. + The gclimit update function, + <seealso marker="snmpa#update_mibs_cache_gclimit">update_mibs_cache_gclimit/1</seealso>, + <em>incorrectly</em> called the age update function, + <seealso marker="snmpa#update_mibs_cache_age">update_mibs_cache_age/2</seealso>. </p> + <p>Johan Claesson</p> + <p>Own Id: OTP-9868</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + + </section> <!-- 4.21.6 --> + + + <section> + <title>SNMP Development Toolkit 4.21.5</title> + <p>Version 4.21.5 supports code replacement in runtime from/to + version 4.21.4, 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1 and 4.20. </p> + + <section> + <title>Improvements and new features</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>[agent] Removed (more) use of old style tuple funs. </p> + <p>Own Id: OTP-9783</p> + </item> + + </list> + + </section> + + <section> + <title>Fixed Bugs and Malfunctions</title> +<!-- + <p>-</p> +--> + + <list type="bulleted"> + <item> + <p>[agent] Repeated vacm table dumping fails due to file name + conflict. When dumping the vacm table to disk, a temoporary + file with a fixed name was used. If the table dumping + (snmpa_vacm:dump_table/0) was initiated from several different + processes in rapid succesion, the dumping could fail because the + different processes was simultaniously trying to write to the + same file. This problem has been eliminated by creating a unique + name for the temporary file. </p> + <p>Own Id: OTP-9851</p> + <p>Aux Id: Seq 11980</p> + </item> + + </list> + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + +<!-- + <list type="bulleted"> + <item> + <p>foo. </p> + <p>Own Id: OTP-9718</p> + </item> + + </list> +--> + + </section> + + </section> <!-- 4.21.5 --> + + + <section> <title>SNMP Development Toolkit 4.21.4</title> + <p>This version has never been released for R14B.</p> <p>Version 4.21.4 supports code replacement in runtime from/to version 4.21.3, 4.21.2, 4.21.1, 4.21, 4.20.1, 4.20 and 4.19. </p> @@ -46,7 +227,7 @@ <list type="bulleted"> <item> <p>[compiler] Improved version info printout from the - <seealso marker="snmpc(command)#">MIB compiler frontend escript</seealso>. </p> + <seealso marker="snmpc(command)#">MIB compiler frontend escript</seealso>. </p> <p>Own Id: OTP-9618</p> </item> @@ -70,7 +251,6 @@ </list> </section> - <section> <title>Incompatibilities</title> <p>-</p> @@ -78,7 +258,7 @@ <!-- <list type="bulleted"> <item> - <p>foo. </p> + <p>foo. </p> <p>Own Id: OTP-9718</p> </item> @@ -641,355 +821,6 @@ snmp_view_basec_acm_mib:vacmAccessTable(set, RowIndex, Cols). </section> <!-- 4.18 --> - <section> - <title>SNMP Development Toolkit 4.17.1</title> - <p>Version 4.17.1 supports code replacement in runtime from/to - version 4.17, 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <list type="bulleted"> - <item> - <p>When the function FilterMod:accept_recv/2 - returned false the SNMP agent stopped collecting - messages from UDP.</p> - <p>Own Id: OTP-8761</p> - </item> - </list> - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.17.1 --> - - - <section> - <title>SNMP Development Toolkit 4.17</title> - <p>Version 4.17 supports code replacement in runtime from/to - version 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent] Added very basic support for multiple SNMPv3 - EngineIDs in a single agent. See - <seealso marker="snmpa#send_notification">send_notification/7</seealso>, - <seealso marker="snmpa_mpd#process_packet">process_packet/7</seealso>, - <seealso marker="snmpa_mpd#generate_response_msg">generate_response_msg/6</seealso> or - <seealso marker="snmpa_mpd#generate_msg">generate_msg/6</seealso> - for more info. </p> - - <p>Own Id: OTP-8478</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <p>-</p> - - <!-- - <list type="bulleted"> - <item> - <p>The config utility - (<seealso marker="snmp#config">snmp:config/0</seealso>) - generated a default notify.conf - with a bad name for the standard trap entry (was "stadard trap", - but should have been "standard trap"). This has been corrected. </p> - <p>Kenji Rikitake</p> - <p>Own Id: OTP-8433</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.17 --> - - - <section> - <title>SNMP Development Toolkit 4.16.2</title> - <p>Version 4.16.2 supports code replacement in runtime from/to - version 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[compiler] The SMI specifies that a table row OID should be - named: { <tableIdentifier> "1" }. </p> - <p>A new option has been introduced, - <seealso marker="snmpc#compiler_opts">relaxed_row_name_assign_check</seealso>, - that allows for a more liberal numbering scheme</p> - <p>Own Id: OTP-8574</p> - </item> - - <item> - <p>[agent|manager] Changes to make snmp (forward) compatible with - the new version of the crypto application (released in R14). - As of R14, crypto is implemented using NIFs. Also, - the API is more strict. </p> - <p>Own Id: OTP-8594</p> - </item> - - <item> - <p>Auto [agent] Changed default value for the MIB server cache. - GC is now on by default. </p> - <p>Own Id: OTP-8648</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - - <list type="bulleted"> - <item> - <p>Encode/decode of Counter64 values larger than - 16#7fffffffffffffff (9223372036854775807) failed. </p> - <p>Own Id: OTP-8563</p> - </item> - - <item> - <p>[compiler] Fails to compile non-contiguous BITS. </p> - <p>Per Hedeland</p> - <p>Own Id: OTP-8595</p> - </item> - - <item> - <p>[manager] Raise condition causing the manager server process to - crash. Unregistering an agent while traffic (set/get-operations) - is ongoing could cause a crash in the manager server process - (raise condition). </p> - <p>Own Id: OTP-8646</p> - <p>Aux Id: Seq 11585</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.16.2 --> - - - <section> - <title>SNMP Development Toolkit 4.16.1</title> - <p>Version 4.16.1 supports code replacement in runtime from/to - version 4.16, 4.15, 4.14 and 4.13.5.</p> - - <section> - <title>Improvements and new features</title> - <p>-</p> - <!-- - <list type="bulleted"> - <item> - <p>[agent|manager] Entries in the audit trail log can now be - augmented by a sequence number. </p> - <p>This is enabled by the <c>seqno</c> option, which is part of the - <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso> - config option. </p> - <p>See the - <seealso marker="snmp_app#configuration_params">reference manual</seealso> - or the - <seealso marker="snmp_config#configuration_params">Configuring the application</seealso> - chapter of the User's Guide for further info. </p> - - <p>Own Id: OTP-8395</p> - </item> - - </list> - --> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - - <list type="bulleted"> - <item> - <p>[manager] Fixed an upgrade/downgrade problem. </p> - <p>Upgrade/downgrade from/to 4.13.5 did not work for the net-if - process. This has now been fixed. </p> - <p>Own Id: OTP-8481</p> - </item> - - <item> - <p>[agent] A minor mnesia related performance improvement. </p> - <p>Own Id: OTP-8480</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.16.1 --> - - - <section> - <title>SNMP Development Toolkit 4.16</title> - <p>Version 4.16 supports code replacement in runtime from/to - version 4.15, 4.14 and 4.13.5.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[agent|manager] Entries in the audit trail log can now be - augmented by a sequence number. </p> - <p>This is enabled by the <c>seqno</c> option, which is part of the - <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso> - config option. </p> - <p>See the - <seealso marker="snmp_app#configuration_params">reference manual</seealso> - or the - <seealso marker="snmp_config#configuration_params">Configuring the application</seealso> - chapter of the User's Guide for further info. </p> - - <p>Own Id: OTP-8395</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - - <list type="bulleted"> - <item> - <p>[manager] Registration of agents using the config file, - <seealso marker="snmp_manager_config_files#agents">agents.conf</seealso>, - does not work. This has now been corrected. </p> - <p>Per Hedeland</p> - <p>Own Id: OTP-8442</p> - </item> - - <item> - <p>The config utility - (<seealso marker="snmp#config">snmp:config/0</seealso>) - generated a default notify.conf - with a bad name for the standard trap entry (was "stadard trap", - but should have been "standard trap"). This has been corrected. </p> - <p>Kenji Rikitake</p> - <p>Own Id: OTP-8433</p> - </item> - - </list> - - </section> - - <section> - <title>Incompatibilities</title> - <p>-</p> - </section> - </section> <!-- 4.16 --> - - - <section> - <title>SNMP Development Toolkit 4.15</title> - - <p>Version 4.15 supports code replacement in runtime from/to - version 4.14 and 4.13.5.</p> - - <section> - <title>Improvements and new features</title> - <!-- - <p>-</p> - --> - - <list type="bulleted"> - <item> - <p>The documentation is now built with open source tools - (<em>xsltproc</em> and <em>fop</em>) that exists on most - platforms. One visible change is that the frames are removed.</p> - <p>Own Id: OTP-8249</p> - </item> - - </list> - - </section> - - <section> - <title>Reported Fixed Bugs and Malfunctions</title> - <!-- - <p>-</p> - --> - <list type="bulleted"> - <item> - <p>[manager] When information from an unknown agent is received, - it was previously delivered to the default user via calls to all - the functions of the callback API depending on the info type - (<c>pdu</c>, <c>trap</c>, <c>report</c> or <c>inform</c>). - The problem was that the <c>TargetName</c> argument was useless - in this case (only an already known agent has a known/valid - <c>TargetName</c>, but the <c>TargetName</c> used in these calls - was generated "on the fly"). </p> - <p>This has now been changed so that when a message is received - from an unknown agent, then only - <seealso marker="snmpm_user#handle_agent">handle_agent</seealso> - (for the default user) is called, but now this call also has a - <c>Type</c> argument, which is - <c>pdu | trap | report | inform</c>, depending on what kind of - message was actually received, thus making it possible for the - user to properly analyze the data received. </p> - <p>To handle this, the - <seealso marker="snmpm_user">snmpm_user</seealso> behaviour has - been updated. </p> - <p>*** POTENTIAL INCOMPATIBILITY ***</p> - <p>Own Id: OTP-8229</p> - <!-- <p>Aux Id: Seq 11312</p> --> - </item> - - </list> - - </section> - - </section> <!-- 4.15 --> - - <!-- section> <title>Release notes history</title> <p>For information about older versions see diff --git a/lib/snmp/doc/src/notes_history.xml b/lib/snmp/doc/src/notes_history.xml index e833335ffb..023717cd7c 100644 --- a/lib/snmp/doc/src/notes_history.xml +++ b/lib/snmp/doc/src/notes_history.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2004</year><year>2011</year> + <year>2004</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,6 +33,355 @@ </header> <section> + <title>SNMP Development Toolkit 4.17.1</title> + <p>Version 4.17.1 supports code replacement in runtime from/to + version 4.17, 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <list type="bulleted"> + <item> + <p>When the function FilterMod:accept_recv/2 + returned false the SNMP agent stopped collecting + messages from UDP.</p> + <p>Own Id: OTP-8761</p> + </item> + </list> + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.17.1 --> + + + <section> + <title>SNMP Development Toolkit 4.17</title> + <p>Version 4.17 supports code replacement in runtime from/to + version 4.16.2, 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent] Added very basic support for multiple SNMPv3 + EngineIDs in a single agent. See + <seealso marker="snmpa#send_notification">send_notification/7</seealso>, + <seealso marker="snmpa_mpd#process_packet">process_packet/7</seealso>, + <seealso marker="snmpa_mpd#generate_response_msg">generate_response_msg/6</seealso> or + <seealso marker="snmpa_mpd#generate_msg">generate_msg/6</seealso> + for more info. </p> + + <p>Own Id: OTP-8478</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <p>-</p> + + <!-- + <list type="bulleted"> + <item> + <p>The config utility + (<seealso marker="snmp#config">snmp:config/0</seealso>) + generated a default notify.conf + with a bad name for the standard trap entry (was "stadard trap", + but should have been "standard trap"). This has been corrected. </p> + <p>Kenji Rikitake</p> + <p>Own Id: OTP-8433</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.17 --> + + + <section> + <title>SNMP Development Toolkit 4.16.2</title> + <p>Version 4.16.2 supports code replacement in runtime from/to + version 4.16.1, 4.16, 4.15, 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[compiler] The SMI specifies that a table row OID should be + named: { <tableIdentifier> "1" }. </p> + <p>A new option has been introduced, + <seealso marker="snmpc#compiler_opts">relaxed_row_name_assign_check</seealso>, + that allows for a more liberal numbering scheme</p> + <p>Own Id: OTP-8574</p> + </item> + + <item> + <p>[agent|manager] Changes to make snmp (forward) compatible with + the new version of the crypto application (released in R14). + As of R14, crypto is implemented using NIFs. Also, + the API is more strict. </p> + <p>Own Id: OTP-8594</p> + </item> + + <item> + <p>Auto [agent] Changed default value for the MIB server cache. + GC is now on by default. </p> + <p>Own Id: OTP-8648</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>Encode/decode of Counter64 values larger than + 16#7fffffffffffffff (9223372036854775807) failed. </p> + <p>Own Id: OTP-8563</p> + </item> + + <item> + <p>[compiler] Fails to compile non-contiguous BITS. </p> + <p>Per Hedeland</p> + <p>Own Id: OTP-8595</p> + </item> + + <item> + <p>[manager] Raise condition causing the manager server process to + crash. Unregistering an agent while traffic (set/get-operations) + is ongoing could cause a crash in the manager server process + (raise condition). </p> + <p>Own Id: OTP-8646</p> + <p>Aux Id: Seq 11585</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.16.2 --> + + + <section> + <title>SNMP Development Toolkit 4.16.1</title> + <p>Version 4.16.1 supports code replacement in runtime from/to + version 4.16, 4.15, 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <p>-</p> + <!-- + <list type="bulleted"> + <item> + <p>[agent|manager] Entries in the audit trail log can now be + augmented by a sequence number. </p> + <p>This is enabled by the <c>seqno</c> option, which is part of the + <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso> + config option. </p> + <p>See the + <seealso marker="snmp_app#configuration_params">reference manual</seealso> + or the + <seealso marker="snmp_config#configuration_params">Configuring the application</seealso> + chapter of the User's Guide for further info. </p> + + <p>Own Id: OTP-8395</p> + </item> + + </list> + --> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>[manager] Fixed an upgrade/downgrade problem. </p> + <p>Upgrade/downgrade from/to 4.13.5 did not work for the net-if + process. This has now been fixed. </p> + <p>Own Id: OTP-8481</p> + </item> + + <item> + <p>[agent] A minor mnesia related performance improvement. </p> + <p>Own Id: OTP-8480</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.16.1 --> + + + <section> + <title>SNMP Development Toolkit 4.16</title> + <p>Version 4.16 supports code replacement in runtime from/to + version 4.15, 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[agent|manager] Entries in the audit trail log can now be + augmented by a sequence number. </p> + <p>This is enabled by the <c>seqno</c> option, which is part of the + <seealso marker="snmp_config#audit_trail_log">Audit Trail Log</seealso> + config option. </p> + <p>See the + <seealso marker="snmp_app#configuration_params">reference manual</seealso> + or the + <seealso marker="snmp_config#configuration_params">Configuring the application</seealso> + chapter of the User's Guide for further info. </p> + + <p>Own Id: OTP-8395</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>[manager] Registration of agents using the config file, + <seealso marker="snmp_manager_config_files#agents">agents.conf</seealso>, + does not work. This has now been corrected. </p> + <p>Per Hedeland</p> + <p>Own Id: OTP-8442</p> + </item> + + <item> + <p>The config utility + (<seealso marker="snmp#config">snmp:config/0</seealso>) + generated a default notify.conf + with a bad name for the standard trap entry (was "stadard trap", + but should have been "standard trap"). This has been corrected. </p> + <p>Kenji Rikitake</p> + <p>Own Id: OTP-8433</p> + </item> + + </list> + + </section> + + <section> + <title>Incompatibilities</title> + <p>-</p> + </section> + </section> <!-- 4.16 --> + + + <section> + <title>SNMP Development Toolkit 4.15</title> + + <p>Version 4.15 supports code replacement in runtime from/to + version 4.14 and 4.13.5.</p> + + <section> + <title>Improvements and new features</title> + <!-- + <p>-</p> + --> + + <list type="bulleted"> + <item> + <p>The documentation is now built with open source tools + (<em>xsltproc</em> and <em>fop</em>) that exists on most + platforms. One visible change is that the frames are removed.</p> + <p>Own Id: OTP-8249</p> + </item> + + </list> + + </section> + + <section> + <title>Reported Fixed Bugs and Malfunctions</title> + <!-- + <p>-</p> + --> + <list type="bulleted"> + <item> + <p>[manager] When information from an unknown agent is received, + it was previously delivered to the default user via calls to all + the functions of the callback API depending on the info type + (<c>pdu</c>, <c>trap</c>, <c>report</c> or <c>inform</c>). + The problem was that the <c>TargetName</c> argument was useless + in this case (only an already known agent has a known/valid + <c>TargetName</c>, but the <c>TargetName</c> used in these calls + was generated "on the fly"). </p> + <p>This has now been changed so that when a message is received + from an unknown agent, then only + <seealso marker="snmpm_user#handle_agent">handle_agent</seealso> + (for the default user) is called, but now this call also has a + <c>Type</c> argument, which is + <c>pdu | trap | report | inform</c>, depending on what kind of + message was actually received, thus making it possible for the + user to properly analyze the data received. </p> + <p>To handle this, the + <seealso marker="snmpm_user">snmpm_user</seealso> behaviour has + been updated. </p> + <p>*** POTENTIAL INCOMPATIBILITY ***</p> + <p>Own Id: OTP-8229</p> + <!-- <p>Aux Id: Seq 11312</p> --> + </item> + + </list> + + </section> + + </section> <!-- 4.15 --> + + + <section> <title>SNMP Development Toolkit 4.14</title> <p>Version 4.14 supports code replacement in runtime from/to diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml index 694e619da1..f6abe783b3 100644 --- a/lib/snmp/doc/src/snmp_app.xml +++ b/lib/snmp/doc/src/snmp_app.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE appref SYSTEM "appref.dtd"> <appref> <header> <copyright> - <year>1997</year><year>2010</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -78,7 +78,15 @@ ]. </pre> - <!-- The info below is also found in the snmp_config.xml file --> + + <!-- + ******************************************************** + + The info below is also found in the snmp_config.xml file + + ******************************************************** + --> + <p>Each snmp component has its own set of configuration parameters, even though some of the types are common to both components. </p> @@ -92,6 +100,7 @@ {agent_verbosity, verbosity()} | {discovery, agent_discovery()} | {versions, versions()} | + {gb_max_vbs, gb_max_vbs()} | {priority, priority()} | {multi_threaded, multi_threaded()} | {db_dir, db_dir()} | @@ -122,8 +131,10 @@ {def_user_data, def_user_data()} </pre> + <marker id="agent_opts_and_types"></marker> <p>Agent specific config options and types:</p> <taglist> + <marker id="agent_type"></marker> <tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag> <item> <p>If <c>master</c>, one master agent is @@ -131,6 +142,7 @@ <p>Default is <c>master</c>.</p> </item> + <marker id="agent_disco"></marker> <tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_discovery_opt() = @@ -143,6 +155,7 @@ <p>For defaults see the options in <c>agent_discovery_opt()</c>.</p> </item> + <marker id="agent_term_disco_opts"></marker> <tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_terminating_discovery_opt() = @@ -160,6 +173,7 @@ </list> </item> + <marker id="agent_orig_disco_opts"></marker> <tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_originating_discovery_opt() = @@ -173,6 +187,7 @@ </list> </item> + <marker id="agent_mt"></marker> <tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, the agent is multi-threaded, with one @@ -180,11 +195,21 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_data_dir"></marker> <tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent internal db files are stored.</p> </item> + <marker id="agent_gb_max_vbs"></marker> + <tag><c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag> + <item> + <p>Defines the maximum number of varbinds allowed + in a Get-BULK response.</p> + <p>Default is <c>1000</c>.</p> + </item> + + <marker id="agent_local_db"></marker> <tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag> <item> <p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p> @@ -192,6 +217,7 @@ <p>For defaults see the options in <c>local_db_opt()</c>.</p> </item> + <marker id="agent_ldb_repair"></marker> <tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag> <item> <p>When starting snmpa_local_db it always tries to open an @@ -202,6 +228,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="agent_ldb_auto_save"></marker> <tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk @@ -209,6 +236,7 @@ <p>Default is <c>5000</c>.</p> </item> + <marker id="agent_net_if"></marker> <tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag> <item> <p><c>agent_net_if_opt() = {module, agent_net_if_module()} | {verbosity, verbosity()} | {options, agent_net_if_options()}</c></p> @@ -217,6 +245,7 @@ <p>For defaults see the options in <c>agent_net_if_opt()</c>.</p> </item> + <marker id="agent_ni_module"></marker> <tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the @@ -225,6 +254,7 @@ <p>Default is <c>snmpa_net_if</c>.</p> </item> + <marker id="agent_ni_opts"></marker> <tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag> <item> <p><c>agent_net_if_option() = {bind_to, bind_to()} | @@ -239,12 +269,14 @@ <p>For defaults see the options in <c>agent_net_if_option()</c>.</p> </item> + <marker id="agent_ni_req_limit"></marker> <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag> <item> <p>Max number of simultaneous requests handled by the agent.</p> <p>Default is <c>infinity</c>.</p> </item> + <marker id="agent_ni_filter_opts"></marker> <tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c>agent_net_if_filter_option() = {module, agent_net_if_filter_module()}</c></p> @@ -255,6 +287,7 @@ <c>agent_net_if_filter_option()</c>.</p> </item> + <marker id="agent_ni_filter_module"></marker> <tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the @@ -263,6 +296,7 @@ <p>Default is <c>snmpa_net_if_filter</c>.</p> </item> + <marker id="agent_mibs"></marker> <tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) that defines which MIBs @@ -277,6 +311,7 @@ <p>Default is <c>[]</c>.</p> </item> + <marker id="agent_mib_storage"></marker> <tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag> <item> <p>Specifies how info retrieved from the mibs will be stored.</p> @@ -302,6 +337,7 @@ mnesia/dets table already exist.</p> </item> + <marker id="agent_mib_server"></marker> <tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag> <item> <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p> @@ -309,6 +345,7 @@ <p>For defaults see the options in <c>mib_server_opt()</c>.</p> </item> + <marker id="agent_ms_meo"></marker> <tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each mib- @@ -318,6 +355,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_ms_teo"></marker> <tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each trap @@ -327,6 +365,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_ms_cache"></marker> <tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag> <item> <p>Shall the agent utilize the mib server lookup cache or not.</p> @@ -334,6 +373,7 @@ default values apply).</p> </item> + <marker id="agent_ms_cache_opts"></marker> <tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag> <item> <p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p> @@ -341,6 +381,7 @@ <p>For defaults see the options in <c>mibs_cache_opt()</c>.</p> </item> + <marker id="agent_ms_cache_autogc"></marker> <tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag> <item> <p>Defines if the mib server shall perform cache gc automatically or @@ -349,6 +390,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="agent_ms_cache_age"></marker> <tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag> <item> <p>Defines how old the entries in the cache will be allowed before @@ -358,6 +400,7 @@ <p>Default is <c>10 timutes</c>.</p> </item> + <marker id="agent_ms_cache_gclimit"></marker> <tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag> <item> <p>When performing a GC, this is the max number of cache entries @@ -368,6 +411,7 @@ <p>Default is <c>100</c>.</p> </item> + <marker id="agent_error_report_mod"></marker> <tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag> <item> <p>Defines an error report module, implementing the @@ -377,6 +421,7 @@ <p>Default is <c>snmpa_error_logger</c>.</p> </item> + <marker id="agent_symbolic_store"></marker> <tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag> <item> <p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p> @@ -384,23 +429,29 @@ <p>For defaults see the options in <c>symbolic_store_opt()</c>.</p> </item> + <marker id="agent_target_cache"></marker> <tag><c>target_cache() = [target_cache_opt()]</c></tag> <item> <p><c>target_cache_opt() = {verbosity, verbosity()}</c></p> <p>Defines options specific for the SNMP agent target cache. </p> <p>For defaults see the options in <c>target_cache_opt()</c>.</p> </item> + + <marker id="agent_config"></marker> <tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag> <item> <p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p> <p>Defines specific config related options for the SNMP agent. </p> <p>For defaults see the options in <c>agent_config_opt()</c>.</p> </item> + + <marker id="agent_config_dir"></marker> <tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent configuration files are stored.</p> </item> + <marker id="agent_force_load"></marker> <tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c> the configuration files are re-read @@ -412,14 +463,18 @@ </item> </taglist> + <marker id="manager_opts_and_types"></marker> <p>Manager specific config options and types:</p> <taglist> + <marker id="manager_server"></marker> <tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag> <item> <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p> <p>Specifies the options for the manager server process.</p> <p>Default is <c>silence</c>.</p> </item> + + <marker id="manager_server_timeout"></marker> <tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag> <item> <p>Asynchroneous request cleanup time. For every requests, @@ -440,6 +495,7 @@ <p>Default is <c>30000</c>.</p> </item> + <marker id="manager_config"></marker> <tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag> <item> <p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p> @@ -447,16 +503,19 @@ <p>For defaults see the options in <c>manager_config_opt()</c>.</p> </item> + <marker id="manager_config_dir"></marker> <tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager configuration files are stored.</p> </item> + <marker id="manager_config_db_dir"></marker> <tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager store persistent data.</p> </item> + <marker id="manager_config_repair"></marker> <tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag> <item> <p>Defines the repair option for the persistent database (if @@ -464,6 +523,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="manager_config_auto_save"></marker> <tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk @@ -471,6 +531,7 @@ <p>Default is <c>5000</c>.</p> </item> + <marker id="manager_irb"></marker> <tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag> <item> <p>This option defines how the manager will handle the sending of @@ -500,6 +561,7 @@ <p>Default is <c>auto</c>.</p> </item> + <marker id="manager_mibs"></marker> <tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) and defines which MIBs @@ -507,6 +569,7 @@ <p>Default is <c>[]</c>.</p> </item> + <marker id="manager_net_if"></marker> <tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag> <item> <p><c>manager_net_if_opt() = {module, manager_net_if_module()} | @@ -517,6 +580,7 @@ <p>For defaults see the options in <c>manager_net_if_opt()</c>.</p> </item> + <marker id="manager_ni_opts"></marker> <tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_option() = {bind_to, bind_to()} | @@ -530,6 +594,7 @@ <p>For defaults see the options in <c>manager_net_if_option()</c>.</p> </item> + <marker id="manager_ni_module"></marker> <tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the @@ -538,6 +603,7 @@ <p>Default is <c>snmpm_net_if</c>.</p> </item> + <marker id="manager_ni_filter_opts"></marker> <tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p> @@ -548,6 +614,7 @@ <c>manager_net_if_filter_option()</c>.</p> </item> + <marker id="manager_ni_filter_module"></marker> <tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the @@ -556,6 +623,7 @@ <p>Default is <c>snmpm_net_if_filter</c>.</p> </item> + <marker id="manager_def_user_module"></marker> <tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag> <item> <p>The module implementing the default user. See the @@ -563,6 +631,7 @@ <p>Default is <c>snmpm_user_default</c>.</p> </item> + <marker id="manager_def_user_data"></marker> <tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag> <item> <p>Data for the default user. Passed to the user module when @@ -571,8 +640,10 @@ </item> </taglist> + <marker id="common_types"></marker> <p>Common config types:</p> <taglist> + <marker id="restart_type"></marker> <tag><c>restart_type() = permanent | transient | temporary</c></tag> <item> <p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso> @@ -580,6 +651,8 @@ <p>Default is <c>permanent</c> for the agent and <c>transient</c> for the manager.</p> </item> + + <marker id="db_init_error"></marker> <tag><c>db_init_error() = terminate | create</c></tag> <item> <p>Defines what to do if the agent or manager is unable to open an @@ -588,23 +661,31 @@ agent/manager will remove the faulty file(s) and create new ones.</p> <p>Default is <c>terminate</c>.</p> </item> + + <marker id="prio"></marker> <tag><c><![CDATA[priority() = atom() <optional>]]></c></tag> <item> <p>Defines the Erlang priority for all SNMP processes.</p> <p>Default is <c>normal</c>.</p> </item> + + <marker id="versions"></marker> <tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag> <item> <p><c>version() = v1 | v2 | v3</c></p> <p>Which SNMP versions shall be accepted/used.</p> <p>Default is <c>[v1,v2,v3]</c>.</p> </item> + + <marker id="verbosity"></marker> <tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag> <item> <p>Verbosity for a SNMP process. This specifies now much debug info is printed.</p> <p>Default is <c>silence</c>.</p> </item> + + <marker id="bind_to"></marker> <tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if binds to the IP address. @@ -612,6 +693,8 @@ where it is running. </p> <p>Default is <c>false</c>.</p> </item> + + <marker id="no_reuse"></marker> <tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if does not specify that the IP @@ -619,22 +702,30 @@ the address is set to reusable. </p> <p>Default is <c>false</c>.</p> </item> + + <marker id="recbuf"></marker> <tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag> <item> <p>Receive buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> + + <marker id="sndbuf"></marker> <tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag> <item> <p>Send buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> + + <marker id="note_store"></marker> <tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag> <item> <p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p> <p>Specifies the start-up verbosity for the SNMP note store.</p> <p>For defaults see the options in <c>note_store_opt()</c>.</p> </item> + + <marker id="ns_timeout"></marker> <tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag> <item> <p>Note cleanup time. When storing a note in the note store, @@ -643,9 +734,9 @@ milli-seconds.</p> <p>Default is <c>30000</c>.</p> - <marker id="audit_trail_log"></marker> </item> + <marker id="audit_trail_log"></marker> <tag><c><![CDATA[audit_trail_log() = [audit_trail_log_opt()] <optional>]]></c></tag> <item> <p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}</c></p> @@ -655,6 +746,8 @@ <c>size</c> options are mandatory.</p> <p>If not present, audit trail logging is not used.</p> </item> + + <marker id="atl_type"></marker> <tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag> <item> <p>Specifies what type of an audit trail log should be used. @@ -675,12 +768,16 @@ </list> <p>Default is <c>read_write</c>.</p> </item> + + <marker id="atl_dir"></marker> <tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag> <item> <p>Specifies where the audit trail log should be stored.</p> <p>If <c>audit_trail_log</c> specifies that logging should take place, this parameter <em>must</em> be defined.</p> </item> + + <marker id="atl_size"></marker> <tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag> <item> <p>Specifies the size of the audit @@ -688,6 +785,8 @@ <p>If <c>audit_trail_log</c> specifies that logging should take place, this parameter <em>must</em> be defined.</p> </item> + + <marker id="atl_repair"></marker> <tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag> <item> <p>Specifies if and how the audit trail log shall be repaired @@ -699,6 +798,8 @@ analysis.</p> <p>Default is <c>true</c>.</p> </item> + + <marker id="atl_seqno"></marker> <tag><c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag> <item> <p>Specifies if the audit trail log entries will be (sequence) diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml index fc8562b638..0a49b7a62e 100644 --- a/lib/snmp/doc/src/snmp_config.xml +++ b/lib/snmp/doc/src/snmp_config.xml @@ -40,6 +40,7 @@ <item>starting the application (agent and/or manager)</item> <item>debugging the application (agent and/or manager)</item> </list> + <p>Refer also to the chapter(s) <seealso marker="snmp_agent_config_files">Definition of Agent Configuration Files</seealso> and <seealso marker="snmp_manager_config_files">Definition of Manager Configuration Files</seealso> which contains more detailed information @@ -73,7 +74,14 @@ </item> </list> - <!-- The info below is also found in the snmp_app.xml file --> + + <!-- + ***************************************************** + + The info below is also found in the snmp_app.xml file + + ***************************************************** + --> <p>The agent and manager uses (application) configuration parameters to find out where these directories are located. The parameters should be @@ -87,6 +95,7 @@ {agent_verbosity, verbosity()} | {versions, versions()} | {discovery, agent_discovery()} | + {gb_max_vbs, gb_max_vbs()} | {priority, priority()} | {multi_threaded, multi_threaded()} | {db_dir, db_dir()} | @@ -117,8 +126,10 @@ {def_user_data, def_user_data()} </pre> + <marker id="agent_opts_and_types"></marker> <p>Agent specific config options and types:</p> <taglist> + <marker id="agent_type"></marker> <tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag> <item> <p>If <c>master</c>, one master agent is @@ -126,6 +137,7 @@ <p>Default is <c>master</c>.</p> </item> + <marker id="agent_disco"></marker> <tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_discovery_opt() = @@ -138,6 +150,7 @@ <p>For defaults see the options in <c>agent_discovery_opt()</c>.</p> </item> + <marker id="agent_term_disco_opts"></marker> <tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_terminating_discovery_opt() = @@ -155,6 +168,7 @@ </list> </item> + <marker id="agent_orig_disco_opts"></marker> <tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag> <item> <p><c>agent_originating_discovery_opt() = @@ -168,6 +182,7 @@ </list> </item> + <marker id="agent_mt"></marker> <tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, the agent is multi-threaded, with one @@ -175,11 +190,21 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_data_dir"></marker> <tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent internal db files are stored.</p> </item> + <marker id="agent_gb_max_vbs"></marker> + <tag><c><![CDATA[gb_max_vbs() = pos_integer() | infinity <optional>]]></c></tag> + <item> + <p>Defines the maximum number of varbinds allowed + in a Get-BULK response.</p> + <p>Default is <c>1000</c>.</p> + </item> + + <marker id="agent_local_db"></marker> <tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag> <item> <p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p> @@ -187,6 +212,7 @@ <p>For defaults see the options in <c>local_db_opt()</c>.</p> </item> + <marker id="agent_ldb_repair"></marker> <tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag> <item> <p>When starting snmpa_local_db it always tries to open an @@ -197,6 +223,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="agent_ldb_auto_save"></marker> <tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk @@ -204,6 +231,7 @@ <p>Default is <c>5000</c>.</p> </item> + <marker id="agent_net_if"></marker> <tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag> <item> <p><c>agent_net_if_option() = {module, agent_net_if_module()} | @@ -214,6 +242,7 @@ <p>For defaults see the options in <c>agent_net_if_opt()</c>.</p> </item> + <marker id="agent_ni_module"></marker> <tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the @@ -222,6 +251,7 @@ <p>Default is <c>snmpa_net_if</c>.</p> </item> + <marker id="agent_ni_opts"></marker> <tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag> <item> <p><c>agent_net_if_option() = {bind_to, bind_to()} | @@ -236,6 +266,14 @@ <p>For defaults see the options in <c>agent_net_if_option()</c>.</p> </item> + <marker id="agent_ni_req_limit"></marker> + <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag> + <item> + <p>Max number of simultaneous requests handled by the agent.</p> + <p>Default is <c>infinity</c>.</p> + </item> + + <marker id="agent_ni_filter_opts"></marker> <tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c><![CDATA[agent_net_if_filter_option() = {module, agent_net_if_filter_module()}]]></c></p> @@ -245,6 +283,7 @@ <p>For defaults see the options in <c>agent_net_if_filter_option()</c>.</p> </item> + <marker id="agent_ni_filter_module"></marker> <tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the @@ -254,12 +293,7 @@ <p>Default is <c>snmpa_net_if_filter</c>.</p> </item> - <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag> - <item> - <p>Max number of simultaneous requests handled by the agent.</p> - <p>Default is <c>infinity</c>.</p> - </item> - + <marker id="agent_mibs"></marker> <tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) that defines which MIBs @@ -274,6 +308,7 @@ <p>Default is <c>[]</c>.</p> </item> + <marker id="agent_mib_storage"></marker> <tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag> <item> <p>Specifies how info retrieved from the mibs will be stored.</p> @@ -299,6 +334,7 @@ mnesia/dets table already exist.</p> </item> + <marker id="agent_mib_server"></marker> <tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag> <item> <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p> @@ -306,6 +342,7 @@ <p>For defaults see the options in <c>mib_server_opt()</c>.</p> </item> + <marker id="agent_ms_meo"></marker> <tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each mib- @@ -315,6 +352,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_ms_teo"></marker> <tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag> <item> <p>If this value is false, then when loading a mib each trap @@ -324,6 +362,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="agent_ms_cache"></marker> <tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag> <item> <p>Shall the agent utilize the mib server lookup cache or not.</p> @@ -331,6 +370,7 @@ default values apply).</p> </item> + <marker id="agent_ms_cache_opts"></marker> <tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag> <item> <p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p> @@ -338,6 +378,7 @@ <p>For defaults see the options in <c>mibs_cache_opt()</c>.</p> </item> + <marker id="agent_ms_cache_autogc"></marker> <tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag> <item> <p>Defines if the mib server shall perform cache gc automatically or @@ -346,6 +387,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="agent_ms_cache_age"></marker> <tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag> <item> <p>Defines how old the entries in the cache will be allowed before @@ -355,6 +397,7 @@ <p>Default is <c>10 timutes</c>.</p> </item> + <marker id="agent_ms_cache_gclimit"></marker> <tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag> <item> <p>When performing a GC, this is the max number of cache entries @@ -365,6 +408,7 @@ <p>Default is <c>100</c>.</p> </item> + <marker id="agent_error_report_mod"></marker> <tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag> <item> <p>Defines an error report module, implementing the @@ -374,6 +418,7 @@ <p>Default is <c>snmpa_error_logger</c>.</p> </item> + <marker id="agent_symbolic_store"></marker> <tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag> <item> <p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p> @@ -381,12 +426,15 @@ <p>For defaults see the options in <c>symbolic_store_opt()</c>.</p> </item> + <marker id="agent_target_cache"></marker> <tag><c>target_cache() = [target_cache_opt()]</c></tag> <item> <p><c>target_cache_opt() = {verbosity, verbosity()}</c></p> <p>Defines options specific for the SNMP agent target cache. </p> <p>For defaults see the options in <c>target_cache_opt()</c>.</p> </item> + + <marker id="agent_config"></marker> <tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag> <item> <p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p> @@ -394,11 +442,13 @@ <p>For defaults see the options in <c>agent_config_opt()</c>.</p> </item> + <marker id="agent_config_dir"></marker> <tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP agent configuration files are stored.</p> </item> + <marker id="agent_force_load"></marker> <tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c> the configuration files are re-read @@ -410,14 +460,18 @@ </item> </taglist> + <marker id="manager_opts_and_types"></marker> <p>Manager specific config options and types:</p> <taglist> + <marker id="manager_server"></marker> <tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag> <item> <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p> <p>Specifies the options for the manager server process.</p> <p>Default is <c>silence</c>.</p> </item> + + <marker id="manager_server_timeout"></marker> <tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag> <item> <p>Asynchroneous request cleanup time. For every requests, @@ -438,6 +492,7 @@ <p>Default is <c>30000</c>.</p> </item> + <marker id="manager_config"></marker> <tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag> <item> <p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p> @@ -445,16 +500,19 @@ <p>For defaults see the options in <c>manager_config_opt()</c>.</p> </item> + <marker id="manager_config_dir"></marker> <tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager configuration files are stored.</p> </item> + <marker id="manager_config_db_dir"></marker> <tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag> <item> <p>Defines where the SNMP manager store persistent data.</p> </item> + <marker id="manager_config_repair"></marker> <tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag> <item> <p>Defines the repair option for the persistent database (if @@ -462,6 +520,7 @@ <p>Default is <c>true</c>.</p> </item> + <marker id="manager_config_auto_save"></marker> <tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag> <item> <p>The auto save interval. The table is flushed to disk @@ -469,6 +528,7 @@ <p>Default is <c>5000</c>.</p> </item> + <marker id="manager_irb"></marker> <tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag> <item> <p>This option defines how the manager will handle the sending of @@ -498,6 +558,7 @@ <p>Default is <c>auto</c>.</p> </item> + <marker id="manager_mibs"></marker> <tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag> <item> <p>Specifies a list of MIBs (including path) and defines which MIBs @@ -505,6 +566,7 @@ <p>Default is <c>[]</c>.</p> </item> + <marker id="manager_net_if"></marker> <tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag> <item> <p><c>manager_net_if_opt() = {module, manager_net_if_module()} | @@ -515,6 +577,7 @@ <p>For defaults see the options in <c>manager_net_if_opt()</c>.</p> </item> + <marker id="manager_ni_opts"></marker> <tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_option() = {bind_to, bind_to()} | @@ -528,6 +591,7 @@ <p>For defaults see the options in <c>manager_net_if_option()</c>.</p> </item> + <marker id="manager_ni_module"></marker> <tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface part for the @@ -536,6 +600,7 @@ <p>Default is <c>snmpm_net_if</c>.</p> </item> + <marker id="manager_ni_filter_opts"></marker> <tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag> <item> <p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p> @@ -546,6 +611,7 @@ <c>manager_net_if_filter_option()</c>.</p> </item> + <marker id="manager_ni_filter_module"></marker> <tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag> <item> <p>Module which handles the network interface filter part for the @@ -554,6 +620,7 @@ <p>Default is <c>snmpm_net_if_filter</c>.</p> </item> + <marker id="manager_def_user_module"></marker> <tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag> <item> <p>The module implementing the default user. See the @@ -561,6 +628,7 @@ <p>Default is <c>snmpm_user_default</c>.</p> </item> + <marker id="manager_def_user_data"></marker> <tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag> <item> <p>Data for the default user. Passed to the user when calling @@ -569,8 +637,10 @@ </item> </taglist> + <marker id="common_types"></marker> <p>Common config types:</p> <taglist> + <marker id="restart_type"></marker> <tag><c>restart_type() = permanent | transient | temporary</c></tag> <item> <p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso> @@ -579,6 +649,7 @@ for the manager.</p> </item> + <marker id="db_init_error"></marker> <tag><c>db_init_error() = terminate | create</c></tag> <item> <p>Defines what to do if the agent is unable to open an @@ -588,12 +659,14 @@ <p>Default is <c>terminate</c>.</p> </item> + <marker id="prio"></marker> <tag><c><![CDATA[priority() = atom() <optional>]]></c></tag> <item> <p>Defines the Erlang priority for all SNMP processes.</p> <p>Default is <c>normal</c>.</p> </item> + <marker id="versions"></marker> <tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag> <item> <p><c>version() = v1 | v2 | v3</c></p> @@ -601,6 +674,7 @@ <p>Default is <c>[v1,v2,v3]</c>.</p> </item> + <marker id="verbosity"></marker> <tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag> <item> <p>Verbosity for a SNMP process. This specifies now much debug info @@ -608,6 +682,7 @@ <p>Default is <c>silence</c>.</p> </item> + <marker id="bind_to"></marker> <tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if binds to the IP address. @@ -616,6 +691,7 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="no_reuse"></marker> <tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag> <item> <p>If <c>true</c>, net_if does not specify that the IP @@ -624,17 +700,21 @@ <p>Default is <c>false</c>.</p> </item> + <marker id="recbuf"></marker> <tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag> <item> <p>Receive buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> + + <marker id="sndbuf"></marker> <tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag> <item> <p>Send buffer size. </p> <p>Default value is defined by <c>gen_udp</c>.</p> </item> + <marker id="note_store"></marker> <tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag> <item> <p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p> @@ -642,6 +722,7 @@ <p>For defaults see the options in <c>note_store_opt()</c>.</p> </item> + <marker id="ns_timeout"></marker> <tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag> <item> <p>Note cleanup time. When storing a note in the note store, @@ -649,10 +730,9 @@ process performs a GC to remove the expired note's. Time in milli-seconds.</p> <p>Default is <c>30000</c>.</p> - - <marker id="audit_trail_log"></marker> </item> + <marker id="audit_trail_log"></marker> <tag><c><![CDATA[audit_trail_log() [audit_trail_log_opt()] <optional>]]></c></tag> <item> <p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()} | {seqno, atl_seqno()}</c></p> @@ -663,6 +743,7 @@ <p>If not present, audit trail logging is not used.</p> </item> + <marker id="atl_type"></marker> <tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag> <item> <p>Specifies what type of an audit trail log should be used. @@ -684,6 +765,7 @@ <p>Default is <c>read_write</c>.</p> </item> + <marker id="atl_dir"></marker> <tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag> <item> <p>Specifies where the audit trail log should be stored.</p> @@ -691,6 +773,7 @@ place, this parameter <em>must</em> be defined.</p> </item> + <marker id="atl_size"></marker> <tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag> <item> <p>Specifies the size of the audit @@ -699,6 +782,7 @@ take place, this parameter <em>must</em> be defined.</p> </item> + <marker id="atl_repair"></marker> <tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag> <item> <p>Specifies if and how the audit trail log shall be repaired @@ -710,6 +794,8 @@ analysis.</p> <p>Default is <c>true</c>.</p> </item> + + <marker id="atl_seqno"></marker> <tag><c><![CDATA[atl_seqno() = true | false <optional>]]></c></tag> <item> <p>Specifies if the audit trail log entries will be (sequence) diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml index 27d89ea4e3..2322af28cc 100644 --- a/lib/snmp/doc/src/snmpa.xml +++ b/lib/snmp/doc/src/snmpa.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2004</year><year>2011</year> + <year>2004</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -198,12 +198,18 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} <type> <v>BackupDir = string()</v> <v>Agent = pid() | atom()</v> + <v>Reason = backup_in_progress | term()</v> </type> <desc> <p>Backup persistent/permanent data handled by the agent (such as local-db, mib-data and vacm). </p> <p>Data stored by mnesia is not handled. </p> <p>BackupDir cannot be identical to DbDir. </p> + <p>Simultaneous backup calls are <em>not</em> allowed. + That is, two different processes cannot simultaneously + successfully call this function. One of them will be first, + and succeed. The second will fail with the error reason + <c>backup_in_progress</c>. </p> <marker id="info"></marker> </desc> @@ -217,13 +223,13 @@ notification_delivery_info() = #snmpa_notification_delivery_info{} </type> <desc> <p>Returns a list (a dictionary) containing information about - the agent. Information includes loaded MIBs, registered - sub-agents, some information about the memory allocation. </p> - <p>As of version 4.4 the format of the info has been changed. - To convert the info to the old format, call the - <seealso marker="#old_info_format">old_info_format</seealso> - function. </p> - + the agent. Information includes loaded MIBs, registered + sub-agents, some information about the memory allocation. </p> + <p>As of version 4.4 the format of the info has been changed. + To convert the info to the old format, call the + <seealso marker="#old_info_format">old_info_format</seealso> + function. </p> + <marker id="old_info_format"></marker> </desc> </func> diff --git a/lib/snmp/src/agent/depend.mk b/lib/snmp/src/agent/depend.mk index bc39e1fa35..078ef15821 100644 --- a/lib/snmp/src/agent/depend.mk +++ b/lib/snmp/src/agent/depend.mk @@ -52,6 +52,7 @@ $(EBIN)/snmpa_acm.$(EMULATOR): \ $(EBIN)/snmpa_agent.$(EMULATOR): \ snmpa_agent.erl \ + snmpa_internal.hrl \ ../misc/snmp_debug.hrl \ ../misc/snmp_verbosity.hrl \ ../../include/snmp_types.hrl @@ -136,6 +137,7 @@ $(EBIN)/snmpa_set_lib.$(EMULATOR): \ $(EBIN)/snmpa_supervisor.$(EMULATOR): \ snmpa_supervisor.erl \ + snmpa_internal.hrl \ ../misc/snmp_debug.hrl \ ../misc/snmp_verbosity.hrl diff --git a/lib/snmp/src/agent/snmp_generic_mnesia.erl b/lib/snmp/src/agent/snmp_generic_mnesia.erl index a73aad5b33..ce42af404b 100644 --- a/lib/snmp/src/agent/snmp_generic_mnesia.erl +++ b/lib/snmp/src/agent/snmp_generic_mnesia.erl @@ -121,7 +121,7 @@ table_func(set, RowIndex, Cols, Name) -> fun() -> snmp_generic:table_set_row( {Name, mnesia}, nofunc, - {snmp_generic_mnesia, table_try_make_consistent}, + fun table_try_make_consistent/2, RowIndex, Cols) end) of {atomic, Value} -> @@ -368,7 +368,8 @@ table_set_elements(Name, RowIndex, Cols) -> _ -> false end. table_set_elements(Name, RowIndex, Cols, ConsFunc) -> - #table_info{index_types = Indexes, first_own_index = FirstOwnIndex} = + #table_info{index_types = Indexes, + first_own_index = FirstOwnIndex} = snmp_generic:table_info(Name), AddCol = if FirstOwnIndex == 0 -> 2; diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl index 60bd3e0912..a45db89c09 100644 --- a/lib/snmp/src/agent/snmp_target_mib.erl +++ b/lib/snmp/src/agent/snmp_target_mib.erl @@ -46,8 +46,14 @@ %% Column not accessible via SNMP - needed when the agent sends informs -define(snmpTargetAddrEngineId, 10). %% Extra comlumns for the augmented table snmpTargetAddrExtTable --define(snmpTargetAddrTMask, 11). --define(snmpTargetAddrMMS, 12). +-define(snmpTargetAddrTMask, 11). +-define(snmpTargetAddrMMS, 12). + +-ifdef(snmp_extended_verbosity). +-define(vt(F,A), ?vtrace(F, A)). +-else. +-define(vt(_F, _A), ok). +-endif. %%----------------------------------------------------------------- @@ -459,10 +465,16 @@ get_target_addrs() -> get_target_addrs(Key, {Tab, _} = TabDb, Acc) -> + ?vt("get_target_addrs -> entry with" + "~n Key: ~p", [Key]), case table_next(Tab, Key) of endOfTable -> + ?vt("get_target_addrs -> endOfTable when" + "~n Acc: ~p", [Acc]), Acc; NextKey -> + ?vt("get_target_addrs -> next ok: " + "~n NextKey: ~p", [NextKey]), case get_target_addr(TabDb, NextKey) of {ok, Targ} -> get_target_addrs(NextKey, TabDb, [Targ| Acc]); diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl index 37f6dd3f26..2cee91b081 100644 --- a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl +++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -203,18 +203,16 @@ init_sec2group_table([Row | T]) -> init_sec2group_table(T); init_sec2group_table([]) -> true. -init_access_table([{GN, Prefix, Model, Level, Row} | T]) -> -%% ?vtrace("init access table: " -%% "~n GN: ~p" -%% "~n Prefix: ~p" -%% "~n Model: ~p" -%% "~n Level: ~p" -%% "~n Row: ~p",[GN, Prefix, Model, Level, Row]), - Key = [length(GN) | GN] ++ [length(Prefix) | Prefix] ++ [Model, Level], - snmpa_vacm:insert([{Key, Row}], false), - init_access_table(T); -init_access_table([]) -> - snmpa_vacm:dump_table(). +make_access_key(GN, Prefix, Model, Level) -> + [length(GN) | GN] ++ [length(Prefix) | Prefix] ++ [Model, Level]. + +make_access_entry({GN, Prefix, Model, Level, Row}) -> + Key = make_access_key(GN, Prefix, Model, Level), + {Key, Row}. + +init_access_table(TableData) -> + TableData2 = [make_access_entry(E) || E <- TableData], + snmpa_vacm:insert(TableData2, true). init_view_table([Row | T]) -> %% ?vtrace("init view table: " @@ -276,10 +274,7 @@ add_access(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) -> Match, RV, WV, NV}, case (catch check_vacm(Access)) of {ok, {vacmAccess, {GN, Pref, SM, SL, Row}}} -> - Key1 = [length(GN) | GN], - Key2 = [length(Pref) | Pref], - Key3 = [SM, SL], - Key = Key1 ++ Key2 ++ Key3, + Key = make_access_key(GN, Pref, SM, SL), snmpa_vacm:insert([{Key, Row}], false), snmpa_agent:invalidate_ca_cache(), {ok, Key}; diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl index 50b169e4e7..c400aaddf7 100644 --- a/lib/snmp/src/agent/snmpa.erl +++ b/lib/snmp/src/agent/snmpa.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -547,7 +547,7 @@ update_mibs_cache_age(Agent, Age) -> update_mibs_cache_gclimit(GcLimit) -> - update_mibs_cache_age(snmp_master_agent, GcLimit). + update_mibs_cache_gclimit(snmp_master_agent, GcLimit). update_mibs_cache_gclimit(Agent, GcLimit) -> snmpa_agent:update_mibs_cache_gclimit(Agent, GcLimit). diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index 46c634969d..9cc986cf47 100644 --- a/lib/snmp/src/agent/snmpa_agent.erl +++ b/lib/snmp/src/agent/snmpa_agent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -68,8 +68,11 @@ %% Internal exports -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, tr_var/2, tr_varbind/1, - handle_pdu/7, worker/2, worker_loop/1, + handle_pdu/8, worker/2, worker_loop/1, do_send_trap/7, do_send_trap/8]). +%% <BACKWARD-COMPAT> +-export([handle_pdu/7]). +%% </BACKWARD-COMPAT> -include("snmpa_internal.hrl"). @@ -87,7 +90,6 @@ -define(DISCO_TERMINATING_TRIGGER_USERNAME, ""). - -ifdef(snmp_debug). -define(GS_START_LINK3(Prio, Parent, Ref, Opts), gen_server:start_link(?MODULE, [Prio, Parent, Ref, Opts], @@ -103,13 +105,49 @@ gen_server:start_link({local, Name}, ?MODULE, [Prio, Parent, Ref, Opts],[])). -endif. - + +%% Increment this whenever a change is made to the worker interface +-define(WORKER_INTERFACE_VERSION, 1). + +%% -- Utility macros for creating worker commands -- +-define(mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra), + #wrequest{cmd = handle_pdu, + info = [{vsn, Vsn}, + {pdu, Pdu}, + {pdu_ms, PduMS}, + {acm_data, ACMData}, + {addr, Address}, + {gb_max_vbs, GbMaxVBs}, + {extra, Extra}]}). +-define(mk_send_trap_wreq(TrapRec, NotifyName, ContextName, + Recv, Vbs, LocalEngineID, Extra), + #wrequest{cmd = send_trap, + info = [{trap_rec, TrapRec}, + {notify_name, NotifyName}, + {context_name, ContextName}, + {receiver, Recv}, + {varbinds, Vbs}, + {local_engine_id, LocalEngineID}, + {extra, Extra}]}). +-define(mk_terminate_wreq(), #wrequest{cmd = terminate, info = []}). +-define(mk_verbosity_wreq(V), #wrequest{cmd = verbosity, + info = [{verbosity, V}]}). + -record(notification_filter, {id, mod, data}). -record(disco, {from, rec, sender, target, engine_id, sec_level, ctx, ivbs, stage, handler, extra}). +%% This record is used when sending requests to the worker processes +-record(wrequest, + { + version = ?WORKER_INTERFACE_VERSION, + cmd, + info + } + ). + %%----------------------------------------------------------------- %% The agent is multi-threaded, i.e. each request is handled @@ -142,7 +180,8 @@ net_if_mod, backup, disco, - mibs_cache_request}). + mibs_cache_request, + gb_max_vbs}). %%%----------------------------------------------------------------- @@ -330,6 +369,8 @@ do_init(Prio, Parent, Ref, Options) -> MultiT = get_multi_threaded(Options), Vsns = get_versions(Options), + GbMaxVbs = get_gb_max_vbs(Options), + NS = start_note_store(Prio, Ref, Options), {Type, NetIfPid, NetIfMod} = start_net_if(Parent, Prio, Ref, Vsns, NS, Options), @@ -348,7 +389,8 @@ do_init(Prio, Parent, Ref, Options) -> ref = Ref, vsns = Vsns, note_store = NS, - net_if_mod = NetIfMod}}. + net_if_mod = NetIfMod, + gb_max_vbs = GbMaxVbs}}. start_note_store(Prio, Ref, Options) -> @@ -410,7 +452,8 @@ start_net_if(Parent, _Prio, _Ref, _Vsns, _NoteStore, _Options) start_mib_server(Prio, Ref, Mibs, Options) -> ?vdebug("start_mib_server -> with Prio: ~p", [Prio]), MibStorage = get_mib_storage(Options), - MibsOpts = [{mib_storage, MibStorage}|get_option(mib_server, Options, [])], + MibsOpts = [{mib_storage, MibStorage} | + get_option(mib_server, Options, [])], ?vtrace("start_mib_server -> " "~n Mibs: ~p" @@ -751,7 +794,8 @@ handle_info({snmp_pdu, Vsn, Pdu, PduMS, ACMData, Address, Extra}, S) -> ?vdebug("handle_info(snmp_pdu) -> entry with" "~n Vsn: ~p" "~n Pdu: ~p" - "~n Address: ~p", [Vsn, Pdu, Address]), + "~n Address: ~p" + "~n Extra: ~p", [Vsn, Pdu, Address, Extra]), NewS = handle_snmp_pdu(is_valid_pdu_type(Pdu#pdu.type), Vsn, Pdu, PduMS, ACMData, Address, Extra, S), @@ -934,6 +978,7 @@ handle_info({'EXIT', Pid, Reason}, S) -> end, {noreply, S} end; + handle_info({'DOWN', Ref, process, Pid, {mibs_cache_reply, Reply}}, #state{mibs_cache_request = {Pid, Ref, From}} = S) -> ?vlog("reply from the mibs cache request handler (~p): ~n~p", @@ -1075,7 +1120,7 @@ handle_call({subagent_get_next, MibView, Varbinds, PduData}, _From, S) -> "~n PduData: ~p", [MibView,Varbinds,PduData]), put_pdu_data(PduData), - {reply, do_get_next(MibView, Varbinds), S}; + {reply, do_get_next(MibView, Varbinds, infinity), S}; handle_call({subagent_set, Arguments, PduData}, _From, S) -> ?vlog("[handle_call] subagent set:" "~n Arguments: ~p" @@ -1116,7 +1161,7 @@ handle_call({get_next, Vars, Context}, _From, S) -> ?vdebug("Varbinds: ~p",[Varbinds]), MibView = snmpa_acm:get_root_mib_view(), Reply = - case do_get_next(MibView, Varbinds) of + case do_get_next(MibView, Varbinds, infinity) of {noError, 0, NewVarbinds} -> Vbs = lists:keysort(#varbind.org_index, NewVarbinds), [{Oid,Val} || #varbind{oid = Oid, value = Val} <- Vbs]; @@ -1217,7 +1262,8 @@ handle_call(info, _From, S) -> handle_call(get_net_if, _From, S) -> {reply, get(net_if), S}; -handle_call({backup, BackupDir}, From, S) -> +%% Only accept a backup request if there is none already in progress +handle_call({backup, BackupDir}, From, #state{backup = undefined} = S) -> ?vlog("backup: ~p", [BackupDir]), Pid = self(), V = get(verbosity), @@ -1234,7 +1280,11 @@ handle_call({backup, BackupDir}, From, S) -> end), ?vtrace("backup server: ~p", [BackupServer]), {noreply, S#state{backup = {BackupServer, From}}}; - + +handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) -> + ?vinfo("backup already in progress: ~p", [Backup]), + {reply, {error, backup_in_progress}, S}; + handle_call(dump_mibs, _From, S) -> Reply = snmpa_mib:dump(get(mibserver)), {reply, Reply, S}; @@ -1283,27 +1333,27 @@ handle_call({me_of, Oid}, _From, S) -> {reply, Reply, S}; handle_call(get_log_type, _From, S) -> - ?vlog("get_log_type", []), + ?vlog("handle_call(get_log_type) -> entry with", []), Reply = handle_get_log_type(S), {reply, Reply, S}; handle_call({set_log_type, NewType}, _From, S) -> - ?vlog("set_log_type -> " + ?vlog("handle_call(set_log_type) -> entry with" "~n NewType: ~p", [NewType]), Reply = handle_set_log_type(S, NewType), {reply, Reply, S}; handle_call(get_request_limit, _From, S) -> - ?vlog("get_request_limit", []), + ?vlog("handle_call(get_request_limit) -> entry with", []), Reply = handle_get_request_limit(S), {reply, Reply, S}; handle_call({set_request_limit, NewLimit}, _From, S) -> - ?vlog("set_request_limit -> " + ?vlog("handle_call(set_request_limit) -> entry with" "~n NewLimit: ~p", [NewLimit]), Reply = handle_set_request_limit(S, NewLimit), {reply, Reply, S}; - + handle_call(stop, _From, S) -> {stop, normal, ok, S}; @@ -1312,15 +1362,15 @@ handle_call(Req, _From, S) -> Reply = {error, {unknown, Req}}, {reply, Reply, S}. -handle_cast({verbosity,Verbosity}, S) -> - ?vlog("verbosity: ~p -> ~p",[get(verbosity),Verbosity]), +handle_cast({verbosity, Verbosity}, S) -> + ?vlog("verbosity: ~p -> ~p",[get(verbosity), Verbosity]), put(verbosity,snmp_verbosity:validate(Verbosity)), case S#state.worker of - Pid when is_pid(Pid) -> Pid ! {verbosity,Verbosity}; + Pid when is_pid(Pid) -> Pid ! ?mk_verbosity_wreq(Verbosity); _ -> ok end, case S#state.set_worker of - Pid2 when is_pid(Pid2) -> Pid2 ! {verbosity,Verbosity}; + Pid2 when is_pid(Pid2) -> Pid2 ! ?mk_verbosity_wreq(Verbosity); _ -> ok end, {noreply, S}; @@ -1407,13 +1457,80 @@ handle_mibs_cache_request(MibServer, Req) -> %% Downgrade %% -%% code_change({down, _Vsn}, S, downgrade_to_pre_4_13) -> -%% {ok, S2}; +code_change({down, _Vsn}, S1, downgrade_to_pre_4_17_3) -> + #state{type = Type, + parent = Parent, + worker = Worker, + worker_state = WorkerState, + set_worker = SetWorker, + multi_threaded = MT, + ref = Ref, + vsns = Vsns, + nfilters = NF, + note_store = NoteStore, + mib_server = MS, + net_if = NetIf, + net_if_mod = NetIfMod, + backup = Backup, + disco = Disco, + mibs_cache_request = MCR} = S1, + S2 = {state, + type = Type, + parent = Parent, + worker = Worker, + worker_state = WorkerState, + set_worker = SetWorker, + multi_threaded = MT, + ref = Ref, + vsns = Vsns, + nfilters = NF, + note_store = NoteStore, + mib_server = MS, + net_if = NetIf, + net_if_mod = NetIfMod, + backup = Backup, + disco = Disco, + mibs_cache_request = MCR}, + {ok, S2}; %% Upgrade %% -%% code_change(_Vsn, S, upgrade_from_pre_4_13) -> -%% {ok, S2}; +code_change(_Vsn, S1, upgrade_from_pre_4_17_3) -> + {state, + type = Type, + parent = Parent, + worker = Worker, + worker_state = WorkerState, + set_worker = SetWorker, + multi_threaded = MT, + ref = Ref, + vsns = Vsns, + nfilters = NF, + note_store = NoteStore, + mib_server = MS, + net_if = NetIf, + net_if_mod = NetIfMod, + backup = Backup, + disco = Disco, + mibs_cache_request = MCR} = S1, + S2 = #state{type = Type, + parent = Parent, + worker = Worker, + worker_state = WorkerState, + set_worker = SetWorker, + multi_threaded = MT, + ref = Ref, + vsns = Vsns, + nfilters = NF, + note_store = NoteStore, + mib_server = MS, + net_if = NetIf, + net_if_mod = NetIfMod, + backup = Backup, + disco = Disco, + mibs_cache_request = MCR, + gb_max_vbs = ?DEFAULT_GB_MAX_VBS}, + {ok, S2}; code_change(_Vsn, S, _Extra) -> {ok, S}. @@ -1453,7 +1570,7 @@ worker_start(Dict) -> %% worker_stop(Pid, infinity). worker_stop(Pid, Timeout) when is_pid(Pid) -> - Pid ! terminate, + Pid ! ?mk_terminate_wreq(), receive {'EXIT', Pid, normal} -> ok @@ -1590,9 +1707,11 @@ invalidate_ca_cache() -> %% %%----------------------------------------------------------------- -spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra) -> +%% This functions spawns a temporary worker process, +%% that evaluates one request and then silently exits. +spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra) -> Dict = get(), - Args = [Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict], + Args = [Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra, Dict], proc_lib:spawn_link(?MODULE, handle_pdu, Args). spawn_trap_thread(TrapRec, NotifyName, ContextName, Recv, Vbs, @@ -1610,7 +1729,7 @@ do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo, Dict) -> lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict), - put(sname,trap_sender_short_name(get(sname))), + put(sname, trap_sender_short_name(get(sname))), ?vlog("starting",[]), snmpa_trap:send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo, get(net_if)). @@ -1622,58 +1741,122 @@ worker(Master, Dict) -> worker_loop(Master). worker_loop(Master) -> - receive - {Vsn, Pdu, PduMS, ACMData, Address, Extra} -> - ?vtrace("worker_loop -> received request", []), - handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra), - Master ! worker_available; - - %% We don't trap EXITs! - {TrapRec, NotifyName, ContextName, Recv, Vbs} -> - ?vtrace("worker_loop -> send trap:" - "~n ~p", [TrapRec]), - snmpa_trap:send_trap(TrapRec, NotifyName, - ContextName, Recv, Vbs, - ?DEFAULT_NOTIF_EXTRA_INFO, - get(net_if)), - Master ! worker_available; - - %% We don't trap EXITs! - {send_trap, - TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID} -> - ?vtrace("worker_loop -> send trap:" - "~n ~p", [TrapRec]), - snmpa_trap:send_trap(TrapRec, NotifyName, - ContextName, Recv, Vbs, - LocalEngineID, ?DEFAULT_NOTIF_EXTRA_INFO, - get(net_if)), - Master ! worker_available; - - {send_trap, - TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo} -> - ?vtrace("worker_loop -> send trap:" - "~n ~p", [TrapRec]), - snmpa_trap:send_trap(TrapRec, NotifyName, - ContextName, Recv, Vbs, - LocalEngineID, ExtraInfo, - get(net_if)), - Master ! worker_available; - - {verbosity, Verbosity} -> - put(verbosity,snmp_verbosity:validate(Verbosity)); - - terminate -> - exit(normal); - - _X -> - %% ignore - ok - - after 30000 -> - %% This is to assure that the worker process leaves a - %% possibly old version of this module. - ok - end, + Res = + receive + #wrequest{cmd = handle_pdu, + info = Info} = Req -> + ?vtrace("worker_loop -> received handle_pdu request with" + "~n Info: ~p", [Info]), + Vsn = proplists:get_value(vsn, Info), + Pdu = proplists:get_value(pdu, Info), + PduMS = proplists:get_value(pdu_ms, Info), + ACMData = proplists:get_value(acm_data, Info), + Address = proplists:get_value(addr, Info), + GbMaxVBs = proplists:get_value(gb_max_vbs, Info), + Extra = proplists:get_value(extra, Info), + HandlePduRes = + try + begin + handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, + GbMaxVBs, Extra) + end + catch + T:E -> + exit({worker_crash, Req, T, E, + erlang:get_stacktrace()}) + end, + Master ! worker_available, + HandlePduRes; % For debugging... + + + #wrequest{cmd = send_trap, + info = Info} = Req -> + ?vtrace("worker_loop -> received send_trap request with" + "~n Info: ~p", [Info]), + TrapRec = proplists:get_value(trap_rec, Info), + NotifyName = proplists:get_value(notify_name, Info), + ContextName = proplists:get_value(context_name, Info), + Recv = proplists:get_value(receiver, Info), + Vbs = proplists:get_value(varbinds, Info), + LocalEngineID = proplists:get_value(local_engine_id, Info), + Extra = proplists:get_value(extra, Info), + SendTrapRes = + try + begin + snmpa_trap:send_trap(TrapRec, NotifyName, + ContextName, Recv, Vbs, + LocalEngineID, Extra, + get(net_if)) + end + catch + T:E -> + exit({worker_crash, Req, T, E, + erlang:get_stacktrace()}) + end, + Master ! worker_available, + SendTrapRes; % For debugging... + + + #wrequest{cmd = verbosity, + info = Info} -> + Verbosity = proplists:get_value(verbosity, Info), + put(verbosity, snmp_verbosity:validate(Verbosity)); + + + #wrequest{cmd = terminate} -> + ?vtrace("worker_loop -> received terminate request", []), + exit(normal); + + + %% ************************************************************* + %% + %% Kept for backward compatibillity reasons + %% + %% ************************************************************* + + {Vsn, Pdu, PduMS, ACMData, Address, Extra} -> + ?vtrace("worker_loop -> received request", []), + handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, + ?DEFAULT_GB_MAX_VBS, Extra), + Master ! worker_available; + + %% We don't trap exits! + {TrapRec, NotifyName, ContextName, Recv, Vbs} -> + ?vtrace("worker_loop -> send trap:" + "~n ~p", [TrapRec]), + snmpa_trap:send_trap(TrapRec, NotifyName, + ContextName, Recv, Vbs, get(net_if)), + Master ! worker_available; + + %% We don't trap exits! + {send_trap, + TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, + ExtraInfo} -> + ?vtrace("worker_loop -> send trap:" + "~n ~p", [TrapRec]), + snmpa_trap:send_trap(TrapRec, NotifyName, + ContextName, Recv, Vbs, + LocalEngineID, ExtraInfo, + get(net_if)), + Master ! worker_available; + + {verbosity, Verbosity} -> + put(verbosity, snmp_verbosity:validate(Verbosity)); + + terminate -> + exit(normal); + + _X -> + %% ignore + ignore_unknown + + after 30000 -> + %% This is to assure that the worker process leaves a + %% possibly old version of this module. + ok + end, + ?vtrace("worker_loop -> wrap with" + "~n ~p", [Res]), ?MODULE:worker_loop(Master). @@ -1681,42 +1864,52 @@ worker_loop(Master) -> %%----------------------------------------------------------------- handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra, - #state{multi_threaded = false} = S) -> + #state{multi_threaded = false, + gb_max_vbs = GbMaxVBs} = S) -> ?vtrace("handle_snmp_pdu -> single-thread agent",[]), - handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra), + handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra), S; handle_snmp_pdu(true, Vsn, #pdu{type = 'set-request'} = Pdu, PduMS, ACMData, Address, Extra, #state{set_worker = Worker} = S) -> ?vtrace("handle_snmp_pdu -> multi-thread agent: " "send set-request to main worker",[]), - Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra}, + WRequest = ?mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, infinity, Extra), + Worker ! WRequest, S#state{worker_state = busy}; handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra, - #state{worker_state = busy} = S) -> + #state{worker_state = busy, + gb_max_vbs = GbMaxVBs} = S) -> ?vtrace("handle_snmp_pdu -> multi-thread agent: " "main worker busy - create new worker",[]), - spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra), + spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra), S; handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra, - #state{worker = Worker} = S) -> + #state{worker = Worker, + gb_max_vbs = GbMaxVBs} = S) -> ?vtrace("handle_snmp_pdu -> multi-thread agent: " "send to main worker",[]), - Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra}, + WRequest = ?mk_pdu_wreq(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra), + Worker ! WRequest, S#state{worker_state = busy}; handle_snmp_pdu(_, _Vsn, _Pdu, _PduMS, _ACMData, _Address, _Extra, S) -> S. %% Called via the spawn_thread function +%% <BACKWARD-COMPAT> handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict) -> + handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, ?DEFAULT_GB_MAX_VBS, Extra, + Dict). +%% </BACKWARD-COMPAT> +handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra, Dict) -> lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict), put(sname, pdu_handler_short_name(get(sname))), ?vlog("new worker starting",[]), - handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra). + handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra). -handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) -> +handle_pdu2(Vsn, Pdu, PduMS, ACMData, Address, GbMaxVBs, Extra) -> %% OTP-3324 AuthMod = get(auth_module), case AuthMod:init_check_access(Pdu, ACMData) of @@ -1725,7 +1918,8 @@ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) -> "~n MibView: ~p" "~n ContextName: ~p", [MibView, ContextName]), AgentData = cheat(ACMData, Address, ContextName), - do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData, Extra); + do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData, + GbMaxVBs, Extra); {error, Reason} -> ?vlog("handle_pdu -> error:" "~n Reason: ~p", [Reason]), @@ -1739,16 +1933,19 @@ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) -> end. do_handle_pdu(MibView, Vsn, Pdu, PduMS, - ACMData, {Community, Address, ContextName}, Extra) -> + ACMData, {Community, Address, ContextName}, + GbMaxVBs, Extra) -> put(net_if_data, Extra), + RePdu = process_msg(MibView, Vsn, Pdu, PduMS, Community, - Address, ContextName), + Address, ContextName, GbMaxVBs), ?vtrace("do_handle_pdu -> processed:" "~n RePdu: ~p", [RePdu]), - get(net_if) ! {snmp_response, Vsn, RePdu, - RePdu#pdu.type, ACMData, Address, Extra}. + NetIf = get(net_if), + NetIf ! {snmp_response, Vsn, RePdu, + RePdu#pdu.type, ACMData, Address, Extra}. handle_acm_error(Vsn, Reason, Pdu, ACMData, Address, Extra) -> @@ -1949,9 +2146,9 @@ do_handle_send_trap(S, TrapRec, NotifyName, ContextName, Recv, Varbinds, master_agent -> %% Send to main worker ?vtrace("do_handle_send_trap -> send to main worker",[]), - S#state.worker ! {send_trap, - TrapRec, NotifyName, ContextName, Recv, Vbs, - LocalEngineID, ExtraInfo}, + S#state.worker ! ?mk_send_trap_wreq(TrapRec, NotifyName, + ContextName, Recv, Vbs, + LocalEngineID, ExtraInfo), {ok, S#state{worker_state = busy}} end. @@ -2291,17 +2488,18 @@ handle_mib_of(MibServer, Oid) -> %% Func: process_msg/7 %% Returns: RePdu %%----------------------------------------------------------------- -process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName) -> +process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName, + GbMaxVBs) -> #pdu{request_id = ReqId} = Pdu, put(snmp_address, {tuple_to_list(Ip), Udp}), put(snmp_request_id, ReqId), put(snmp_community, Community), put(snmp_context, ContextName), ?vtrace("process ~p",[Pdu#pdu.type]), - process_pdu(Pdu, PduMS, Vsn, MibView). + process_pdu(Pdu, PduMS, Vsn, MibView, GbMaxVBs). process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs}, - _PduMS, Vsn, MibView) -> + _PduMS, Vsn, MibView, _GbMaxVBs) -> ?vtrace("get ~p",[ReqId]), Res = get_err(do_get(MibView, Vbs, false)), ?vtrace("get result: " @@ -2322,12 +2520,12 @@ process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs}, make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds); process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs}, - _PduMS, Vsn, MibView) -> + _PduMS, Vsn, MibView, _GbMaxVBs) -> ?vtrace("process get-next-request -> entry with" "~n ReqId: ~p" "~n Vbs: ~p" "~n MibView: ~p",[ReqId, Vbs, MibView]), - Res = get_err(do_get_next(MibView, Vbs)), + Res = get_err(do_get_next(MibView, Vbs, infinity)), ?vtrace("get-next result: " "~n ~p",[Res]), {ErrStatus, ErrIndex, ResVarbinds} = @@ -2344,11 +2542,15 @@ process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs}, "~n ~p",[ResponseVarbinds]), make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds); -process_pdu(#pdu{type = 'get-bulk-request',request_id = ReqId,varbinds = Vbs, - error_status = NonRepeaters, error_index = MaxRepetitions}, - PduMS, _Vsn, MibView)-> +process_pdu(#pdu{type = 'get-bulk-request', + request_id = ReqId, + varbinds = Vbs, + error_status = NonRepeaters, + error_index = MaxRepetitions}, + PduMS, _Vsn, MibView, GbMaxVBs) -> {ErrStatus, ErrIndex, ResponseVarbinds} = - get_err(do_get_bulk(MibView,NonRepeaters,MaxRepetitions,PduMS,Vbs)), + get_err(do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Vbs, + GbMaxVBs)), ?vtrace("get-bulk final result: " "~n Error status: ~p" "~n Error index: ~p" @@ -2357,7 +2559,7 @@ process_pdu(#pdu{type = 'get-bulk-request',request_id = ReqId,varbinds = Vbs, make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds); process_pdu(#pdu{type = 'set-request', request_id = ReqId, varbinds = Vbs}, - _PduMS, Vsn, MibView)-> + _PduMS, Vsn, MibView, _GbMaxVbs)-> Res = do_set(MibView, Vbs), ?vtrace("set result: " "~n ~p",[Res]), @@ -2414,7 +2616,8 @@ validate_next_v1_2([Vb | _Vbs], _MibView, _Res) {noSuchName, Vb#varbind.org_index}; validate_next_v1_2([Vb | Vbs], MibView, Res) when Vb#varbind.variabletype =:= 'Counter64' -> - case validate_next_v1(do_get_next(MibView, [mk_next_oid(Vb)]), MibView) of + case validate_next_v1( + do_get_next(MibView, [mk_next_oid(Vb)], infinity), MibView) of {noError, 0, [NVb]} -> validate_next_v1_2(Vbs, MibView, [NVb | Res]); {Error, Index, _OrgVb} -> @@ -2887,59 +3090,97 @@ validate_tab_res(_TooMany, [], Mfa, _Res, I) -> %% that this really matters, since many nexts across the same %% subagent must be considered to be very rare. %%----------------------------------------------------------------- -do_get_next(MibView, UnsortedVarbinds) -> - SortedVarbinds = oid_sort_varbindlist(UnsortedVarbinds), - next_loop_varbinds([], SortedVarbinds, MibView, [], []). -oid_sort_varbindlist(Vbs) -> +%% It may be a bit agressive to check this already, +%% but since it is a security measure, it makes sense. +do_get_next(_MibView, UnsortedVarbinds, GbMaxVBs) + when (is_integer(GbMaxVBs) andalso (length(UnsortedVarbinds) > GbMaxVBs)) -> + {tooBig, 0, []}; % What is the correct index in this case? +do_get_next(MibView, UnsortedVBs, GbMaxVBs) -> + ?vt("do_get_next -> entry when" + "~n MibView: ~p" + "~n UnsortedVBs: ~p", [MibView, UnsortedVBs]), + SortedVBs = oid_sort_vbs(UnsortedVBs), + ?vt("do_get_next -> " + "~n SortedVBs: ~p", [SortedVBs]), + next_loop_varbinds([], SortedVBs, MibView, [], [], GbMaxVBs). + +oid_sort_vbs(Vbs) -> lists:keysort(#varbind.oid, Vbs). +next_loop_varbinds(_, Vbs, _MibView, Res, _LAVb, GbMaxVBs) + when (is_integer(GbMaxVBs) andalso + ((length(Vbs) + length(Res)) > GbMaxVBs)) -> + {tooBig, 0, []}; % What is the correct index in this case? + %% LAVb is Last Accessible Vb -next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb) -> +next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds -> entry when" "~n Vb: ~p" "~n MibView: ~p", [Vb, MibView]), case varbind_next(Vb, MibView) of endOfMibView -> + ?vt("next_loop_varbind -> endOfMibView", []), RVb = if LAVb =:= [] -> Vb; true -> LAVb end, NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView}, - next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []); + next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], GbMaxVBs); + {variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso (ME#me.access =/= 'write-only') andalso (ME#me.access =/= 'accessible-for-notify')) -> + ?vt("next_loop_varbind -> variable: " + "~n ME: ~p" + "~n VarOid: ~p", [ME, VarOid]), case try_get_instance(Vb, ME) of {value, noValue, _NoSuchSomething} -> + ?vt("next_loop_varbind -> noValue", []), %% Try next one - NewVb = Vb#varbind{oid = VarOid, value = 'NULL'}, - next_loop_varbinds([], [NewVb | Vbs], MibView, Res, []); + NewVb = Vb#varbind{oid = VarOid, + value = 'NULL'}, + next_loop_varbinds([], [NewVb | Vbs], MibView, Res, [], + GbMaxVBs); {value, Type, Value} -> - NewVb = Vb#varbind{oid = VarOid, variabletype = Type, - value = Value}, - next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []); + ?vt("next_loop_varbind -> value" + "~n Type: ~p" + "~n Value: ~p", [Type, Value]), + NewVb = Vb#varbind{oid = VarOid, + variabletype = Type, + value = Value}, + next_loop_varbinds([], Vbs, MibView, [NewVb | Res], [], + GbMaxVBs); {error, ErrorStatus} -> ?vdebug("next loop varbinds:" "~n ErrorStatus: ~p",[ErrorStatus]), {ErrorStatus, Vb#varbind.org_index, []} end; {variable, _ME, VarOid} -> + ?vt("next_loop_varbind -> variable: " + "~n VarOid: ~p", [VarOid]), RVb = if LAVb =:= [] -> Vb; true -> LAVb end, NewVb = Vb#varbind{oid = VarOid, value = 'NULL'}, - next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb); + next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb, GbMaxVBs); {table, TableOid, TableRestOid, ME} -> + ?vt("next_loop_varbind -> table: " + "~n TableOid: ~p" + "~n TableRestOid: ~p" + "~n ME: ~p", [TableOid, TableRestOid, ME]), next_loop_varbinds({table, TableOid, ME, [{tab_oid(TableRestOid), Vb}]}, - Vbs, MibView, Res, []); + Vbs, MibView, Res, [], GbMaxVBs); {subagent, SubAgentPid, SAOid} -> + ?vt("next_loop_varbind -> subagent: " + "~n SubAgentPid: ~p" + "~n SAOid: ~p", [SubAgentPid, SAOid]), NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'}, next_loop_varbinds({subagent, SubAgentPid, SAOid, [NewVb]}, - Vbs, MibView, Res, []) + Vbs, MibView, Res, [], GbMaxVBs) end; next_loop_varbinds({table, TableOid, ME, TabOids}, - [Vb | Vbs], MibView, Res, _LAVb) -> + [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds(table) -> entry with" "~n TableOid: ~p" "~n Vb: ~p", [TableOid, Vb]), @@ -2947,13 +3188,14 @@ next_loop_varbinds({table, TableOid, ME, TabOids}, {table, TableOid, TableRestOid, _ME} -> next_loop_varbinds({table, TableOid, ME, [{tab_oid(TableRestOid), Vb} | TabOids]}, - Vbs, MibView, Res, []); + Vbs, MibView, Res, [], GbMaxVBs); _ -> case get_next_table(ME, TableOid, TabOids, MibView) of {ok, TabRes, TabEndOfTabVbs} -> NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]), NewRes = lists:append(TabRes, Res), - next_loop_varbinds([], NewVbs, MibView, NewRes, []); + next_loop_varbinds([], NewVbs, MibView, NewRes, [], + GbMaxVBs); {ErrorStatus, OrgIndex} -> ?vdebug("next loop varbinds: next varbind" "~n ErrorStatus: ~p" @@ -2963,7 +3205,7 @@ next_loop_varbinds({table, TableOid, ME, TabOids}, end end; next_loop_varbinds({table, TableOid, ME, TabOids}, - [], MibView, Res, _LAVb) -> + [], MibView, Res, _LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds(table) -> entry with" "~n TableOid: ~p", [TableOid]), case get_next_table(ME, TableOid, TabOids, MibView) of @@ -2972,7 +3214,8 @@ next_loop_varbinds({table, TableOid, ME, TabOids}, "~n TabRes: ~p" "~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]), NewRes = lists:append(TabRes, Res), - next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, []); + next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, [], + GbMaxVBs); {ErrorStatus, OrgIndex} -> ?vdebug("next loop varbinds: next table" "~n ErrorStatus: ~p" @@ -2981,7 +3224,7 @@ next_loop_varbinds({table, TableOid, ME, TabOids}, {ErrorStatus, OrgIndex, []} end; next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, - [Vb | Vbs], MibView, Res, _LAVb) -> + [Vb | Vbs], MibView, Res, _LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds(subagent) -> entry with" "~n SAPid: ~p" "~n SAOid: ~p" @@ -2990,13 +3233,14 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, {subagent, _SubAgentPid, SAOid} -> next_loop_varbinds({subagent, SAPid, SAOid, [Vb | SAVbs]}, - Vbs, MibView, Res, []); + Vbs, MibView, Res, [], GbMaxVBs); _ -> case get_next_sa(SAPid, SAOid, SAVbs, MibView) of {ok, SARes, SAEndOfMibViewVbs} -> NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]), NewRes = lists:append(SARes, Res), - next_loop_varbinds([], NewVbs, MibView, NewRes, []); + next_loop_varbinds([], NewVbs, MibView, NewRes, [], + GbMaxVBs); {noSuchName, OrgIndex} -> %% v1 reply, treat this Vb as endOfMibView, and try again %% for the others. @@ -3009,12 +3253,14 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, case lists:delete(EVb, SAVbs) of [] -> next_loop_varbinds([], [EndOfVb, Vb | Vbs], - MibView, Res, []); + MibView, Res, [], + GbMaxVBs); TryAgainVbs -> next_loop_varbinds({subagent, SAPid, SAOid, TryAgainVbs}, [EndOfVb, Vb | Vbs], - MibView, Res, []) + MibView, Res, [], + GbMaxVBs) end; false -> %% bad index from subagent @@ -3030,14 +3276,15 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, end end; next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, - [], MibView, Res, _LAVb) -> + [], MibView, Res, _LAVb, GbMaxVBs) -> ?vt("next_loop_varbinds(subagent) -> entry with" "~n SAPid: ~p" "~n SAOid: ~p", [SAPid, SAOid]), case get_next_sa(SAPid, SAOid, SAVbs, MibView) of {ok, SARes, SAEndOfMibViewVbs} -> NewRes = lists:append(SARes, Res), - next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, []); + next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, [], + GbMaxVBs); {noSuchName, OrgIndex} -> %% v1 reply, treat this Vb as endOfMibView, and try again for %% the others. @@ -3048,11 +3295,13 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, value = {endOfMibView, NextOid}}, case lists:delete(EVb, SAVbs) of [] -> - next_loop_varbinds([], [EndOfVb], MibView, Res, []); + next_loop_varbinds([], [EndOfVb], MibView, Res, [], + GbMaxVBs); TryAgainVbs -> next_loop_varbinds({subagent, SAPid, SAOid, TryAgainVbs}, - [EndOfVb], MibView, Res, []) + [EndOfVb], MibView, Res, [], + GbMaxVBs) end; false -> %% bad index from subagent @@ -3065,12 +3314,15 @@ next_loop_varbinds({subagent, SAPid, SAOid, SAVbs}, [ErrorStatus,OrgIndex]), {ErrorStatus, OrgIndex, []} end; -next_loop_varbinds([], [], _MibView, Res, _LAVb) -> +next_loop_varbinds([], [], _MibView, Res, _LAVb, _GbMaxVBs) -> ?vt("next_loop_varbinds -> entry when done", []), {noError, 0, Res}. try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) -> - ?vtrace("try get instance from <~p,~p,~p>",[M,F,A]), + ?vtrace("try_get_instance -> entry with" + "~n M: ~p" + "~n F: ~p" + "~n A: ~p", [M,F,A]), Result = (catch dbg_apply(M, F, [get | A])), % mib shall return {value, <a-nice-value-within-range>} | % {noValue, noSuchName} (v1) | @@ -3081,6 +3333,7 @@ try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) -> tab_oid([]) -> [0]; tab_oid(X) -> X. + %%----------------------------------------------------------------- %% Perform a next, using the varbinds Oid if value is simple %% value. If value is {endOf<something>, NextOid}, use NextOid. @@ -3327,22 +3580,30 @@ next_oid(Oid) -> %%%----------------------------------------------------------------- %%% 5. GET-BULK REQUEST +%%% +%%% In order to prevent excesses in reply sizes there are two +%%% preventive methods in place. One is to check that the encode +%%% size does not exceed Max PDU size (this is mentioned in the +%%% standard). The other is a simple VBs limit. That is, the +%%% resulting response cannot contain more then this number of VBs. %%%----------------------------------------------------------------- -do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) -> - ?vtrace("do get bulk: start with" + +do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs) -> + ?vtrace("do_get_bulk -> entry with" "~n MibView: ~p" "~n NonRepeaters: ~p" "~n MaxRepetitions: ~p" "~n PduMS: ~p" - "~n Varbinds: ~p", - [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds]), + "~n Varbinds: ~p" + "~n GbMaxVBs: ~p", + [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds, GbMaxVBs]), {NonRepVbs, RestVbs} = split_vbs(NonRepeaters, Varbinds, []), - ?vt("do get bulk -> split: " + ?vt("do_get_bulk -> split: " "~n NonRepVbs: ~p" "~n RestVbs: ~p", [NonRepVbs, RestVbs]), - case do_get_next(MibView, NonRepVbs) of - {noError, 0, UResNonRepVbs} -> - ?vt("do get bulk -> next: " + case do_get_next(MibView, NonRepVbs, GbMaxVBs) of + {noError, 0, UResNonRepVbs} -> + ?vt("do_get_bulk -> next noError: " "~n UResNonRepVbs: ~p", [UResNonRepVbs]), ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs), %% Decode the first varbinds, produce a reversed list of @@ -3352,11 +3613,12 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) -> user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]), {genErr, Idx, []}; {SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) -> - ?vtrace("do get bulk -> encoded: " + ?vtrace("do_get_bulk -> encoded: " "~n SizeLeft: ~p" "~n Res: ~w", [SizeLeft, Res]), case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions, - RestVbs, Res)) of + RestVbs, Res, + length(UResNonRepVbs), GbMaxVBs)) of {error, Idx, Reason} -> user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]), @@ -3365,6 +3627,10 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) -> ?vtrace("do get bulk -> Res: " "~n ~w", [Res]), {noError, 0, conv_res(Res)}; + {noError, 0, Data} = OK -> + ?vtrace("do get bulk -> OK: " + "~n length(Data): ~w", [length(Data)]), + OK; Else -> ?vtrace("do get bulk -> Else: " "~n ~w", [Else]), @@ -3373,6 +3639,7 @@ do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) -> Res when is_list(Res) -> {noError, 0, conv_res(Res)} end; + {ErrorStatus, Index, _} -> ?vdebug("do get bulk: " "~n ErrorStatus: ~p" @@ -3422,11 +3689,12 @@ enc_vbs(SizeLeft, Vbs) -> end, lists:foldl(Fun, {SizeLeft, []}, Vbs). -do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res) +do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) when MaxRepetitions >= 0 -> - do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res); -do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res) -> - do_get_rep(Sz, MibView, 0, 0, Varbinds, Res). + do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res, + GbNumVBs, GbMaxVBs); +do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res, GbNumVBs, GbMaxVBs) -> + do_get_rep(Sz, MibView, 0, 0, Varbinds, Res, GbNumVBs, GbMaxVBs). conv_res(ResVarbinds) -> conv_res(ResVarbinds, []). @@ -3435,22 +3703,30 @@ conv_res([VbListOfBytes | T], Bytes) -> conv_res([], Bytes) -> Bytes. -do_get_rep(_Sz, _MibView, Max, Max, _, Res) -> +%% The only other value, then a positive integer, is infinity. +do_get_rep(_Sz, _MibView, Count, Max, _, _Res, GbNumVBs, GbMaxVBs) + when (is_integer(GbMaxVBs) andalso (GbNumVBs > GbMaxVBs)) -> + ?vinfo("Max Get-BULK VBs limit (~w) exceeded (~w) when:" + "~n Count: ~p" + "~n Max: ~p", [GbMaxVBs, GbNumVBs, Count, Max]), + {tooBig, 0, []}; +do_get_rep(_Sz, _MibView, Max, Max, _, Res, _GbNumVBs, _GbMaxVBs) -> ?vt("do_get_rep -> done when: " "~n Res: ~p", [Res]), {noError, 0, conv_res(Res)}; -do_get_rep(Sz, MibView, Count, Max, Varbinds, Res) -> +do_get_rep(Sz, MibView, Count, Max, Varbinds, Res, GbNumVBs, GbMaxVBs) -> ?vt("do_get_rep -> entry when: " "~n Sz: ~p" "~n Count: ~p" "~n Res: ~w", [Sz, Count, Res]), - case try_get_bulk(Sz, MibView, Varbinds) of + case try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) of {noError, NextVarbinds, SizeLeft, Res2} -> ?vt("do_get_rep -> noError: " "~n SizeLeft: ~p" "~n Res2: ~p", [SizeLeft, Res2]), do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds, - Res2 ++ Res); + Res2 ++ Res, + GbNumVBs + length(Varbinds), GbMaxVBs); {endOfMibView, _NextVarbinds, _SizeLeft, Res2} -> ?vt("do_get_rep -> endOfMibView: " "~n Res2: ~p", [Res2]), @@ -3462,22 +3738,29 @@ do_get_rep(Sz, MibView, Count, Max, Varbinds, Res) -> {ErrorStatus, Index, []} end. -try_get_bulk(Sz, MibView, Varbinds) -> +org_index_sort_vbs(Vbs) -> + lists:keysort(#varbind.org_index, Vbs). + +try_get_bulk(Sz, MibView, Varbinds, GbMaxVBs) -> ?vt("try_get_bulk -> entry with" - "~n Sz: ~w", [Sz]), - case do_get_next(MibView, Varbinds) of + "~n Sz: ~w" + "~n MibView: ~w" + "~n Varbinds: ~w", [Sz, MibView, Varbinds]), + case do_get_next(MibView, Varbinds, GbMaxVBs) of {noError, 0, UNextVarbinds} -> - ?vt("try_get_bulk -> noError", []), - NextVarbinds = lists:keysort(#varbind.org_index, UNextVarbinds), + ?vt("try_get_bulk -> noError: " + "~n UNextVarbinds: ~p", [UNextVarbinds]), + NextVarbinds = org_index_sort_vbs(UNextVarbinds), case (catch enc_vbs(Sz, NextVarbinds)) of {error, Idx, Reason} -> user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]), - ?vtrace("try_get_bulk -> error: " + ?vtrace("try_get_bulk -> encode error: " "~n Idx: ~p" "~n Reason: ~p", [Idx, Reason]), {genErr, Idx}; - {SizeLeft, Res} when is_integer(SizeLeft) andalso is_list(Res) -> - ?vt("try get bulk -> " + {SizeLeft, Res} when is_integer(SizeLeft) andalso + is_list(Res) -> + ?vt("try get bulk -> encode ok: " "~n SizeLeft: ~w" "~n Res: ~w", [SizeLeft, Res]), {check_end_of_mibview(NextVarbinds), @@ -3488,9 +3771,9 @@ try_get_bulk(Sz, MibView, Varbinds) -> {endOfMibView, [], 0, Res} end; {ErrorStatus, Index, _} -> - ?vt("try get bulk: " + ?vt("try_get_bulk -> error: " "~n ErrorStatus: ~p" - "~n Index: ~p",[ErrorStatus, Index]), + "~n Index: ~p", [ErrorStatus, Index]), {ErrorStatus, Index} end. @@ -3631,9 +3914,8 @@ get_err({ErrC, ErrI, Vbs}) -> {get_err_i(ErrC), ErrI, Vbs}. get_err_i(noError) -> noError; -get_err_i(S) -> - ?vtrace("convert '~p' to 'genErr'",[S]), - genErr. +get_err_i(tooBig) -> tooBig; % OTP-9700 +get_err_i(ES) -> ?vtrace("convert ErrorStatus '~p' to 'genErr'", [ES]), genErr. v2err_to_v1err(noError) -> noError; v2err_to_v1err(noAccess) -> noSuchName; @@ -3859,6 +4141,7 @@ mapfoldl(F, Eas, Accu0, [Hd|Tail]) -> {Accu2,[R|Rs]}; mapfoldl(_F, _Eas, Accu, []) -> {Accu,[]}. + %%----------------------------------------------------------------- %% Runtime debugging of the agent. %%----------------------------------------------------------------- @@ -3983,7 +4266,7 @@ handle_set_request_limit(_, _) -> {error, not_supported}. -agent_info(#state{worker = W, set_worker = SW}) -> +agent_info(#state{worker = W, set_worker = SW}) -> case (catch get_agent_info(W, SW)) of Info when is_list(Info) -> Info; @@ -4142,6 +4425,9 @@ get_multi_threaded(Opts) -> get_versions(Opts) -> get_option(versions, Opts, [v1,v2,v3]). +get_gb_max_vbs(Opts) -> + get_option(gb_max_vbs, Opts, infinity). + get_note_store_opt(Opts) -> get_option(note_store, Opts, []). diff --git a/lib/snmp/src/agent/snmpa_internal.hrl b/lib/snmp/src/agent/snmpa_internal.hrl index 20a36cc118..c435b519d9 100644 --- a/lib/snmp/src/agent/snmpa_internal.hrl +++ b/lib/snmp/src/agent/snmpa_internal.hrl @@ -26,6 +26,15 @@ -define(DEFAULT_LOCAL_ENGINE_ID, snmp_framework_mib:get_engine_id()). -define(DEFAULT_NOTIF_EXTRA_INFO, {snmpa_default_notification_extra_info}). +%% -- Max number of VBs in a Get-BULK response -- +%% (( The default value, 1000, is *way* more )) +%% (( then there is room for in a normal pdu )) +%% (( (unless the max pdu size has been )) +%% (( cranked way up), so this value should )) +%% (( suffice as "infinity" without actually )) +%% (( causing memory issues for the VM ... )) +-define(DEFAULT_GB_MAX_VBS, 1000). + -define(snmpa_info(F, A), ?snmp_info("agent", F, A)). -define(snmpa_warning(F, A), ?snmp_warning("agent", F, A)). -define(snmpa_error(F, A), ?snmp_error("agent", F, A)). diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl index 5b04c70054..1ec8dd3874 100644 --- a/lib/snmp/src/agent/snmpa_local_db.erl +++ b/lib/snmp/src/agent/snmpa_local_db.erl @@ -486,7 +486,11 @@ handle_call({match, Name, Db, Pattern}, _From, State) -> L1 = match(Db, Name, Pattern, State), {reply, lists:delete([undef], L1), State}; -handle_call({backup, BackupDir}, From, #state{dets = Dets} = State) -> +%% This check (that there is no backup already in progress) is also +%% done in the master agent process, but just in case a user issues +%% a backup call to this process directly, we add a similar check here. +handle_call({backup, BackupDir}, From, + #state{backup = undefined, dets = Dets} = State) -> ?vlog("backup: ~p",[BackupDir]), Pid = self(), V = get(verbosity), @@ -511,6 +515,10 @@ handle_call({backup, BackupDir}, From, #state{dets = Dets} = State) -> {reply, Error, State} end; +handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) -> + ?vinfo("backup already in progress: ~p", [Backup]), + {reply, {error, backup_in_progress}, S}; + handle_call(dump, _From, #state{dets = Dets} = State) -> ?vlog("dump",[]), dets_sync(Dets), diff --git a/lib/snmp/src/agent/snmpa_mib.erl b/lib/snmp/src/agent/snmpa_mib.erl index ce90db18b3..574467d38f 100644 --- a/lib/snmp/src/agent/snmpa_mib.erl +++ b/lib/snmp/src/agent/snmpa_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -552,8 +552,12 @@ handle_call({dump, File}, _From, #state{data = Data} = State) -> Reply = snmpa_mib_data:dump(Data, File), {reply, Reply, State}; -handle_call({backup, BackupDir}, From, #state{data = Data} = State) -> - ?vlog("backup to ~s",[BackupDir]), +%% This check (that there is no backup already in progress) is also +%% done in the master agent process, but just in case a user issues +%% a backup call to this process directly, we add a similar check here. +handle_call({backup, BackupDir}, From, + #state{backup = undefined, data = Data} = State) -> + ?vlog("backup to ~s", [BackupDir]), Pid = self(), V = get(verbosity), case file:read_file_info(BackupDir) of @@ -576,6 +580,10 @@ handle_call({backup, BackupDir}, From, #state{data = Data} = State) -> {reply, Error, State} end; +handle_call({backup, _BackupDir}, From, #state{backup = Backup} = S) -> + ?vinfo("backup already in progress: ~p", [Backup]), + {reply, {error, backup_in_progress}, S}; + handle_call(stop, _From, State) -> ?vlog("stop",[]), {stop, normal, ok, State}; diff --git a/lib/snmp/src/agent/snmpa_mib_lib.erl b/lib/snmp/src/agent/snmpa_mib_lib.erl index 078e681945..3c94cc8095 100644 --- a/lib/snmp/src/agent/snmpa_mib_lib.erl +++ b/lib/snmp/src/agent/snmpa_mib_lib.erl @@ -61,23 +61,23 @@ table_del_row({Tab, Db} = TabDb, Key) -> get_table(NameDb, FOI) -> (catch get_table(NameDb, FOI, [], [])). -get_table(NameDb, FOI, Oid, Acc) -> - case table_next(NameDb, Oid) of +get_table(NameDb, FOI, Key, Acc) -> + case table_next(NameDb, Key) of endOfTable -> ?vdebug("end of table",[]), {ok, lists:reverse(Acc)}; - Oid -> + Key -> %% Crap, circular ref - ?vinfo("cyclic reference: ~w -> ~w", [Oid,Oid]), - throw({error, {cyclic_db_reference, Oid, Acc}}); - NextOid -> - ?vtrace("get row for oid ~w", [NextOid]), - case table_get_row(NameDb, NextOid, FOI) of + ?vinfo("cyclic reference: ~w -> ~w", [Key, Key]), + throw({error, {cyclic_db_reference, Key, Acc}}); + NextKey -> + ?vtrace("get row for key ~w", [NextKey]), + case table_get_row(NameDb, NextKey, FOI) of undefined -> - throw({error, {invalid_rowindex, NextOid, Acc}}); + throw({error, {invalid_rowindex, NextKey, Acc}}); Row -> ?vtrace("row: ~w", [Row]), - get_table(NameDb, FOI, NextOid, [{NextOid, Row}|Acc]) + get_table(NameDb, FOI, NextKey, [{NextKey, Row}|Acc]) end end. diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl index 0305e1fbec..2d37ea56f0 100644 --- a/lib/snmp/src/agent/snmpa_mpd.erl +++ b/lib/snmp/src/agent/snmpa_mpd.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl index 5ef5914e18..7a9c214e0d 100644 --- a/lib/snmp/src/agent/snmpa_supervisor.erl +++ b/lib/snmp/src/agent/snmpa_supervisor.erl @@ -176,8 +176,8 @@ init([AgentType, Opts]) -> "~n AgentType: ~p" "~n Opts: ~p", [AgentType, Opts]), - put(sname, asup), - put(verbosity,get_verbosity(Opts)), + put(sname, asup), + put(verbosity, get_verbosity(Opts)), ?vlog("starting",[]), @@ -203,7 +203,12 @@ init([AgentType, Opts]) -> Vsns = get_opt(versions, Opts, [v1,v2,v3]), ?vdebug("[agent table] store versions: ~p",[Vsns]), ets:insert(snmp_agent_table, {versions, Vsns}), - + + %% -- Max number of VBs in a Get-BULK response -- + GbMaxVBs = get_gb_max_vbs(Opts), + ?vdebug("[agent table] Get-BULK max VBs: ~p", [GbMaxVBs]), + ets:insert(snmp_agent_table, {gb_max_vbs, GbMaxVBs}), + %% -- DB-directory -- DbDir = get_opt(db_dir, Opts), ?vdebug("[agent table] store db_dir: ~n ~p",[DbDir]), @@ -377,7 +382,8 @@ init([AgentType, Opts]) -> {versions, Vsns}, {net_if, NiOpts}, {mib_server, MibsOpts}, - {note_store, NsOpts}| + {note_store, NsOpts}, + {gb_max_vbs, GbMaxVBs} | get_opt(master_agent_options, Opts, [])], AgentSpec = @@ -542,6 +548,32 @@ get_verbosity(Opts) -> get_agent_type(Opts) -> get_opt(agent_type, Opts, master). + +%% We validate this option! This should really be done for all +%% options, but it is beyond the scope of this ticket, OTP-9700. + +get_gb_max_vbs(Opts) -> + Validate = + fun(GbMaxVBs) + when ((is_integer(GbMaxVBs) andalso (GbMaxVBs > 0)) orelse + (GbMaxVBs =:= infinity)) -> + ok; + (_) -> + error + end, + get_option(gb_max_vbs, ?DEFAULT_GB_MAX_VBS, Validate, Opts). + +get_option(Key, Default, Validate, Opts) + when is_list(Opts) andalso is_function(Validate) -> + Value = get_opt(Key, Opts, Default), + case Validate(Value) of + ok -> + Value; + error -> + exit({bad_option, Key, Value}) + end. + + get_opt(Key, Opts) -> snmp_misc:get_option(Key, Opts). diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl index 5b579efc13..994d926224 100644 --- a/lib/snmp/src/agent/snmpa_trap.erl +++ b/lib/snmp/src/agent/snmpa_trap.erl @@ -352,11 +352,26 @@ send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, ExtraInfo, NetIf) -> send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo, NetIf). +%% The agent normally does not care about the result, +%% but since it can be usefull when debugging, add +%% some info when we fail to send the trap(s). send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo, NetIf) -> - (catch do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, - LocalEngineID, ExtraInfo, NetIf)). - + try + begin + do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, + LocalEngineID, ExtraInfo, NetIf) + end + catch + T:E -> + Info = [{args, [TrapRec, NotifyName, ContextName, + Recv, Vbs, LocalEngineID, ExtraInfo, NetIf]}, + {tag, T}, + {err, E}, + {stacktrace, erlang:get_stacktrace()}], + {error, {failed_sending_trap, Info}} + end. + do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, LocalEngineID, ExtraInfo, NetIf) -> VarbindList = make_varbind_list(Vbs), diff --git a/lib/snmp/src/agent/snmpa_vacm.erl b/lib/snmp/src/agent/snmpa_vacm.erl index 892dc265f1..dadcf32543 100644 --- a/lib/snmp/src/agent/snmpa_vacm.erl +++ b/lib/snmp/src/agent/snmpa_vacm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -62,6 +62,13 @@ get_mib_view(ViewType, SecModel, SecName, SecLevel, ContextName) -> %% Follows the procedure in rfc2275 auth(ViewType, SecModel, SecName, SecLevel, ContextName) -> + ?vtrace("auth -> entry with" + "~n ViewType: ~p" + "~n SecModel: ~p" + "~n SecName: ~p" + "~n SecLevel: ~p" + "~n ContextName: ~p", + [ViewType, SecModel, SecName, SecLevel, ContextName]), % 3.2.1 - Check that the context is known to us ?vdebug("check that the context (~p) is known to us",[ContextName]), case snmp_view_based_acm_mib:vacmContextTable(get, ContextName, @@ -74,7 +81,7 @@ auth(ViewType, SecModel, SecName, SecLevel, ContextName) -> end, % 3.2.2 - Check that the SecModel and SecName is valid ?vdebug("check that SecModel (~p) and SecName (~p) is valid", - [SecModel,SecName]), + [SecModel, SecName]), GroupName = case snmp_view_based_acm_mib:get(vacmSecurityToGroupTable, [SecModel, length(SecName) | SecName], @@ -111,6 +118,8 @@ check_auth(Res) -> {ok, Res}. %% key in the table >= ViewIndex. %%----------------------------------------------------------------- get_mib_view(ViewName) -> + ?vtrace("get_mib_view -> entry with" + "~n ViewName: ~p", [ViewName]), ViewKey = [length(ViewName) | ViewName], case snmp_view_based_acm_mib:table_next(vacmViewTreeFamilyTable, ViewKey) of @@ -202,6 +211,13 @@ backup(BackupDir) -> %% Ret: {ok, ViewName} | {error, Reason} get_view_name(ViewType, GroupName, ContextName, SecModel, SecLevel) -> + ?vtrace("get_view_name -> entry with" + "~n ViewType: ~p" + "~n GroupName: ~p" + "~n ContextName: ~p" + "~n SecModel: ~p" + "~n SecLevel: ~p", + [ViewType, GroupName, ContextName, SecModel, SecLevel]), GroupKey = [length(GroupName) | GroupName], case get_access_row(GroupKey, ContextName, SecModel, SecLevel) of undefined -> @@ -266,9 +282,10 @@ dump_table(true) -> dump_table(_) -> ok. + dump_table() -> [{_, FName}] = ets:lookup(snmp_agent_table, snmpa_vacm_file), - TmpName = FName ++ ".tmp", + TmpName = unique_table_name(FName), case ets:tab2file(snmpa_vacm, TmpName) of ok -> case file:rename(TmpName, FName) of @@ -283,6 +300,35 @@ dump_table() -> [FName, Reason]) end. +%% This little thing is an attempt to create a "unique" filename +%% in order to minimize the risk of two processes at the same +%% time dumping the table. +unique_table_name(Pre) -> + %% We want something that is guaranteed to be unique, + %% therefor we use erlang:now() instead of os:timestamp() + unique_table_name(Pre, erlang:now()). + +unique_table_name(Pre, {_A, _B, C} = Now) -> + {Date, Time} = calendar:now_to_datetime(Now), + {YYYY, MM, DD} = Date, + {Hour, Min, Sec} = Time, + FormatDate = + io_lib:format("~.4w~.2.0w~.2.0w_~.2.0w~.2.0w~.2.0w_~w", + [YYYY, MM, DD, Hour, Min, Sec, round(C/1000)]), + unique_table_name2(Pre, FormatDate). + +unique_table_name2(Pre, FormatedDate) -> + PidPart = unique_table_name_pid(), + lists:flatten(io_lib:format("~s.~s~s.tmp", [Pre, PidPart, FormatedDate])). + +unique_table_name_pid() -> + case string:tokens(pid_to_list(self()), [$<,$.,$>]) of + [A, B, C] -> + A ++ B ++ C ++ "."; + _ -> + "" + end. + %%----------------------------------------------------------------- %% Alg. diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src index 219ac62a73..c8e5eec6db 100644 --- a/lib/snmp/src/app/snmp.appup.src +++ b/lib/snmp/src/app/snmp.appup.src @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -22,46 +22,124 @@ %% ----- U p g r a d e ------------------------------------------------------- [ + {"4.21.6", + [ + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} + ] + }, + {"4.21.5", + [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} + ] + }, + {"4.21.4", + [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} + ] + }, {"4.21.3", [ - {update, snmpa_local_db, soft, soft_purge, soft_purge, []} + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.21.2", [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {load_module, snmpa_mpd, soft_purge, soft_purge, []}, {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, {load_module, snmpa_trap, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []} + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.21.1", [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {load_module, snmpa_mpd, soft_purge, soft_purge, []}, {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, {load_module, snmpa_trap, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []}, - {update, snmp_note_store, soft, soft_purge, soft_purge, []} + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {update, snmp_note_store, soft, soft_purge, soft_purge, []} ] }, {"4.21", [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {load_module, snmpa_mpd, soft_purge, soft_purge, []}, {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, {load_module, snmpa_trap, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []}, - {update, snmp_note_store, soft, soft_purge, soft_purge, []} + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {update, snmp_note_store, soft, soft_purge, soft_purge, []} ] }, {"4.20.1", [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, {load_module, snmpa_trap, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, {load_module, snmpm, soft_purge, soft_purge, [snmpm_server, snmpm_config, snmp_config]}, @@ -73,21 +151,29 @@ [snmp_conf, snmp_config]}, {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]}, {update, snmp_note_store, soft, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, - {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, - {update, snmpm_server, soft, soft_purge, soft_purge, + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, + {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, + {update, snmpm_server, soft, soft_purge, soft_purge, [snmpm_net_if, snmpm_mpd, snmpm_config]}, - {update, snmpm_net_if, soft, soft_purge, soft_purge, + {update, snmpm_net_if, soft, soft_purge, soft_purge, [snmp_conf, snmpm_mpd, snmpm_config]} ] }, {"4.20", [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, {load_module, snmpa_trap, soft_purge, soft_purge, []}, {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]}, + {load_module, snmp_target_mib, soft_purge, soft_purge, + [snmpa_mib_lib, snmp_conf]}, {load_module, snmpm, soft_purge, soft_purge, [snmpm_server, snmpm_config, snmp_config]}, {load_module, snmp_conf, soft_purge, soft_purge, []}, @@ -98,101 +184,137 @@ [snmp_conf, snmp_config]}, {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]}, {update, snmp_note_store, soft, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, - {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, - {update, snmpm_server, soft, soft_purge, soft_purge, + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, + {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, + {update, snmpm_server, soft, soft_purge, soft_purge, [snmpm_net_if, snmpm_mpd, snmpm_config]}, - {update, snmpm_net_if, soft, soft_purge, soft_purge, + {update, snmpm_net_if, soft, soft_purge, soft_purge, [snmp_conf, snmpm_mpd, snmpm_config]} ] - }, - {"4.19", - [ - {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, - {load_module, snmpa, soft_purge, soft_purge, []}, - {load_module, snmpm, soft_purge, soft_purge, - [snmpm_server, snmpm_config, snmp_config]}, - {load_module, snmpa_usm, soft_purge, soft_purge, []}, - {load_module, snmpm_usm, soft_purge, soft_purge, []}, - {load_module, snmp_log, soft_purge, soft_purge, []}, - {load_module, snmp_pdus, soft_purge, soft_purge, []}, - {load_module, snmp_conf, soft_purge, soft_purge, []}, - {load_module, snmpa_conf, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmp_misc, soft_purge, soft_purge, []}, - {load_module, snmp_config, soft_purge, soft_purge, []}, - {load_module, snmpa_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmpm_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config, snmpm_config]}, - {load_module, snmpa_trap, soft_purge, soft_purge, - [snmpa_mpd, snmp_notification_mib, snmp_target_mib, snmpa_net_if]}, - {load_module, snmpa_acm, soft_purge, soft_purge, - [snmp_conf, snmpa_mpd, snmp_target_mib]}, - {load_module, snmpa_conf, soft_purge, soft_purge, - [snmp_config, snmp_notification_mib]}, - {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, - {load_module, snmp_notification_mib, soft_purge, soft_purge, - [snmp_conf, snmp_target_mib]}, - {load_module, snmp_community_mib, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, - [snmp_conf]}, - {update, snmp_note_store, soft, soft_purge, soft_purge, []}, - {update, snmpm_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpm_mpd, snmpm_config]}, - {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, - {update, snmpm_server, soft, soft_purge, soft_purge, - [snmpm_net_if, snmpm_mpd, snmpm_config]}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpa_mpd]}, - {update, snmpa_agent, soft, soft_purge, soft_purge, - [snmpa_acm, snmpa_mpd, snmpa_trap]} - ] } ], %% ------D o w n g r a d e --------------------------------------------------- [ + {"4.21.6", + [ + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} + ] + }, + {"4.21.5", + [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} + ] + }, + {"4.21.4", + [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} + ] + }, {"4.21.3", [ - {update, snmpa_local_db, soft, soft_purge, soft_purge, []} + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {load_module, snmpa_trap, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.21.2", [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {load_module, snmpa_mpd, soft_purge, soft_purge, []}, {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, {load_module, snmpa_trap, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []} + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []} ] }, {"4.21.1", [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmp_target_mib, soft_purge, soft_purge, [snmpa_mib_lib]}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {load_module, snmpa_mpd, soft_purge, soft_purge, []}, {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, {load_module, snmpa_trap, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, {update, snmp_note_store, soft, soft_purge, soft_purge, []} ] }, {"4.21", [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {load_module, snmpa_mpd, soft_purge, soft_purge, []}, {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, {load_module, snmpa_trap, soft_purge, soft_purge, []}, {load_module, snmp_target_mib, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, []}, + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, []}, {update, snmp_note_store, soft, soft_purge, soft_purge, []} ] }, {"4.20.1", [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, {load_module, snmpa_trap, soft_purge, soft_purge, []}, {load_module, snmp_target_mib, soft_purge, soft_purge, []}, @@ -207,8 +329,10 @@ [snmp_conf, snmp_config]}, {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]}, {update, snmp_note_store, soft, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, {update, snmpm_server, soft, soft_purge, soft_purge, [snmpm_net_if, snmpm_mpd, snmpm_config]}, @@ -218,6 +342,11 @@ }, {"4.20", [ + {load_module, snmpa, soft_purge, soft_purge, []}, + {load_module, snmpa_mib_lib, soft_purge, soft_purge, []}, + {update, snmpa_supervisor, soft, soft_purge, soft_purge, []}, + + {load_module, snmpa_vacm, soft_purge, soft_purge, []}, {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, {load_module, snmpa_trap, soft_purge, soft_purge, []}, {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, @@ -232,58 +361,16 @@ [snmp_conf, snmp_config]}, {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]}, {update, snmp_note_store, soft, soft_purge, soft_purge, []}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, + {load_module, snmp_generic_mnesia, soft_purge, soft_purge, []}, + {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, + {update, snmpa_mib, soft, soft_purge, soft_purge, []}, + {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]}, {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, {update, snmpm_server, soft, soft_purge, soft_purge, [snmpm_net_if, snmpm_mpd, snmpm_config]}, {update, snmpm_net_if, soft, soft_purge, soft_purge, [snmp_conf, snmpm_mpd, snmpm_config]} ] - }, - {"4.19", - [ - {load_module, snmpa_set_lib, soft_purge, soft_purge, []}, - {load_module, snmpa, soft_purge, soft_purge, []}, - {load_module, snmpm, soft_purge, soft_purge, - [snmpm_server, snmpm_config, snmp_config]}, - {load_module, snmpa_usm, soft_purge, soft_purge, []}, - {load_module, snmpm_usm, soft_purge, soft_purge, []}, - {load_module, snmp_log, soft_purge, soft_purge, []}, - {load_module, snmp_pdus, soft_purge, soft_purge, []}, - {load_module, snmp_conf, soft_purge, soft_purge, []}, - {load_module, snmpa_conf, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmp_misc, soft_purge, soft_purge, []}, - {load_module, snmp_config, soft_purge, soft_purge, []}, - {load_module, snmpa_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config]}, - {load_module, snmpm_mpd, soft_purge, soft_purge, - [snmp_conf, snmp_config, snmpm_config]}, - {load_module, snmpa_trap, soft_purge, soft_purge, - [snmpa_mpd, snmp_notification_mib, snmp_target_mib, snmpa_net_if]}, - {load_module, snmpa_acm, soft_purge, soft_purge, - [snmp_conf, snmpa_mpd, snmp_target_mib]}, - {load_module, snmpa_conf, soft_purge, soft_purge, - [snmp_config, snmp_notification_mib]}, - {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []}, - {load_module, snmp_notification_mib, soft_purge, soft_purge, - [snmp_conf, snmp_target_mib]}, - {load_module, snmp_community_mib, soft_purge, soft_purge, []}, - {load_module, snmp_target_mib, soft_purge, soft_purge, - [snmp_conf]}, - {update, snmp_note_store, soft, soft_purge, soft_purge, []}, - {update, snmpm_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpm_mpd, snmpm_config]}, - {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]}, - {update, snmpm_server, soft, soft_purge, soft_purge, - [snmpm_net_if, snmpm_mpd, snmpm_config]}, - {update, snmpa_local_db, soft, soft_purge, soft_purge, []}, - {update, snmpa_net_if, soft, soft_purge, soft_purge, - [snmp_conf, snmpa_mpd]}, - {update, snmpa_agent, soft, soft_purge, soft_purge, - [snmpa_acm, snmpa_mpd, snmpa_trap]} - ] } ] }. diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl index c95346b5a6..e968bc65b1 100644 --- a/lib/snmp/test/snmp_agent_test.erl +++ b/lib/snmp/test/snmp_agent_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2011. All Rights Reserved. +%% Copyright Ericsson AB 2003-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -222,7 +222,7 @@ groups() -> {group, otp_7157} ] }, - {tickets2, [], [otp8395]}, + {tickets2, [], [otp8395, otp9884]}, {otp_4394, [], [otp_4394_test]}, {otp_7157, [], [otp_7157_test] } @@ -322,6 +322,12 @@ init_per_testcase(otp8395 = Case, Config) when is_list(Config) -> "~n Config: ~p", [Case, Config]), Config2 = init_per_testcase2(Case, init_per_suite(Config)), otp8395({init, Config2}); +init_per_testcase(otp9884 = Case, Config) when is_list(Config) -> + ?DBG("init_per_testcase -> entry with" + "~n Case: ~p" + "~n Config: ~p", [Case, Config]), + Config2 = init_per_testcase2(Case, init_per_suite(Config)), + otp9884({init, Config2}); init_per_testcase(otp_7157_test = _Case, Config) when is_list(Config) -> ?DBG("init_per_testcase -> entry with" "~n Case: ~p" @@ -349,6 +355,8 @@ init_per_testcase(_Case, Config) when is_list(Config) -> end_per_testcase(otp8395, Config) when is_list(Config) -> otp8395({fin, Config}); +end_per_testcase(otp9884, Config) when is_list(Config) -> + otp9884({fin, Config}); end_per_testcase(_Case, Config) when is_list(Config) -> ?DBG("end_per_testcase -> entry with" "~n Case: ~p" @@ -1321,8 +1329,11 @@ finish_v3(Config) when is_list(Config) -> lists:keydelete(vsn, 1, C1). -mt_cases() -> - [multi_threaded, mt_trap]. +mt_cases() -> + [ + multi_threaded, + mt_trap + ]. init_mt(Config) when is_list(Config) -> SaNode = ?config(snmp_sa, Config), @@ -5235,16 +5246,6 @@ loop_it_2(Oid, N) -> %%%----------------------------------------------------------------- - - - -%% These are (ticket) test cases where the initiation has to be done -%% individually. - - - - - %%----------------------------------------------------------------- %% Ticket: OTP-1128 %% Slogan: Bug in handling of createAndWait set-requests. @@ -5885,7 +5886,7 @@ otp_7157_test1(MA) -> otp8395({init, Config}) when is_list(Config) -> ?DBG("otp8395(init) -> entry with" "~n Config: ~p", [Config]), - + %% -- %% Start nodes %% @@ -5893,7 +5894,7 @@ otp8395({init, Config}) when is_list(Config) -> {ok, AgentNode} = start_node(agent), %% {ok, SubAgentNode} = start_node(sub_agent), {ok, ManagerNode} = start_node(manager), - + %% -- %% Mnesia init %% @@ -5901,10 +5902,10 @@ otp8395({init, Config}) when is_list(Config) -> AgentDbDir = ?config(agent_db_dir, Config), AgentMnesiaDir = filename:join([AgentDbDir, "mnesia"]), mnesia_init(AgentNode, AgentMnesiaDir), - -%% SubAgentDir = ?config(sub_agent_dir, Config), -%% SubAgentMnesiaDir = filename:join([SubAgentDir, "mnesia"]), -%% mnesia_init(SubAgentNode, SubAgentMnesiaDir), + + %% SubAgentDir = ?config(sub_agent_dir, Config), + %% SubAgentMnesiaDir = filename:join([SubAgentDir, "mnesia"]), + %% mnesia_init(SubAgentNode, SubAgentMnesiaDir), %% ok = mnesia_create_schema(AgentNode, [AgentNode, SubAgentNode]), %% ok = mnesia:create_schema([AgentNode, SubAgentNode]), @@ -5929,12 +5930,12 @@ otp8395({init, Config}) when is_list(Config) -> %% SubAgentIP = tuple_to_list(SubAgentIP0), {ok, ManagerIP0} = snmp_misc:ip(ManagerHost), ManagerIP = tuple_to_list(ManagerIP0), - + %% -- %% Write agent config %% - + Vsns = [v1], AgentConfDir = ?config(agent_conf_dir, Config), ManagerConfDir = ?config(manager_top_dir, Config), @@ -5958,7 +5959,7 @@ otp8395({init, Config}) when is_list(Config) -> {manager_node, ManagerNode}, {manager_host, ManagerHost}, {manager_ip, ManagerIP}|Config]), - + %% -- %% Create watchdog %% @@ -5970,7 +5971,7 @@ otp8395({init, Config}) when is_list(Config) -> otp8395({fin, Config}) when is_list(Config) -> ?DBG("otp8395(fin) -> entry with" "~n Config: ~p", [Config]), - + AgentNode = ?config(agent_node, Config), ManagerNode = ?config(manager_node, Config), @@ -5978,11 +5979,11 @@ otp8395({fin, Config}) when is_list(Config) -> %% Stop agent (this is the nice way to do it, %% so logs and files can be closed in the proper way). %% - + AgentSup = ?config(agent_sup, Config), ?DBG("otp8395(fin) -> stop (stand-alone) agent: ~p", [AgentSup]), stop_stdalone_agent(AgentSup), - + %% - %% Stop mnesia %% @@ -5998,8 +5999,8 @@ otp8395({fin, Config}) when is_list(Config) -> stop_node(AgentNode), -%% SubAgentNode = ?config(sub_agent_node, Config), -%% stop_node(SubAgentNode), + %% SubAgentNode = ?config(sub_agent_node, Config), + %% stop_node(SubAgentNode), %% - @@ -6019,7 +6020,7 @@ otp8395(doc) -> otp8395(Config) when is_list(Config) -> ?DBG("otp8395 -> entry with" "~n Config: ~p", [Config]), - + ?SLEEP(1000), %% This is just to dirty trick for the ***old*** test-code @@ -6037,8 +6038,8 @@ otp8395(Config) when is_list(Config) -> {ok, LogInfo} = rpc:call(AgentNode, snmpa, log_info, []), ?DBG("otp8395 -> LogInfo: ~p", [LogInfo]), -%% SyncRes = rpc:call(AgentNode, snmp, log_sync, [?audit_trail_log_name]), -%% ?DBG("otp8395 -> SyncRes: ~p", [SyncRes]), + %% SyncRes = rpc:call(AgentNode, snmp, log_sync, [?audit_trail_log_name]), + %% ?DBG("otp8395 -> SyncRes: ~p", [SyncRes]), ok = agent_log_validation(AgentNode), LTTRes = @@ -6048,7 +6049,195 @@ otp8395(Config) when is_list(Config) -> ?SLEEP(1000), ?DBG("otp8395 -> done", []), ok. - + + +%%----------------------------------------------------------------- + +otp9884({init, Config}) when is_list(Config) -> + ?DBG("otp9884(init) -> entry with" + "~n Config: ~p", [Config]), + + %% -- + %% Start nodes + %% + + {ok, AgentNode} = start_node(agent), + + %% We don't use a manager in this test but the (common) config + %% function takes an argument that is derived from this + {ok, ManagerNode} = start_node(manager), + + %% -- + %% Mnesia init + %% + + AgentDbDir = ?config(agent_db_dir, Config), + AgentMnesiaDir = filename:join([AgentDbDir, "mnesia"]), + mnesia_init(AgentNode, AgentMnesiaDir), + + mnesia_create_schema(AgentNode, [AgentNode]), + + mnesia_start(AgentNode), + + %% -- + %% Host & IP + %% + + AgentHost = ?HOSTNAME(AgentNode), + ManagerHost = ?HOSTNAME(ManagerNode), + + Host = snmp_test_lib:hostname(), + Ip = ?LOCALHOST(), + {ok, AgentIP0} = snmp_misc:ip(AgentHost), + AgentIP = tuple_to_list(AgentIP0), + {ok, ManagerIP0} = snmp_misc:ip(ManagerHost), + ManagerIP = tuple_to_list(ManagerIP0), + + + %% -- + %% Write agent config + %% + + Vsns = [v1], + ManagerConfDir = ?config(manager_top_dir, Config), + AgentConfDir = ?config(agent_conf_dir, Config), + AgentTopDir = ?config(agent_top_dir, Config), + AgentBkpDir1 = filename:join([AgentTopDir, backup1]), + AgentBkpDir2 = filename:join([AgentTopDir, backup2]), + ok = file:make_dir(AgentBkpDir1), + ok = file:make_dir(AgentBkpDir2), + AgentBkpDirs = [AgentBkpDir1, AgentBkpDir2], + snmp_agent_test_lib:config(Vsns, + ManagerConfDir, AgentConfDir, + ManagerIP, AgentIP), + + + %% -- + %% Start the agent + %% + + Config2 = start_agent([{host, Host}, + {ip, Ip}, + {agent_node, AgentNode}, + {agent_host, AgentHost}, + {agent_ip, AgentIP}, + {agent_backup_dirs, AgentBkpDirs}|Config]), + + %% -- + %% Create watchdog + %% + + Dog = ?WD_START(?MINS(1)), + + [{watchdog, Dog} | Config2]; + +otp9884({fin, Config}) when is_list(Config) -> + ?DBG("otp9884(fin) -> entry with" + "~n Config: ~p", [Config]), + + AgentNode = ?config(agent_node, Config), + ManagerNode = ?config(manager_node, Config), + + %% - + %% Stop agent (this is the nice way to do it, + %% so logs and files can be closed in the proper way). + %% + + AgentSup = ?config(agent_sup, Config), + ?DBG("otp9884(fin) -> stop (stand-alone) agent: ~p", [AgentSup]), + stop_stdalone_agent(AgentSup), + + %% - + %% Stop mnesia + %% + ?DBG("otp9884(fin) -> stop mnesia", []), + mnesia_stop(AgentNode), + + + %% - + %% Stop the agent node + %% + + ?DBG("otp9884(fin) -> stop agent node", []), + stop_node(AgentNode), + + + %% SubAgentNode = ?config(sub_agent_node, Config), + %% stop_node(SubAgentNode), + + + %% - + %% Stop the manager node + %% + + ?DBG("otp9884(fin) -> stop manager node", []), + stop_node(ManagerNode), + + Dog = ?config(watchdog, Config), + ?WD_STOP(Dog), + lists:keydelete(watchdog, 1, Config); + +otp9884(doc) -> + "OTP-9884 - Simlutaneous backup call should not work. "; + +otp9884(Config) when is_list(Config) -> + ?DBG("otp9884 -> entry with" + "~n Config: ~p", [Config]), + + AgentNode = ?config(agent_node, Config), + [AgentBkpDir1, AgentBkpDir2] = ?config(agent_backup_dirs, Config), + Self = self(), + timer:apply_after(1000, + ?MODULE, otp9884_backup, [AgentNode, Self, first, AgentBkpDir1]), + timer:apply_after(1000, + ?MODULE, otp9884_backup, [AgentNode, Self, second, AgentBkpDir2]), + otp9884_await_backup_completion(undefined, undefined), + + ?DBG("otp9884 -> done", []), + ok. + + +otp9884_backup(Node, Pid, Tag, Dir) -> + io:format("[~w] call backup function~n", [Tag]), + Res = rpc:call(Node, snmpa, backup, [Dir]), + io:format("[~w] backup result: ~p~n", [Tag, Res]), + Pid ! {otp9884_backup_complete, Tag, Res}. + +otp9884_await_backup_completion(ok, Second) + when ((Second =/= ok) andalso (Second =/= undefined)) -> + io:format("otp9884_await_backup_completion -> " + "first backup succeed and second failed (~p)~n", [Second]), + ok; +otp9884_await_backup_completion(First, ok) + when ((First =/= ok) andalso (First =/= undefined)) -> + io:format("otp9884_await_backup_completion -> " + "second backup succeed and first failed (~p)~n", [First]), + ok; +otp9884_await_backup_completion(First, Second) + when (((First =:= undefined) andalso (Second =:= undefined)) + orelse + ((First =:= undefined) andalso (Second =/= undefined)) + orelse + ((First =/= undefined) andalso (Second =:= undefined))) -> + io:format("otp9884_await_backup_completion -> await complete messages~n", []), + receive + {otp9884_backup_complete, first, Res} -> + io:format("otp9884_await_backup_completion -> " + "received complete message for first: ~p~n", [Res]), + otp9884_await_backup_completion(Res, Second); + {otp9884_backup_complete, second, Res} -> + io:format("otp9884_await_backup_completion -> " + "received complete message for second: ~p~n", [Res]), + otp9884_await_backup_completion(First, Res) + after 10000 -> + %% we have waited long enough + throw({error, {timeout, First, Second}}) + end; +otp9884_await_backup_completion(First, Second) -> + throw({error, {bad_completion, First, Second}}). + + +%%----------------------------------------------------------------- agent_log_validation(Node) -> rpc:call(Node, ?MODULE, agent_log_validation, []). diff --git a/lib/snmp/test/snmp_compiler_test.erl b/lib/snmp/test/snmp_compiler_test.erl index c964b08168..0a147130b0 100644 --- a/lib/snmp/test/snmp_compiler_test.erl +++ b/lib/snmp/test/snmp_compiler_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2011. All Rights Reserved. +%% Copyright Ericsson AB 2003-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -566,14 +566,7 @@ p(F, A) -> p(TName, F, A) -> io:format("*** [~w][~s] ***" - "~n" ++ F ++ "~n", [TName,format_timestamp(now())|A]). - -format_timestamp({_N1, _N2, N3} = Now) -> - {Date, Time} = calendar:now_to_datetime(Now), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", - [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), - lists:flatten(FormatDate). + "~n" ++ F ++ "~n", [TName, formated_timestamp()|A]). +formated_timestamp() -> + snmp_test_lib:formated_timestamp(). diff --git a/lib/snmp/test/snmp_manager_config_test.erl b/lib/snmp/test/snmp_manager_config_test.erl index 4498d506f3..3192fe1b40 100644 --- a/lib/snmp/test/snmp_manager_config_test.erl +++ b/lib/snmp/test/snmp_manager_config_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -2726,14 +2726,7 @@ p(F, A) -> p(TName, F, A) -> io:format("*** [~s] ***" - " ~w -> " ++ F ++ "~n", [format_timestamp(now()),TName|A]). - -format_timestamp({_N1, _N2, N3} = Now) -> - {Date, Time} = calendar:now_to_datetime(Now), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", - [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), - lists:flatten(FormatDate). + " ~w -> " ++ F ++ "~n", [formated_timestamp(),TName|A]). +formated_timestamp() -> + snmp_test_lib:formated_timestamp(). diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl index d18f20d359..75c9f7b277 100644 --- a/lib/snmp/test/snmp_manager_test.erl +++ b/lib/snmp/test/snmp_manager_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2011. All Rights Reserved. +%% Copyright Ericsson AB 2003-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -6064,7 +6064,7 @@ rcall(Node, Mod, Func, Args) -> %% Time in milli sec %% t() -> -%% {A,B,C} = erlang:now(), +%% {A,B,C} = os:timestamp(), %% A*1000000000+B*1000+(C div 1000). @@ -6078,16 +6078,10 @@ p(F, A) -> p(TName, F, A) -> io:format("*** [~w][~s] ***" - "~n" ++ F ++ "~n", [TName,format_timestamp(now())|A]). - -format_timestamp({_N1, _N2, N3} = Now) -> - {Date, Time} = calendar:now_to_datetime(Now), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", - [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), - lists:flatten(FormatDate). + "~n" ++ F ++ "~n", [TName, formated_timestamp()|A]). + +formated_timestamp() -> + snmp_test_lib:formated_timestamp(). %% p(TName, F, A) -> %% io:format("~w -> " ++ F ++ "~n", [TName|A]). diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl index 54839d989b..e4d58a1253 100644 --- a/lib/snmp/test/snmp_test_lib.erl +++ b/lib/snmp/test/snmp_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% Copyright Ericsson AB 2002-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -37,7 +37,7 @@ -export([watchdog/3, watchdog_start/1, watchdog_start/2, watchdog_stop/1]). -export([del_dir/1]). -export([cover/1]). --export([p/2, print/5]). +-export([p/2, print/5, formated_timestamp/0]). %% ---------------------------------------------------------------------- @@ -521,15 +521,18 @@ p(F, A) when is_list(F) andalso is_list(A) -> print(Prefix, Module, Line, Format, Args) -> io:format("*** [~s] ~s ~p ~p ~p:~p *** " ++ Format ++ "~n", - [format_timestamp(now()), + [formated_timestamp(), Prefix, node(), self(), Module, Line|Args]). +formated_timestamp() -> + format_timestamp(os:timestamp()). + format_timestamp({_N1, _N2, N3} = Now) -> {Date, Time} = calendar:now_to_datetime(Now), {YYYY,MM,DD} = Date, {Hour,Min,Sec} = Time, FormatDate = - io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", + io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w ~w", [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), lists:flatten(FormatDate). diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl index 84bdc6b04f..499cf7abcf 100644 --- a/lib/snmp/test/snmp_test_mgr.erl +++ b/lib/snmp/test/snmp_test_mgr.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1124,16 +1124,11 @@ d(F,A) -> d(get(debug),F,A). d(true,F,A) -> io:format("*** [~s] MGR_DBG *** " ++ F ++ "~n", - [format_timestamp(now())|A]); + [formated_timestamp()|A]); d(_,_F,_A) -> ok. -format_timestamp({_N1, _N2, N3} = Now) -> - {Date, Time} = calendar:now_to_datetime(Now), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", - [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), - lists:flatten(FormatDate). + +formated_timestamp() -> + snmp_test_lib:formated_timestamp(). diff --git a/lib/snmp/test/snmp_test_mgr_misc.erl b/lib/snmp/test/snmp_test_mgr_misc.erl index fc6dedd96d..5525c5c3ec 100644 --- a/lib/snmp/test/snmp_test_mgr_misc.erl +++ b/lib/snmp/test/snmp_test_mgr_misc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -779,16 +779,9 @@ d(F,A) -> d(get(debug),F,A). d(true,F,A) -> io:format("*** [~s] MGR_PS_DBG *** " ++ F ++ "~n", - [format_timestamp(now())|A]); + [formated_timestamp()|A]); d(_,_F,_A) -> ok. -format_timestamp({_N1, _N2, N3} = Now) -> - {Date, Time} = calendar:now_to_datetime(Now), - {YYYY,MM,DD} = Date, - {Hour,Min,Sec} = Time, - FormatDate = - io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", - [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), - lists:flatten(FormatDate). - +formated_timestamp() -> + snmp_test_lib:formated_timestamp(). diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk index ee2e633c69..fb1dcb6c41 100644 --- a/lib/snmp/vsn.mk +++ b/lib/snmp/vsn.mk @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2011. All Rights Reserved. +# Copyright Ericsson AB 1997-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -18,6 +18,6 @@ # %CopyrightEnd% APPLICATION = snmp -SNMP_VSN = 4.21.4 -PRE_VSN = -APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)" +SNMP_VSN = 4.21.7 +PRE_VSN = +APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)" diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml index 6fc4fdc43d..c6c634212f 100644 --- a/lib/ssh/doc/src/notes.xml +++ b/lib/ssh/doc/src/notes.xml @@ -29,6 +29,32 @@ <file>notes.xml</file> </header> +<section><title>Ssh 2.0.9</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Erlang/OTP can now be built using parallel make if you + limit the number of jobs, for instance using '<c>make + -j6</c>' or '<c>make -j10</c>'. '<c>make -j</c>' does not + work at the moment because of some missing + dependencies.</p> + <p> + Own Id: OTP-9451</p> + </item> + <item> + <p> + Ssh behaviours now use the new directive "-callback". + Parameters will be further specified in a later version + of ssh.</p> + <p> + Own Id: OTP-9796</p> + </item> + </list> + </section> + +</section> + <section><title>Ssh 2.0.8</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index 2c5096a25f..ed88b3a1af 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -1,10 +1,10 @@ -<?xml version="1.0" encoding="latin1" ?> +<?xml version="1.0" encoding="iso-8859-1" ?> <!DOCTYPE erlref SYSTEM "erlref.dtd"> <erlref> <header> <copyright> - <year>2004</year><year>2010</year> + <year>2004</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -86,7 +86,7 @@ by calling ssh_connect:session_channel/2.</p> <p>Options are:</p> <taglist> - <tag><c><![CDATA[{user_dir, String}]]></c></tag> + <tag><c><![CDATA[{user_dir, string()}]]></c></tag> <item> <p>Sets the user directory e.i. the directory containing ssh configuration files for the user such as @@ -94,6 +94,18 @@ <c><![CDATA[authorized_key]]></c>. Defaults to the directory normally referred to as <c><![CDATA[~/.ssh]]></c> </p> </item> + <tag><c><![CDATA[{dsa_pass_phrase, string()}]]></c></tag> + <item> + <p>If the user dsa key is protected by a pass phrase it can be + supplied with this option. + </p> + </item> + <tag><c><![CDATA[{rsa_pass_phrase, string()}]]></c></tag> + <item> + <p>If the user rsa key is protected by a pass phrase it can be + supplied with this option. + </p> + </item> <tag><c><![CDATA[{silently_accept_hosts, boolean()}]]></c></tag> <item> <p>When true hosts are added to the @@ -222,6 +234,14 @@ option <c>shell</c> which is much less work than implementing your own cli channel. </item> + <tag><c><![CDATA[{user_dir, String}]]></c></tag> + <item> + <p>Sets the user directory e.i. the directory containing + ssh configuration files for the user such as + <c><![CDATA[known_hosts]]></c>, <c><![CDATA[id_rsa, id_dsa]]></c> and + <c><![CDATA[authorized_key]]></c>. Defaults to the directory normally + referred to as <c><![CDATA[~/.ssh]]></c> </p> + </item> <tag><c><![CDATA[{system_dir, string()}]]></c></tag> <item> <p>Sets the system directory, containing the host files @@ -283,22 +303,6 @@ </func> <func> - <name>sign_data(Data, Algorithm) -> Signature | {error, Reason}</name> - <fsummary> </fsummary> - <type> - <v> Data = binary()</v> - <v> Algorithm = "ssh-rsa"</v> - <v> Signature = binary()</v> - <v> Reason = term()</v> - </type> - <desc> - <p>Signs the supplied binary using the SSH key. - </p> - </desc> - </func> - - - <func> <name>start() -> </name> <name>start(Type) -> ok | {error, Reason}</name> <fsummary>Starts the Ssh application. </fsummary> @@ -356,21 +360,6 @@ </desc> </func> - <func> - <name>verify_data(Data, Signature, Algorithm) -> ok | {error, Reason}</name> - <fsummary> </fsummary> - <type> - <v> Data = binary()</v> - <v> Algorithm = "ssh-rsa"</v> - <v> Signature = binary()</v> - <v> Reason = term()</v> - </type> - <desc> - <p>Verifies the supplied binary against the binary signature. - </p> - </desc> - </func> - </funcs> </erlref> diff --git a/lib/ssh/src/DSS.asn1 b/lib/ssh/src/DSS.asn1 deleted file mode 100644 index 77aca3808b..0000000000 --- a/lib/ssh/src/DSS.asn1 +++ /dev/null @@ -1,20 +0,0 @@ -DSS DEFINITIONS EXPLICIT TAGS ::= - -BEGIN - --- EXPORTS ALL --- All types and values defined in this module are exported for use --- in other ASN.1 modules. - -DSAPrivateKey ::= SEQUENCE { - version INTEGER, - p INTEGER, -- p - q INTEGER, -- q - g INTEGER, -- q - y INTEGER, -- y - x INTEGER -- x -} - -END - - diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile index da31d87369..7be97abf66 100644 --- a/lib/ssh/src/Makefile +++ b/lib/ssh/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2004-2011. All Rights Reserved. +# Copyright Ericsson AB 2004-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -36,7 +36,11 @@ RELSYSDIR = $(RELEASE_PATH)/lib/ssh-$(VSN) # Common Macros # ---------------------------------------------------- +# Behaviour (api) modules are first so they are compiled when +# the compiler reaches a callback module using them. MODULES= \ + ssh_sftpd_file_api \ + ssh_key_api \ ssh \ ssh_sup \ sshc_sup \ @@ -56,25 +60,22 @@ MODULES= \ ssh_auth\ ssh_bits \ ssh_cli \ - ssh_dsa \ ssh_file \ ssh_io \ ssh_math \ ssh_no_io \ - ssh_rsa \ ssh_sftp \ ssh_sftpd \ ssh_sftpd_file\ - ssh_sftpd_file_api \ ssh_transport \ ssh_userreg \ ssh_xfer PUBLIC_HRL_FILES= ssh.hrl ssh_userauth.hrl ssh_xfer.hrl -ERL_FILES= $(MODULES:%=%.erl) $(ASN_ERLS) +ERL_FILES= $(MODULES:%=%.erl) -ALL_MODULES= $(MODULES) $(ASN_MODULES) +ALL_MODULES= $(MODULES) TARGET_FILES= $(ALL_MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET) @@ -87,22 +88,13 @@ APP_TARGET= $(EBIN)/$(APP_FILE) APPUP_SRC= $(APPUP_FILE).src APPUP_TARGET= $(EBIN)/$(APPUP_FILE) -ASN_MODULES = PKCS-1 DSS -ASN_ASNS = $(ASN_MODULES:%=%.asn1) -ASN_ERLS = $(ASN_MODULES:%=%.erl) -ASN_HRLS = $(ASN_MODULES:%=%.hrl) -ASN_DBS = $(ASN_MODULES:%=%.asn1db) -ASN_TABLES = $(ASN_MODULES:%=%.table) - -ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize +noobj +inline - -INTERNAL_HRL_FILES = $(ASN_HRLS) ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl +INTERNAL_HRL_FILES = ssh_auth.hrl ssh_connect.hrl ssh_transport.hrl # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- -ERL_COMPILE_FLAGS += -pa$(EBIN) - +ERL_COMPILE_FLAGS += -pa$(EBIN)\ + -pz $(ERL_TOP)/lib/public_key/ebin # ---------------------------------------------------- # Targets # ---------------------------------------------------- @@ -114,7 +106,6 @@ debug: ERLC_FLAGS += -Ddebug clean: rm -f $(TARGET_FILES) rm -f errs core *~ - rm -f $(ASN_ERLS) $(ASN_HRLS) $(ASN_DBS) $(TARGET_FILES): ssh.hrl @@ -127,10 +118,6 @@ $(APP_TARGET): $(APP_SRC) ../vsn.mk $(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk sed -e 's;%VSN%;$(VSN);' $< > $@ -%.erl %.hrl: %.asn1 - $(ERLC) $(ASN_FLAGS) $< - -$(EBIN)/ssh_file.$(EMULATOR) $(EBIN)/ssh_rsa.$(EMULATOR): $(ASN_HRLS) docs: diff --git a/lib/ssh/src/PKCS-1.asn1 b/lib/ssh/src/PKCS-1.asn1 deleted file mode 100644 index e7d6b18c63..0000000000 --- a/lib/ssh/src/PKCS-1.asn1 +++ /dev/null @@ -1,116 +0,0 @@ -PKCS-1 { - iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) - modules(0) pkcs-1(1) -} - --- $Revision: 1.1 $ - -DEFINITIONS EXPLICIT TAGS ::= - -BEGIN - --- IMPORTS id-sha256, id-sha384, id-sha512 --- FROM NIST-SHA2 { --- joint-iso-itu-t(2) country(16) us(840) organization(1) --- gov(101) csor(3) nistalgorithm(4) modules(0) sha2(1) --- }; - -pkcs-1 OBJECT IDENTIFIER ::= { - iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 -} - -rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 } - -id-RSAES-OAEP OBJECT IDENTIFIER ::= { pkcs-1 7 } - -id-pSpecified OBJECT IDENTIFIER ::= { pkcs-1 9 } - -id-RSASSA-PSS OBJECT IDENTIFIER ::= { pkcs-1 10 } - -md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 } -md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 } -sha1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } -sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } -sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } -sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } - -id-sha1 OBJECT IDENTIFIER ::= { - iso(1) identified-organization(3) oiw(14) secsig(3) - algorithms(2) 26 -} - -id-md2 OBJECT IDENTIFIER ::= { - iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 2 -} - -id-md5 OBJECT IDENTIFIER ::= { - iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5 -} - -id-mgf1 OBJECT IDENTIFIER ::= { pkcs-1 8 } - - -RSAPublicKey ::= SEQUENCE { - modulus INTEGER, -- n - publicExponent INTEGER -- e -} - -RSAPrivateKey ::= SEQUENCE { - version Version, - modulus INTEGER, -- n - publicExponent INTEGER, -- e - privateExponent INTEGER, -- d - prime1 INTEGER, -- p - prime2 INTEGER, -- q - exponent1 INTEGER, -- d mod (p-1) - exponent2 INTEGER, -- d mod (q-1) - coefficient INTEGER, -- (inverse of q) mod p - otherPrimeInfos OtherPrimeInfos OPTIONAL -} - -Version ::= INTEGER { two-prime(0), multi(1) } - (CONSTRAINED BY { - -- version must be multi if otherPrimeInfos present -- - }) - -OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo - -OtherPrimeInfo ::= SEQUENCE { - prime INTEGER, -- ri - exponent INTEGER, -- di - coefficient INTEGER -- ti -} - -Algorithm ::= SEQUENCE { - algorithm OBJECT IDENTIFIER, - parameters ANY DEFINED BY algorithm OPTIONAL -} - -AlgorithmNull ::= SEQUENCE { - algorithm OBJECT IDENTIFIER, - parameters NULL -} - - -RSASSA-PSS-params ::= SEQUENCE { - hashAlgorithm [0] Algorithm, -- DEFAULT sha1, - maskGenAlgorithm [1] Algorithm, -- DEFAULT mgf1SHA1, - saltLength [2] INTEGER DEFAULT 20, - trailerField [3] TrailerField DEFAULT trailerFieldBC -} - -TrailerField ::= INTEGER { trailerFieldBC(1) } - -DigestInfo ::= SEQUENCE { - digestAlgorithm Algorithm, - digest OCTET STRING -} - -DigestInfoNull ::= SEQUENCE { - digestAlgorithm AlgorithmNull, - digest OCTET STRING -} - - -END -- PKCS1Definitions - diff --git a/lib/ssh/src/prebuild.skip b/lib/ssh/src/prebuild.skip deleted file mode 100644 index 1d7552d98d..0000000000 --- a/lib/ssh/src/prebuild.skip +++ /dev/null @@ -1,2 +0,0 @@ -DSS.asn1db -PKCS-1.asn1db diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src index 8a3e15841f..7a58dbe54f 100644 --- a/lib/ssh/src/ssh.app.src +++ b/lib/ssh/src/ssh.app.src @@ -3,9 +3,7 @@ {application, ssh, [{description, "SSH-2 for Erlang/OTP"}, {vsn, "%VSN%"}, - {modules, ['DSS', - 'PKCS-1', - ssh, + {modules, [ssh, ssh_app, ssh_acceptor, ssh_acceptor_sup, @@ -21,12 +19,11 @@ ssh_shell, sshc_sup, sshd_sup, - ssh_dsa, ssh_file, ssh_io, + ssh_key_api, ssh_math, ssh_no_io, - ssh_rsa, ssh_sftp, ssh_sftpd, ssh_sftpd_file, diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index cada109df0..5751f2eaa0 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -23,6 +23,7 @@ -include("ssh.hrl"). -include("ssh_connect.hrl"). +-include_lib("public_key/include/public_key.hrl"). -export([start/0, start/1, stop/0, connect/3, connect/4, close/1, connection_info/2, channel_info/3, @@ -30,6 +31,9 @@ stop_listener/1, stop_listener/2, stop_daemon/1, stop_daemon/2, shell/1, shell/2, shell/3]). +-deprecated({sign_data, 2, next_major_release}). +-deprecated({verify_data, 3, next_major_release}). + -export([sign_data/2, verify_data/3]). %%-------------------------------------------------------------------- @@ -89,6 +93,9 @@ connect(Host, Port, Options, Timeout) -> %% might return undefined as the connection manager %% could allready have terminated, so we will not %% match the Manager in this case + {_, not_connected, {error, econnrefused}} when DisableIpv6 == false -> + do_demonitor(MRef, Manager), + connect(Host, Port, [{ip_v6_disabled, true} | Options], Timeout); {_, not_connected, {error, Reason}} -> do_demonitor(MRef, Manager), {error, Reason}; @@ -247,43 +254,6 @@ shell(Host, Port, Options) -> Error end. - -%%-------------------------------------------------------------------- -%% Function: sign_data(Data, Algorithm) -> binary() | -%% {error, Reason} -%% -%% Data = binary() -%% Algorithm = "ssh-rsa" -%% -%% Description: Use SSH key to sign data. -%%-------------------------------------------------------------------- -sign_data(Data, Algorithm) when is_binary(Data) -> - case ssh_file:private_identity_key(Algorithm,[]) of - {ok, Key} when Algorithm == "ssh-rsa" -> - ssh_rsa:sign(Key, Data); - Error -> - Error - end. - -%%-------------------------------------------------------------------- -%% Function: verify_data(Data, Signature, Algorithm) -> ok | -%% {error, Reason} -%% -%% Data = binary() -%% Signature = binary() -%% Algorithm = "ssh-rsa" -%% -%% Description: Use SSH signature to verify data. -%%-------------------------------------------------------------------- -verify_data(Data, Signature, Algorithm) when is_binary(Data), is_binary(Signature) -> - case ssh_file:public_identity_key(Algorithm, []) of - {ok, Key} when Algorithm == "ssh-rsa" -> - ssh_rsa:verify(Key, Data, Signature); - Error -> - Error - end. - - %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- @@ -336,6 +306,10 @@ handle_options([{connect_timeout, _} = Opt | Rest], SockOpts, Opts) -> handle_options(Rest, SockOpts, [Opt | Opts]); handle_options([{user, _} = Opt | Rest], SockOpts, Opts) -> handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{dsa_pass_phrase, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); +handle_options([{rsa_pass_phrase, _} = Opt | Rest], SockOpts, Opts) -> + handle_options(Rest, SockOpts, [Opt | Opts]); handle_options([{password, _} = Opt | Rest], SockOpts, Opts) -> handle_options(Rest, SockOpts, [Opt | Opts]); handle_options([{user_passwords, _} = Opt | Rest], SockOpts, Opts) -> @@ -379,6 +353,50 @@ handle_options([Opt | Rest], SockOpts, Opts) -> inetopt(true) -> inet; inetopt(false) -> - inet6. + case gen_tcp:listen(0, [inet6, {ip, loopback}]) of + {ok, Dummyport} -> + gen_tcp:close(Dummyport), + inet6; + _ -> + inet + end. + +%%% +%% Deprecated +%%% + +%%-------------------------------------------------------------------- +%% Function: sign_data(Data, Algorithm) -> binary() | +%% {error, Reason} +%% +%% Data = binary() +%% Algorithm = "ssh-rsa" +%% +%% Description: Use SSH key to sign data. +%%-------------------------------------------------------------------- +sign_data(Data, Algorithm) when is_binary(Data) -> + case ssh_file:user_key(Algorithm,[]) of + {ok, Key} when Algorithm == "ssh-rsa" -> + public_key:sign(Data, sha, Key); + Error -> + Error + end. +%%-------------------------------------------------------------------- +%% Function: verify_data(Data, Signature, Algorithm) -> ok | +%% {error, Reason} +%% +%% Data = binary() +%% Signature = binary() +%% Algorithm = "ssh-rsa" +%% +%% Description: Use SSH signature to verify data. +%%-------------------------------------------------------------------- +verify_data(Data, Signature, Algorithm) when is_binary(Data), is_binary(Signature) -> + case ssh_file:user_key(Algorithm, []) of + {ok, #'RSAPrivateKey'{publicExponent = E, modulus = N}} when Algorithm == "ssh-rsa" -> + public_key:verify(Data, sha, Signature, #'RSAPublicKey'{publicExponent = E, modulus = N}); + Error -> + Error + end. diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl index ac249b05e3..da5750b6c3 100644 --- a/lib/ssh/src/ssh.hrl +++ b/lib/ssh/src/ssh.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -54,18 +54,6 @@ -define(string(X), << ?STRING(list_to_binary(X)) >> ). -define(binary(X), << ?STRING(X) >>). --ifdef(debug). --define(dbg(Debug, Fmt, As), - case (Debug) of - true -> - io:format([$# | (Fmt)], (As)); - _ -> - ok - end). --else. --define(dbg(Debug, Fmt, As), ok). --endif. - -define(SSH_CIPHER_NONE, 0). -define(SSH_CIPHER_3DES, 3). -define(SSH_CIPHER_AUTHFILE, ?SSH_CIPHER_3DES). @@ -138,7 +126,8 @@ userauth_quiet_mode, % boolean() userauth_supported_methods , % userauth_methods, - userauth_preference + userauth_preference, + available_host_keys }). -record(alg, diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl index 9dbd95886e..62d684f4dc 100644 --- a/lib/ssh/src/ssh_auth.erl +++ b/lib/ssh/src/ssh_auth.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -21,8 +21,9 @@ -module(ssh_auth). --include("ssh.hrl"). +-include_lib("public_key/include/public_key.hrl"). +-include("ssh.hrl"). -include("ssh_auth.hrl"). -include("ssh_transport.hrl"). @@ -36,18 +37,21 @@ %%-------------------------------------------------------------------- %%% Internal application API %%-------------------------------------------------------------------- -publickey_msg([Cb, #ssh{user = User, +publickey_msg([Alg, #ssh{user = User, session_id = SessionId, service = Service, opts = Opts} = Ssh]) -> + + Hash = sha, %% Maybe option?! ssh_bits:install_messages(userauth_pk_messages()), - Alg = Cb:alg_name(), - case ssh_file:private_identity_key(Alg, Opts) of - {ok, PrivKey} -> - PubKeyBlob = ssh_file:encode_public_key(PrivKey), + KeyCb = proplists:get_value(key_cb, Opts, ssh_file), + + case KeyCb:user_key(Alg, Opts) of + {ok, Key} -> + PubKeyBlob = encode_public_key(Key), SigData = build_sig_data(SessionId, - User, Service, Alg, PubKeyBlob), - Sig = Cb:sign(PrivKey, SigData), + User, Service, PubKeyBlob, Alg), + Sig = ssh_transport:sign(SigData, Hash, Key), SigBlob = list_to_binary([?string(Alg), ?binary(Sig)]), ssh_transport:ssh_packet( #ssh_msg_userauth_request{user = User, @@ -58,8 +62,8 @@ publickey_msg([Cb, #ssh{user = User, ?binary(PubKeyBlob), ?binary(SigBlob)]}, Ssh); - _Error -> - not_ok + _Error -> + not_ok end. password_msg([#ssh{opts = Opts, io_cb = IoCb, @@ -67,29 +71,43 @@ password_msg([#ssh{opts = Opts, io_cb = IoCb, ssh_bits:install_messages(userauth_passwd_messages()), Password = case proplists:get_value(password, Opts) of undefined -> - IoCb:read_password("ssh password: "); + user_interaction(Opts, IoCb); PW -> PW end, - ssh_transport:ssh_packet( - #ssh_msg_userauth_request{user = User, - service = Service, - method = "password", - data = - <<?BOOLEAN(?FALSE), - ?STRING(list_to_binary(Password))>>}, - Ssh). + case Password of + not_ok -> + not_ok; + _ -> + ssh_transport:ssh_packet( + #ssh_msg_userauth_request{user = User, + service = Service, + method = "password", + data = + <<?BOOLEAN(?FALSE), + ?STRING(list_to_binary(Password))>>}, + Ssh) + end. + +user_interaction(Opts, IoCb) -> + case proplists:get_value(allow_user_interaction, Opts, true) of + true -> + IoCb:read_password("ssh password: "); + false -> + not_ok + end. + %% See RFC 4256 for info on keyboard-interactive keyboard_interactive_msg([#ssh{user = User, - service = Service} = Ssh]) -> + service = Service} = Ssh]) -> ssh_bits:install_messages(userauth_keyboard_interactive_messages()), ssh_transport:ssh_packet( #ssh_msg_userauth_request{user = User, service = Service, method = "keyboard-interactive", data = << ?STRING(<<"">>), - ?STRING(<<>>) >> }, + ?STRING(<<>>) >> }, Ssh). service_request_msg(Ssh) -> @@ -103,12 +121,12 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) -> service = "ssh-connection", method = "none", data = <<>>}, - CbFirst = proplists:get_value(public_key_alg, Opts, - ?PREFERRED_PK_ALG), - CbSecond = other_cb(CbFirst), + FirstAlg = algorithm(proplists:get_value(public_key_alg, Opts, + ?PREFERRED_PK_ALG)), + SecondAlg = other_alg(FirstAlg), AllowUserInt = proplists:get_value(allow_user_interaction, Opts, true), - Prefs = method_preference(CbFirst, CbSecond, AllowUserInt), + Prefs = method_preference(FirstAlg, SecondAlg, AllowUserInt), ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, userauth_preference = Prefs, userauth_methods = none, @@ -192,12 +210,12 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User, ?TRUE -> case verify_sig(SessionId, User, "ssh-connection", Alg, KeyBlob, SigWLen, Opts) of - ok -> + true -> {authorized, User, ssh_transport:ssh_packet( #ssh_msg_userauth_success{}, Ssh)}; - {error, Reason} -> - {not_authorized, {User, {error, Reason}}, + false -> + {not_authorized, {User, {error, "Invalid signature"}}, ssh_transport:ssh_packet(#ssh_msg_userauth_failure{ authentications="publickey,password", partial_success = false}, Ssh)} @@ -228,7 +246,6 @@ handle_userauth_info_request( PromptInfos = decode_keyboard_interactive_prompts(NumPrompts,Data), Resps = keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos), - %%?dbg(true, "keyboard_interactive_reply: resps=~n#~p ~n", [Resps]), RespBin = list_to_binary( lists:map(fun(S) -> <<?STRING(list_to_binary(S))>> end, Resps)), @@ -263,15 +280,15 @@ userauth_messages() -> %%-------------------------------------------------------------------- %%% Internal functions %%-------------------------------------------------------------------- -method_preference(Callback1, Callback2, true) -> - [{"publickey", ?MODULE, publickey_msg, [Callback1]}, - {"publickey", ?MODULE, publickey_msg,[Callback2]}, +method_preference(Alg1, Alg2, true) -> + [{"publickey", ?MODULE, publickey_msg, [Alg1]}, + {"publickey", ?MODULE, publickey_msg,[Alg2]}, {"password", ?MODULE, password_msg, []}, {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []} ]; -method_preference(Callback1, Callback2, false) -> - [{"publickey", ?MODULE, publickey_msg, [Callback1]}, - {"publickey", ?MODULE, publickey_msg,[Callback2]}, +method_preference(Alg1, Alg2, false) -> + [{"publickey", ?MODULE, publickey_msg, [Alg1]}, + {"publickey", ?MODULE, publickey_msg,[Alg2]}, {"password", ?MODULE, password_msg, []} ]. @@ -295,7 +312,6 @@ user_name(Opts) -> end. check_password(User, Password, Opts) -> - %%?dbg(true, " ~p ~p ~p ~n", [User, Password, Opts]), case proplists:get_value(pwdfun, Opts) of undefined -> Static = get_password_option(Opts, User), @@ -312,25 +328,22 @@ get_password_option(Opts, User) -> end. verify_sig(SessionId, User, Service, Alg, KeyBlob, SigWLen, Opts) -> - case ssh_file:lookup_user_key(User, Alg, Opts) of - {ok, OurKey} -> - {ok, Key} = ssh_file:decode_public_key_v2(KeyBlob, Alg), - case OurKey of - Key -> - NewSig = build_sig_data(SessionId, - User, Service, Alg, KeyBlob), - <<?UINT32(AlgSigLen), AlgSig:AlgSigLen/binary>> = SigWLen, - <<?UINT32(AlgLen), _Alg:AlgLen/binary, - ?UINT32(SigLen), Sig:SigLen/binary>> = AlgSig, - M = alg_to_module(Alg), - M:verify(OurKey, NewSig, Sig); - _ -> - {error, key_unacceptable} - end; - Error -> Error + {ok, Key} = decode_public_key_v2(KeyBlob, Alg), + KeyCb = proplists:get_value(key_cb, Opts, ssh_file), + + case KeyCb:is_auth_key(Key, User, Alg, Opts) of + true -> + PlainText = build_sig_data(SessionId, User, + Service, KeyBlob, Alg), + <<?UINT32(AlgSigLen), AlgSig:AlgSigLen/binary>> = SigWLen, + <<?UINT32(AlgLen), _Alg:AlgLen/binary, + ?UINT32(SigLen), Sig:SigLen/binary>> = AlgSig, + ssh_transport:verify(PlainText, sha, Sig, Key); + false -> + {error, key_unacceptable} end. -build_sig_data(SessionId, User, Service, Alg, KeyBlob) -> +build_sig_data(SessionId, User, Service, KeyBlob, Alg) -> Sig = [?binary(SessionId), ?SSH_MSG_USERAUTH_REQUEST, ?string(User), @@ -341,6 +354,11 @@ build_sig_data(SessionId, User, Service, Alg, KeyBlob) -> ?binary(KeyBlob)], list_to_binary(Sig). +algorithm(ssh_rsa) -> + "ssh-rsa"; +algorithm(ssh_dsa) -> + "ssh-dss". + decode_keyboard_interactive_prompts(NumPrompts, Data) -> Types = lists:append(lists:duplicate(NumPrompts, [string, boolean])), pairwise_tuplify(ssh_bits:decode(Data, Types)). @@ -412,12 +430,28 @@ userauth_pk_messages() -> binary]} % key blob ]. -alg_to_module("ssh-dss") -> - ssh_dsa; -alg_to_module("ssh-rsa") -> - ssh_rsa. - -other_cb(ssh_rsa) -> - ssh_dsa; -other_cb(ssh_dsa) -> - ssh_rsa. +other_alg("ssh-rsa") -> + "ssh-dss"; +other_alg("ssh-dss") -> + "ssh-rsa". +decode_public_key_v2(K_S, "ssh-rsa") -> + case ssh_bits:decode(K_S,[string,mpint,mpint]) of + ["ssh-rsa", E, N] -> + {ok, #'RSAPublicKey'{publicExponent = E, modulus = N}}; + _ -> + {error, bad_format} + end; +decode_public_key_v2(K_S, "ssh-dss") -> + case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of + ["ssh-dss",P,Q,G,Y] -> + {ok, {Y, #'Dss-Parms'{p = P, q = Q, g = G}}}; + _ -> + {error, bad_format} + end; +decode_public_key_v2(_, _) -> + {error, bad_format}. + +encode_public_key(#'RSAPrivateKey'{publicExponent = E, modulus = N}) -> + ssh_bits:encode(["ssh-rsa",E,N], [string,mpint,mpint]); +encode_public_key(#'DSAPrivateKey'{p = P, q = Q, g = G, y = Y}) -> + ssh_bits:encode(["ssh-dss",P,Q,G,Y], [string,mpint,mpint,mpint,mpint]). diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl index 3f0a06575c..5841f06d70 100644 --- a/lib/ssh/src/ssh_bits.erl +++ b/lib/ssh/src/ssh_bits.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. +%% Copyright Ericsson AB 2005-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -105,16 +105,12 @@ bignum(X) -> install_messages(Codes) -> foreach(fun({Name, Code, Ts}) -> - %% ?dbg(true, "install msg: ~s = ~w ~w~n", -%% [Name,Code,Ts]), put({msg_name,Code}, {Name,Ts}), put({msg_code,Name}, {Code,Ts}) end, Codes). uninstall_messages(Codes) -> foreach(fun({Name, Code, _Ts}) -> - %% ?dbg(true, "uninstall msg: ~s = ~w ~w~n", -%% [Name,Code,_Ts]), erase({msg_name,Code}), erase({msg_code,Name}) end, Codes). diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl index 7b9e9185bf..cb02d7b824 100644 --- a/lib/ssh/src/ssh_connection.erl +++ b/lib/ssh/src/ssh_connection.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -722,8 +722,6 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId, request_type = _Other, want_reply = WantReply}, Connection, ConnectionPid, _) -> - ?dbg(true, "ssh_msg ssh_msg_channel_request: Other=~p\n", - [_Other]), if WantReply == true -> FailMsg = channel_failure_msg(ChannelId), {{replies, [{connection_reply, ConnectionPid, FailMsg}]}, diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index 00b30e5434..9079089d5d 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -637,16 +637,18 @@ init_ssh(client = Role, Vsn, Version, Options, Socket) -> {ok, PeerAddr} = inet:peername(Socket), PeerName = proplists:get_value(host, Options), + KeyCb = proplists:get_value(key_cb, Options, ssh_file), #ssh{role = Role, c_vsn = Vsn, c_version = Version, - key_cb = proplists:get_value(key_cb, Options, ssh_file), + key_cb = KeyCb, io_cb = IOCb, userauth_quiet_mode = proplists:get_value(quiet_mode, Options, false), opts = Options, userauth_supported_methods = AuthMethods, - peer = {PeerName, PeerAddr} + peer = {PeerName, PeerAddr}, + available_host_keys = supported_host_keys(Role, KeyCb, Options) }; init_ssh(server = Role, Vsn, Version, Options, Socket) -> @@ -654,17 +656,48 @@ init_ssh(server = Role, Vsn, Version, Options, Socket) -> AuthMethods = proplists:get_value(auth_methods, Options, ?SUPPORTED_AUTH_METHODS), {ok, PeerAddr} = inet:peername(Socket), - + KeyCb = proplists:get_value(key_cb, Options, ssh_file), + #ssh{role = Role, s_vsn = Vsn, s_version = Version, - key_cb = proplists:get_value(key_cb, Options, ssh_file), + key_cb = KeyCb, io_cb = proplists:get_value(io_cb, Options, ssh_io), opts = Options, userauth_supported_methods = AuthMethods, - peer = {undefined, PeerAddr} + peer = {undefined, PeerAddr}, + available_host_keys = supported_host_keys(Role, KeyCb, Options) }. +supported_host_keys(client, _, _) -> + ["ssh-rsa", "ssh-dss"]; +supported_host_keys(server, KeyCb, Options) -> + lists:foldl(fun(Type, Acc) -> + case available_host_key(KeyCb, Type, Options) of + {error, _} -> + Acc; + Alg -> + [Alg | Acc] + end + end, [], + %% Prefered alg last so no need to reverse + ["ssh-dss", "ssh-rsa"]). + +available_host_key(KeyCb, "ssh-dss"= Alg, Opts) -> + case KeyCb:host_key('ssh-dss', Opts) of + {ok, _} -> + Alg; + Other -> + Other + end; +available_host_key(KeyCb, "ssh-rsa" = Alg, Opts) -> + case KeyCb:host_key('ssh-rsa', Opts) of + {ok, _} -> + Alg; + Other -> + Other + end. + send_msg(Msg, #state{socket = Socket, transport_cb = Transport}) -> Transport:send(Socket, Msg). diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl index 9bfd5270da..f729276e65 100644 --- a/lib/ssh/src/ssh_connection_manager.erl +++ b/lib/ssh/src/ssh_connection_manager.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -144,7 +144,7 @@ adjust_window(ConnectionManager, Channel, Bytes) -> cast(ConnectionManager, {adjust_window, Channel, Bytes}). close(ConnectionManager, ChannelId) -> - try call(ConnectionManager, {close, ChannelId}) of + try call(ConnectionManager, {close, ChannelId}) of ok -> ok; {error, channel_closed} -> @@ -604,6 +604,8 @@ call(Pid, Msg, Timeout) -> exit:{timeout, _} -> {error, timeout}; exit:{normal, _} -> + {error, channel_closed}; + exit:{noproc,_} -> {error, channel_closed} end. diff --git a/lib/ssh/src/ssh_dsa.erl b/lib/ssh/src/ssh_dsa.erl deleted file mode 100644 index cb2632beac..0000000000 --- a/lib/ssh/src/ssh_dsa.erl +++ /dev/null @@ -1,95 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% - -%% - -%%% Description: dsa public-key sign and verify - --module(ssh_dsa). - --export([verify/3]). --export([sign/2]). --export([alg_name/0]). - --include("ssh.hrl"). - -%% start() -> -%% crypto:start(). - -%% sign_file(File, Opts) -> -%% start(), -%% {ok,Bin} = file:read_file(File), -%% {ok,Key} = ssh_file:private_host_dsa_key(user, Opts), -%% sign(Key, Bin). - -%% verify_file(File, Sig) -> -%% start(), -%% {ok,Bin} = file:read_file(File), -%% {ok,Key} = ssh_file:public_host_key(user, dsa), -%% verify(Key, Bin, Sig). - -sign(_Private=#ssh_key { private={P,Q,G,X} },Mb) -> - K = ssh_bits:irandom(160) rem Q, - R = ssh_math:ipow(G, K, P) rem Q, - Ki = ssh_math:invert(K, Q), - <<M:160/big-unsigned-integer>> = crypto:sha(Mb), - S = (Ki * (M + X*R)) rem Q, - <<R:160/big-unsigned-integer, S:160/big-unsigned-integer>>. - - -%% the paramiko client sends a bad sig sometimes, -%% instead of crashing, we nicely return error, the -%% typcally manifests itself as Sb being 39 bytes -%% instead of 40. - -verify(Public, Mb, Sb) -> - case catch xverify(Public, Mb, Sb) of - {'EXIT', _Reason} -> - %store({Public, Mb, Sb, _Reason}), - {error, inconsistent_key}; - ok -> - %store({Public, Mb, Sb, ok}) - ok - end. - -%% store(Term) -> -%% {ok, Fd} = file:open("/tmp/dsa", [append]), -%% io:format(Fd, "~p~n~n~n", [Term]), -%% file:close(Fd). - - -xverify(_Public=#ssh_key { public={P,Q,G,Y} },Mb,Sb) -> - <<R0:160/big-unsigned-integer, S0:160/big-unsigned-integer>> = Sb, - ?ssh_assert(R0 >= 0 andalso R0 < Q andalso - S0 >= 0 andalso S0 < Q, out_of_range), - W = ssh_math:invert(S0,Q), - <<M0:160/big-unsigned-integer>> = crypto:sha(Mb), - U1 = (M0*W) rem Q, - U2 = (R0*W) rem Q, - T1 = ssh_math:ipow(G,U1,P), - T2 = ssh_math:ipow(Y,U2,P), - V = ((T1*T2) rem P) rem Q, - if V == R0 -> - ok; - true -> - {error, inconsistent_key} - end. - -alg_name() -> - "ssh-dss". diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl index 12180f56bb..d05fa8e09a 100644 --- a/lib/ssh/src/ssh_file.erl +++ b/lib/ssh/src/ssh_file.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. +%% Copyright Ericsson AB 2005-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -23,80 +23,98 @@ -module(ssh_file). --include("ssh.hrl"). --include("PKCS-1.hrl"). --include("DSS.hrl"). +-behaviour(ssh_key_api). +-include_lib("public_key/include/public_key.hrl"). -include_lib("kernel/include/file.hrl"). --export([public_host_dsa_key/2,private_host_dsa_key/2, - public_host_rsa_key/2,private_host_rsa_key/2, - public_host_key/2,private_host_key/2, - lookup_host_key/3, add_host_key/3, % del_host_key/2, - lookup_user_key/3, ssh_dir/2, file_name/3]). - --export([private_identity_key/2, - public_identity_key/2]). -%% identity_keys/2]). - --export([encode_public_key/1, decode_public_key_v2/2]). +-include("ssh.hrl"). --import(lists, [reverse/1, append/1]). +-export([host_key/2, + user_key/2, + is_host_key/4, + add_host_key/3, + is_auth_key/4]). --define(DBG_PATHS, true). -define(PERM_700, 8#700). -define(PERM_644, 8#644). + %% API -public_host_dsa_key(Type, Opts) -> - File = file_name(Type, "ssh_host_dsa_key.pub", Opts), - read_public_key_v2(File, "ssh-dss"). - -private_host_dsa_key(Type, Opts) -> - File = file_name(Type, "ssh_host_dsa_key", Opts), - read_private_key_v2(File, "ssh-dss"). - -public_host_rsa_key(Type, Opts) -> - File = file_name(Type, "ssh_host_rsa_key.pub", Opts), - read_public_key_v2(File, "ssh-rsa"). - -private_host_rsa_key(Type, Opts) -> - File = file_name(Type, "ssh_host_rsa_key", Opts), - read_private_key_v2(File, "ssh-rsa"). - -public_host_key(Type, Opts) -> - File = file_name(Type, "ssh_host_key", Opts), - case read_private_key_v1(File,public) of - {error, enoent} -> - read_public_key_v1(File++".pub"); - Result -> - Result - end. - -private_host_key(Type, Opts) -> - File = file_name(Type, "ssh_host_key", Opts), - read_private_key_v1(File,private). +%% Used by server +host_key(Algorithm, Opts) -> + File = file_name(system, file_base_name(Algorithm), Opts), + %% We do not expect host keys to have pass phrases + %% so probably we could hardcod Password = ignore, but + %% we keep it as an undocumented option for now. + Password = proplists:get_value(identity_pass_phrase(Algorithm), Opts, ignore), + decode(File, Password). +is_auth_key(Key, User, Alg, Opts) -> + case lookup_user_key(Key, User, Alg, Opts) of + {ok, Key} -> + true; + _ -> + false + end. -%% in: "host" out: "host,1.2.3.4. -add_ip(Host) -> - case inet:getaddr(Host, inet) of - {ok, Addr} -> - case ssh_connection:encode_ip(Addr) of - false -> Host; - IPString -> Host ++ "," ++ IPString - end; - _ -> Host - end. -replace_localhost("localhost") -> - {ok, Hostname} = inet:gethostname(), - Hostname; -replace_localhost(Host) -> - Host. +%% Used by client +is_host_key(Key, PeerName, Algorithm, Opts) -> + case lookup_host_key(PeerName, Algorithm, Opts) of + {ok, Key} -> + true; + _ -> + false + end. + +user_key(Algorithm, Opts) -> + File = file_name(user, identity_key_filename(Algorithm), Opts), + Password = proplists:get_value(identity_pass_phrase(Algorithm), Opts, ignore), + decode(File, Password). + + +%% Internal functions %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +file_base_name('ssh-rsa') -> + "ssh_host_rsa_key"; +file_base_name('ssh-dss') -> + "ssh_host_dsa_key"; +file_base_name(_) -> + "ssh_host_key". + +decode(File, Password) -> + try + {ok, decode_ssh_file(read_ssh_file(File), Password)} + catch + throw:Reason -> + {error, Reason}; + error:Reason -> + {error, Reason} + end. + +read_ssh_file(File) -> + {ok, Bin} = file:read_file(File), + Bin. + +%% Public key +decode_ssh_file(SshBin, public_key) -> + public_key:ssh_decode(SshBin, public_key); + +%% Private Key +decode_ssh_file(Pem, Password) -> + case public_key:pem_decode(Pem) of + [{_, _, not_encrypted} = Entry] -> + public_key:pem_entry_decode(Entry); + [Entry] when Password =/= ignore -> + public_key:pem_entry_decode(Entry, Password); + _ -> + throw("No pass phrase provided for private key file") + end. + %% lookup_host_key %% return {ok, Key(s)} or {error, not_found} @@ -106,15 +124,6 @@ lookup_host_key(Host, Alg, Opts) -> Host1 = replace_localhost(Host), do_lookup_host_key(Host1, Alg, Opts). -do_lookup_host_key(Host, Alg, Opts) -> - case file:open(file_name(user, "known_hosts", Opts), [read]) of - {ok, Fd} -> - Res = lookup_host_key_fd(Fd, Host, Alg), - file:close(Fd), - Res; - {error, enoent} -> {error, not_found}; - Error -> Error - end. add_host_key(Host, Key, Opts) -> Host1 = add_ip(replace_localhost(Host)), @@ -129,383 +138,16 @@ add_host_key(Host, Key, Opts) -> Error end. -%% del_host_key(Host, Opts) -> -%% Host1 = replace_localhost(Host), -%% case file:open(file_name(user, "known_hosts", Opts),[write,read]) of -%% {ok, Fd} -> -%% Res = del_key_fd(Fd, Host1), -%% file:close(Fd), -%% Res; -%% Error -> -%% Error -%% end. - -identity_key_filename("ssh-dss") -> "id_dsa"; -identity_key_filename("ssh-rsa") -> "id_rsa". - -private_identity_key(Alg, Opts) -> - Path = file_name(user, identity_key_filename(Alg), Opts), - read_private_key_v2(Path, Alg). - -public_identity_key(Alg, Opts) -> - Path = file_name(user, identity_key_filename(Alg) ++ ".pub", Opts), - read_public_key_v2(Path, Alg). - - -read_public_key_v2(File, Type) -> - case file:read_file(File) of - {ok,Bin} -> - List = binary_to_list(Bin), - case lists:prefix(Type, List) of - true -> - List1 = lists:nthtail(length(Type), List), - K_S = ssh_bits:b64_decode(List1), - decode_public_key_v2(K_S, Type); - false -> - {error, bad_format} - end; - Error -> - Error - end. - -decode_public_key_v2(K_S, "ssh-rsa") -> - case ssh_bits:decode(K_S,[string,mpint,mpint]) of - ["ssh-rsa", E, N] -> - {ok, #ssh_key { type = rsa, - public = {N,E}, - comment=""}}; - _ -> - {error, bad_format} - end; -decode_public_key_v2(K_S, "ssh-dss") -> - case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of - ["ssh-dss",P,Q,G,Y] -> - {ok,#ssh_key { type = dsa, - public = {P,Q,G,Y} - }}; - _A -> - {error, bad_format} - end; -decode_public_key_v2(_, _) -> - {error, bad_format}. - - -read_public_key_v1(File) -> - case file:read_file(File) of - {ok,Bin} -> - List = binary_to_list(Bin), - case io_lib:fread("~d ~d ~d ~s", List) of - {ok,[_Sz,E,N,Comment],_} -> - {ok,#ssh_key { type = rsa, - public ={N,E}, - comment = Comment }}; - _Error -> - {error, bad_format} - end; - Error -> - Error - end. - -%% pem_type("ssh-dss") -> "DSA"; -%% pem_type("ssh-rsa") -> "RSA". - -read_private_key_v2(File, Type) -> - case file:read_file(File) of - {ok, PemBin} -> - case catch (public_key:pem_decode(PemBin)) of - [{_, Bin, not_encrypted}] -> - decode_private_key_v2(Bin, Type); - Error -> %% Note we do not handle password encrypted keys at the moment - {error, Error} - end; - {error, Reason} -> - {error, Reason} - end. -%% case file:read_file(File) of -%% {ok,Bin} -> -%% case read_pem(binary_to_list(Bin), pem_type(Type)) of -%% {ok,Bin1} -> -%% decode_private_key_v2(Bin1, Type); -%% Error -> -%% Error -%% end; -%% Error -> -%% Error -%% end. - -decode_private_key_v2(Private,"ssh-rsa") -> - case 'PKCS-1':decode( 'RSAPrivateKey', Private) of - {ok,RSA} -> %% FIXME Check for two-prime version - {ok, #ssh_key { type = rsa, - public = {RSA#'RSAPrivateKey'.modulus, - RSA#'RSAPrivateKey'.publicExponent}, - private = {RSA#'RSAPrivateKey'.modulus, - RSA#'RSAPrivateKey'.privateExponent} - }}; - Error -> - Error - end; -decode_private_key_v2(Private, "ssh-dss") -> - case 'DSS':decode('DSAPrivateKey', Private) of - {ok,DSA} -> %% FIXME Check for two-prime version - {ok, #ssh_key { type = dsa, - public = {DSA#'DSAPrivateKey'.p, - DSA#'DSAPrivateKey'.q, - DSA#'DSAPrivateKey'.g, - DSA#'DSAPrivateKey'.y}, - private= {DSA#'DSAPrivateKey'.p, - DSA#'DSAPrivateKey'.q, - DSA#'DSAPrivateKey'.g, - DSA#'DSAPrivateKey'.x} - }}; - _ -> - {error,bad_format} - end. - -%% SSH1 private key format -%% <<"SSH PRIVATE KEY FILE FORMATE 1.1\n" 0:8 -%% CipherNum:8, Reserved:32, -%% NSz/uint32, N/bignum, E/bignum, Comment/string, -%% -%% [ R0:8 R1:8 R0:8 R1:8, D/bignum, IQMP/bignum, Q/bignum, P/bignum, Pad(8)]>> -%% -%% where [ ] is encrypted using des3 (ssh1 version) and -%% a posssibly empty pass phrase using md5(passphase) as key -%% - -read_private_key_v1(File, Type) -> - case file:read_file(File) of - {ok,<<"SSH PRIVATE KEY FILE FORMAT 1.1\n",0, - CipherNum,_Resereved:32,Bin/binary>>} -> - decode_private_key_v1(Bin, CipherNum,Type); - {ok,_} -> - {error, bad_format}; - Error -> - Error - end. - -decode_private_key_v1(Bin, CipherNum, Type) -> - case ssh_bits:decode(Bin,0,[uint32, bignum, bignum, string]) of - {Offset,[_NSz,N,E,Comment]} -> - if Type == public -> - {ok,#ssh_key { type=rsa, - public={N,E}, - comment=Comment}}; - Type == private -> - <<_:Offset/binary, Encrypted/binary>> = Bin, - case ssh_bits:decode(decrypt1(Encrypted, CipherNum),0, - [uint32, bignum, bignum, - bignum, bignum,{pad,8}]) of - {_,[_,D,IQMP,Q,P]} -> - {ok,#ssh_key { type=rsa, - public={N,E}, - private={D,IQMP,Q,P}, - comment=Comment}}; - _ -> - {error,bad_format} - end - end; - _ -> - {error,bad_format} - end. - - -decrypt1(Bin, CipherNum) -> - decrypt1(Bin, CipherNum,""). - -decrypt1(Bin, CipherNum, Phrase) -> - if CipherNum == ?SSH_CIPHER_NONE; Phrase == "" -> - Bin; - CipherNum == ?SSH_CIPHER_3DES -> - <<K1:8/binary, K2:8/binary>> = erlang:md5(Phrase), - K3 = K1, - IV = <<0,0,0,0,0,0,0,0>>, - Bin1 = crypto:des_cbc_decrypt(K3,IV,Bin), - Bin2 = crypto:des_cbc_encrypt(K2,IV,Bin1), - crypto:des_cbc_decrypt(K1,IV,Bin2) - end. - -%% encrypt1(Bin, CipherNum) -> -%% encrypt1(Bin, CipherNum,""). - -%% encrypt1(Bin, CipherNum, Phrase) -> -%% if CipherNum == ?SSH_CIPHER_NONE; Phrase == "" -> -%% Bin; -%% CipherNum == ?SSH_CIPHER_3DES -> -%% <<K1:8/binary, K2:8/binary>> = erlang:md5(Phrase), -%% K3 = K1, -%% IV = <<0,0,0,0,0,0,0,0>>, -%% Bin1 = crypto:des_cbc_encrypt(K1,IV,Bin), -%% Bin2 = crypto:des_cbc_decrypt(K2,IV,Bin1), -%% crypto:des_cbc_encrypt(K3,IV,Bin2) -%% end. - -lookup_host_key_fd(Fd, Host, Alg) -> - case io:get_line(Fd, '') of - eof -> - {error, not_found}; - Line -> - case string:tokens(Line, " ") of - [HostList, Alg, KeyData] -> -%% io:format(" ~p lookup_host_key_fd: HostList ~p Alg ~p KeyData ~p\n", -%% [Host, HostList, Alg, KeyData]), - case lists:member(Host, string:tokens(HostList, ",")) of - true -> - decode_public_key_v2(ssh_bits:b64_decode(KeyData), Alg); - false -> - lookup_host_key_fd(Fd, Host, Alg) - end; - _ -> - lookup_host_key_fd(Fd, Host, Alg) - end - end. - - - -%% del_key_fd(Fd, Host) -> -%% del_key_fd(Fd, Host, 0, 0). - -%% del_key_fd(Fd, Host, ReadPos0, WritePos0) -> -%% case io:get_line(Fd, '') of -%% eof -> -%% if ReadPos0 == WritePos0 -> -%% ok; -%% true -> -%% file:truncate(Fd) -%% end; -%% Line -> -%% {ok,ReadPos1} = file:position(Fd, cur), -%% case string:tokens(Line, " ") of -%% [HostList, _Type, _KeyData] -> -%% case lists:member(Host, string:tokens(HostList, ",")) of -%% true -> -%% del_key_fd(Fd, Host, ReadPos1, WritePos0); -%% false -> -%% if ReadPos0 == WritePos0 -> -%% del_key_fd(Fd, Host, ReadPos1, ReadPos1); -%% true -> -%% file:position(Fd, WritePos0), -%% file:write(Fd, Line), -%% {ok,WritePos1} = file:position(Fd,cur), -%% del_key_fd(Fd, Host, ReadPos1, WritePos1) -%% end -%% end; -%% _ -> -%% if ReadPos0 == WritePos0 -> -%% del_key_fd(Fd, Host, ReadPos1, ReadPos1); -%% true -> -%% file:position(Fd, WritePos0), -%% file:write(Fd, Line), -%% {ok,WritePos1} = file:position(Fd,cur), -%% del_key_fd(Fd, Host, ReadPos1, WritePos1) -%% end -%% end -%% end. - - -add_key_fd(Fd, Host, Key) -> - case Key#ssh_key.type of - rsa -> - {N,E} = Key#ssh_key.public, - DK = ssh_bits:b64_encode( - ssh_bits:encode(["ssh-rsa",E,N], - [string,mpint,mpint])), - file:write(Fd, [Host, " ssh-rsa ", DK, "\n"]); - dsa -> - {P,Q,G,Y} = Key#ssh_key.public, - DK = ssh_bits:b64_encode( - ssh_bits:encode(["ssh-dss",P,Q,G,Y], - [string,mpint,mpint,mpint,mpint])), - file:write(Fd, [Host, " ssh-dss ", DK, "\n"]) - end. - - -%% read_pem(Cs, Type) -> -%% case read_line(Cs) of -%% {"-----BEGIN "++Rest,Cs1} -> -%% case string:tokens(Rest, " ") of -%% [Type, "PRIVATE", "KEY-----"] -> -%% read_pem64(Cs1, [], Type); -%% _ -> -%% {error, bad_format} -%% end; -%% {"",Cs1} when Cs1 =/= "" -> -%% read_pem(Cs1,Type); -%% {_,""} -> -%% {error, bad_format} -%% end. - -%% read_pem64(Cs, Acc, Type) -> -%% case read_line(Cs) of -%% {"-----END "++Rest,_Cs1} -> -%% case string:tokens(Rest, " ") of -%% [Type, "PRIVATE", "KEY-----"] -> -%% {ok,ssh_bits:b64_decode(append(reverse(Acc)))}; -%% Toks -> -%% error_logger:format("ssh: TOKENS=~p\n", [Toks]), -%% {error, bad_format} -%% end; -%% {B64, Cs1} when Cs1 =/= "" -> -%% read_pem64(Cs1, [B64|Acc], Type); -%% _What -> -%% {error, bad_format} -%% end. - - -%% read_line(Cs) -> read_line(Cs,[]). -%% read_line([$\r,$\n|T], Acc) -> {reverse(Acc), T}; -%% read_line([$\n|T], Acc) -> {reverse(Acc), T}; -%% read_line([C|T], Acc) -> read_line(T,[C|Acc]); -%% read_line([], Acc) -> {reverse(Acc),[]}. - -lookup_user_key(User, Alg, Opts) -> +lookup_user_key(Key, User, Alg, Opts) -> SshDir = ssh_dir({remoteuser,User}, Opts), - case lookup_user_key_f(User, SshDir, Alg, "authorized_keys", Opts) of + case lookup_user_key_f(Key, User, SshDir, Alg, "authorized_keys", Opts) of {ok, Key} -> {ok, Key}; _ -> - lookup_user_key_f(User, SshDir, Alg, "authorized_keys2", Opts) - end. - -lookup_user_key_f(_User, [], _Alg, _F, _Opts) -> - {error, nouserdir}; -lookup_user_key_f(_User, nouserdir, _Alg, _F, _Opts) -> - {error, nouserdir}; -lookup_user_key_f(_User, Dir, Alg, F, _Opts) -> - FileName = filename:join(Dir, F), - case file:open(FileName, [read]) of - {ok, Fd} -> - Res = lookup_user_key_fd(Fd, Alg), - file:close(Fd), - Res; - {error, Reason} -> - {error, {{openerr, Reason}, {file, FileName}}} - end. - -lookup_user_key_fd(Fd, Alg) -> - case io:get_line(Fd, '') of - eof -> - {error, not_found}; - Line -> - case string:tokens(Line, " ") of - [Alg, KeyData, _] -> - %% io:format("lookup_user_key_fd: HostList ~p Alg ~p KeyData ~p\n", - %% [HostList, Alg, KeyData]), - decode_public_key_v2(ssh_bits:b64_decode(KeyData), Alg); - _Other -> - %%?dbg(false, "key_fd Other: ~w ~w\n", [Alg, _Other]), - lookup_user_key_fd(Fd, Alg) - end + lookup_user_key_f(Key, User, SshDir, Alg, "authorized_keys2", Opts) end. -encode_public_key(#ssh_key{type = rsa, public = {N, E}}) -> - ssh_bits:encode(["ssh-rsa",E,N], - [string,mpint,mpint]); -encode_public_key(#ssh_key{type = dsa, public = {P,Q,G,Y}}) -> - ssh_bits:encode(["ssh-dss",P,Q,G,Y], - [string,mpint,mpint,mpint,mpint]). - %% %% Utils %% @@ -537,11 +179,130 @@ ssh_dir(user, Opts) -> ssh_dir(system, Opts) -> proplists:get_value(system_dir, Opts, "/etc/ssh"). + file_name(Type, Name, Opts) -> FN = filename:join(ssh_dir(Type, Opts), Name), - %%?dbg(?DBG_PATHS, "file_name: ~p\n", [FN]), FN. + + +%% in: "host" out: "host,1.2.3.4. +add_ip(Host) -> + case inet:getaddr(Host, inet) of + {ok, Addr} -> + case ssh_connection:encode_ip(Addr) of + false -> Host; + IPString -> Host ++ "," ++ IPString + end; + _ -> Host + end. + +replace_localhost("localhost") -> + {ok, Hostname} = inet:gethostname(), + Hostname; +replace_localhost(Host) -> + Host. + +do_lookup_host_key(Host, Alg, Opts) -> + case file:open(file_name(user, "known_hosts", Opts), [read, binary]) of + {ok, Fd} -> + Res = lookup_host_key_fd(Fd, Host, Alg), + file:close(Fd), + {ok, Res}; + {error, enoent} -> {error, not_found}; + Error -> Error + end. + +identity_key_filename("ssh-dss") -> + "id_dsa"; +identity_key_filename("ssh-rsa") -> + "id_rsa". + +identity_pass_phrase("ssh-dss") -> + dsa_pass_phrase; +identity_pass_phrase('ssh-dss') -> + dsa_pass_phrase; +identity_pass_phrase('ssh-rsa') -> + rsa_pass_phrase; +identity_pass_phrase("ssh-rsa") -> + rsa_pass_phrase. + +lookup_host_key_fd(Fd, Host, KeyType) -> + case io:get_line(Fd, '') of + eof -> + {error, not_found}; + Line -> + case public_key:ssh_decode(Line, known_hosts) of + [{Key, Attributes}] -> + handle_host(Fd, Host, proplists:get_value(hostnames, Attributes), Key, KeyType); + [] -> + lookup_host_key_fd(Fd, Host, KeyType) + end + end. + +handle_host(Fd, Host, HostList, Key, KeyType) -> + Host1 = host_name(Host), + case lists:member(Host1, HostList) and key_match(Key, KeyType) of + true -> + Key; + false -> + lookup_host_key_fd(Fd, Host, KeyType) + end. + +host_name(Atom) when is_atom(Atom) -> + atom_to_list(Atom); +host_name(List) -> + List. + +key_match(#'RSAPublicKey'{}, "ssh-rsa") -> + true; +key_match({_, #'Dss-Parms'{}}, "ssh-dss") -> + true; +key_match(_, _) -> + false. + +add_key_fd(Fd, Host,Key) -> + SshBin = public_key:ssh_encode([{Key, [{hostnames, [Host]}]}], known_hosts), + file:write(Fd, SshBin). + +lookup_user_key_f(_, _User, [], _Alg, _F, _Opts) -> + {error, nouserdir}; +lookup_user_key_f(_, _User, nouserdir, _Alg, _F, _Opts) -> + {error, nouserdir}; +lookup_user_key_f(Key, _User, Dir, _Alg, F, _Opts) -> + FileName = filename:join(Dir, F), + case file:open(FileName, [read, binary]) of + {ok, Fd} -> + Res = lookup_user_key_fd(Fd, Key), + file:close(Fd), + Res; + {error, Reason} -> + {error, {{openerr, Reason}, {file, FileName}}} + end. + +lookup_user_key_fd(Fd, Key) -> + case io:get_line(Fd, '') of + eof -> + {error, not_found}; + Line -> + case public_key:ssh_decode(Line, auth_keys) of + [{AuthKey, _}] -> + case is_auth_key(Key, AuthKey) of + true -> + {ok, Key}; + false -> + lookup_user_key_fd(Fd, Key) + end; + [] -> + lookup_user_key_fd(Fd, Key) + end + end. + +is_auth_key(Key, Key) -> + true; +is_auth_key(_,_) -> + false. + default_user_dir()-> {ok,[[Home|_]]} = init:get_argument(home), UserDir = filename:join(Home, ".ssh"), diff --git a/lib/ssh/src/ssh_key_api.erl b/lib/ssh/src/ssh_key_api.erl new file mode 100644 index 0000000000..8085c12e21 --- /dev/null +++ b/lib/ssh/src/ssh_key_api.erl @@ -0,0 +1,45 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011-2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(ssh_key_api). + +-include_lib("public_key/include/public_key.hrl"). +-include("ssh.hrl"). + +-type ssh_algorithm() :: string(). +-type file_error() :: file:posix() | badarg | system_limit | terminated. + +-callback host_key(Algorithm :: ssh_algorithm(), Options :: list()) -> + {ok, [{public_key(), Attributes::list()}]} | public_key() + | {error, string()}. + +-callback user_key(Algorithm :: ssh_algorithm(), Options :: list()) -> + {ok, [{public_key(), Attributes::list()}]} | public_key() + | {error, string()}. + +-callback is_host_key(Key :: public_key(), PeerName :: string(), + Algorithm :: ssh_algorithm(), Options :: list()) -> + boolean(). + +-callback add_host_key(Host :: string(), Key :: public_key(), Options :: list()) -> + ok | {error, file_error()}. + +-callback is_auth_key(Key :: public_key(), User :: string(), + Algorithm :: ssh_algorithm(), Options :: list()) -> + boolean(). diff --git a/lib/ssh/src/ssh_rsa.erl b/lib/ssh/src/ssh_rsa.erl deleted file mode 100644 index 77c411b09f..0000000000 --- a/lib/ssh/src/ssh_rsa.erl +++ /dev/null @@ -1,298 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% - -%% - -%%% Description: rsa public-key sign and verify - --module(ssh_rsa). - --export([verify/3, sign/2]). --export([alg_name/0]). - --include("ssh.hrl"). --include("PKCS-1.hrl"). - - --define(MGF(Seed,Len), mgf1((Seed),(Len))). --define(HASH(X), crypto:sha((X))). --define(HLen, 20). - -%% start() -> -%% crypto:start(). - -%% sign_file(File) -> -%% start(), -%% {ok,Bin} = file:read_file(File), -%% {ok,Key} = ssh_file:private_host_rsa_key(user), -%% sign(Key, Bin). - -%% verify_file(File, Sig) -> -%% start(), -%% {ok,Bin} = file:read_file(File), -%% {ok,Key} = ssh_file:public_host_rsa_key(user), -%% verify(Key, Bin, Sig). - -sign(Private,Mb) -> - rsassa_pkcs1_v1_5_sign(Private,Mb). - -verify(Public,Mb,Sb) -> - rsassa_pkcs1_v1_5_verify(Public,Mb,Sb). - - - -%% Integer to octet string -i2osp(X, XLen) -> - ssh_bits:i2bin(X, XLen). - -%% Octet string to Integer -os2ip(X) -> - ssh_bits:bin2i(X). - -%% decrypt1, M = message representative -%% rsaep(#ssh_key { public={N,E}}, M) -> -%% ?ssh_assert(M >= 0 andalso M =< N-1, out_of_range), -%% ssh_math:ipow(M, E, N). - -%% encrypt1, C = cipher representative -%% rsadp(#ssh_key { public={N,_}, private={_,D}}, C) -> -%% ?ssh_assert(C >= 0 andalso C =< N-1, out_of_range), -%% ssh_math:ipow(C, D, N). - -%% sign1, M = message representative -rsasp1(#ssh_key { public={N,_}, private={_,D}}, M) -> - ?ssh_assert((M >= 0 andalso M =< N-1), out_of_range), - ssh_math:ipow(M, D, N). - -%% verify1, S =signature representative -rsavp1(#ssh_key { public={N,E}}, S) -> - ?ssh_assert(S >= 0 andalso S =< N-1, out_of_range), - ssh_math:ipow(S, E, N). - - -%% M messaage -%% rsaes_oaep_encrypt(Public, M) -> -%% rsaes_oaep_encrypt(Public, M, <<>>). - -%% rsaes_oaep_encrypt(Public=#ssh_key { public={N,_E}}, M, L) -> -%% ?ssh_assert(size(L) =< 16#ffffffffffffffff, label_to_long), -%% K = (ssh_bits:isize(N)+7) div 8, -%% MLen = size(M), -%% %% LLen = size(L), -%% ?ssh_assert(MLen =< K - 2*?HLen - 2, message_to_long), -%% LHash = ?HASH(L), -%% PS = ssh_bits:fill_bits(K - MLen - 2*?HLen - 2, 0), -%% DB = <<LHash/binary, PS/binary, 16#01, M/binary>>, -%% Seed = ssh_bits:random(?HLen), -%% DbMask = ?MGF(Seed, K - ?HLen - 1), -%% MaskedDB = ssh_bits:xor_bits(DB, DbMask), -%% SeedMask = ?MGF(MaskedDB, ?HLen), -%% MaskedSeed = ssh_bits:xor_bits(Seed, SeedMask), -%% EM = <<16#00, MaskedSeed/binary, MaskedDB/binary>>, -%% Mc = os2ip(EM), -%% C = rsaep(Public, Mc), -%% i2osp(C, K). - -%% rsaes_oaep_decrypt(Key, C) -> -%% rsaes_oaep_decrypt(Key, C, <<>>). - -%% rsaes_oaep_decrypt(Private=#ssh_key { public={N,_},private={_,_}},Cb,L) -> -%% ?ssh_assert(size(L) =< 16#ffffffffffffffff, label_to_long), -%% K = (ssh_bits:isize(N)+7) div 8, -%% ?ssh_assert(K == 2*?HLen + 2, decryption_error), -%% C = os2ip(Cb), -%% M = rsadp(Private, C), -%% EM = i2osp(M, K), -%% LHash = ?HASH(L), -%% MLen = K - ?HLen -1, -%% case EM of -%% <<16#00, MaskedSeed:?HLen/binary, MaskedDB:MLen>> -> -%% SeedMask = ?MGF(MaskedDB, ?HLen), -%% Seed = ssh_bits:xor_bits(MaskedSeed, SeedMask), -%% DbMask = ?MGF(Seed, K - ?HLen - 1), -%% DB = ssh_bits:xor_bits(MaskedDB, DbMask), -%% PSLen = K - MLen - 2*?HLen - 2, -%% case DB of -%% <<LHash:?HLen, _PS:PSLen/binary, 16#01, M/binary>> -> -%% M; -%% _ -> -%% exit(decryption_error) -%% end; -%% _ -> -%% exit(decryption_error) -%% end. - - -%% rsaes_pkcs1_v1_5_encrypt(Public=#ssh_key { public={N,_}}, M) -> -%% K = (ssh_bits:isize(N)+7) div 8, -%% MLen = size(M), -%% ?ssh_assert(MLen =< K - 11, message_to_long), -%% PS = ssh_bits:random(K - MLen - 3), -%% EM = <<16#00,16#02,PS/binary,16#00,M/binary>>, -%% Mc = os2ip(EM), -%% C = rsaep(Public, Mc), -%% i2osp(C, K). - - -%% rsaes_pkcs1_v1_5_decrypt(Private=#ssh_key { public={N,_},private={_,_}}, -%% Cb) -> -%% K = (ssh_bits:isize(N)+7) div 8, -%% CLen = size(Cb), -%% ?ssh_assert(CLen == K andalso K >= 11, decryption_error), -%% C = os2ip(Cb), -%% M = rsadp(Private, C), -%% EM = i2osp(M, K), -%% PSLen = K - CLen - 3, -%% case EM of -%% <<16#00, 16#02, _PS:PSLen/binary, 16#00, M>> -> -%% M; -%% _ -> -%% exit(decryption_error) -%% end. - -%% rsassa_pss_sign(Private=#ssh_key { public={N,_},private={_,_}},Mb) -> -%% ModBits = ssh_bits:isize(N), -%% K = (ModBits+7) div 8, -%% EM = emsa_pss_encode(Mb, ModBits - 1), -%% M = os2ip(EM), -%% S = rsasp1(Private, M), -%% i2osp(S, K). - -%% rsassa_pss_verify(Public=#ssh_key { public={N,_E}},Mb,Sb) -> -%% ModBits = ssh_bits:isize(N), -%% K = (ModBits+7) div 8, -%% ?ssh_assert(size(Sb) == K, invalid_signature), -%% S = os2ip(Sb), -%% M = rsavp1(Public,S), -%% EMLen = (ModBits-1+7) div 8, -%% EM = i2osp(M, EMLen), -%% emsa_pss_verify(Mb, EM, ModBits-1). - - -rsassa_pkcs1_v1_5_sign(Private=#ssh_key { public={N,_},private={_,_D}},Mb) -> - K = (ssh_bits:isize(N)+7) div 8, - EM = emsa_pkcs1_v1_5_encode(Mb, K), - M = os2ip(EM), - S = rsasp1(Private, M), - i2osp(S, K). - -rsassa_pkcs1_v1_5_verify(Public=#ssh_key { public={N,_E}}, Mb, Sb) -> - K = (ssh_bits:isize(N)+7) div 8, - ?ssh_assert(size(Sb) == K, invalid_signature), - S = os2ip(Sb), - M = rsavp1(Public, S), - EM = i2osp(M, K), - %?dbg(true, "verify K=~p S=~w ~n#M=~w~n#EM=~w~n", [K, S, M, EM]), - case emsa_pkcs1_v1_5_encode(Mb, K) of - EM -> ok; - _S -> - {error, invalid_signature} - end. - - -emsa_pkcs1_v1_5_encode(M, EMLen) -> - H = ?HASH(M), - %% Must use speical xxNull types here! - Alg = #'AlgorithmNull' { algorithm = ?'id-sha1', - parameters = <<>> }, - {ok,TCode} = 'PKCS-1':encode('DigestInfoNull', - #'DigestInfoNull'{ digestAlgorithm = Alg, - digest = H }), - T = list_to_binary(TCode), - TLen = size(T), - ?ssh_assert(EMLen >= TLen + 11, message_to_short), - PS = ssh_bits:fill_bits(EMLen - TLen - 3, 16#ff), - <<16#00, 16#01, PS/binary, 16#00, T/binary>>. - - -%% emsa_pss_encode(M, EMBits) -> -%% emsa_pss_encode(M, EMBits, 0). - -%% emsa_pss_encode(M, EMBits, SLen) -> -%% ?ssh_assert(size(M) =< 16#ffffffffffffffff, message_to_long), -%% EMLen = (EMBits + 7) div 8, -%% MHash = ?HASH(M), -%% ?ssh_assert(EMLen >= ?HLen + SLen + 2, encoding_error), -%% Salt = ssh_bits:random(SLen), -%% M1 = [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, -%% MHash, Salt], -%% H = ?HASH(M1), -%% PS = ssh_bits:fill_bits(EMLen-SLen-?HLen-2, 0), -%% DB = <<PS/binary, 16#01, Salt/binary>>, -%% DbMask = ?MGF(H, EMLen - ?HLen -1), -%% MaskedDB = ssh_bits:xor_bits(DB, DbMask), -%% ZLen = 8*EMLen - EMBits, -%% NZLen = (8 - (ZLen rem 8)) rem 8, -%% <<_:ZLen, NZ:NZLen, MaskedDB1/binary>> = MaskedDB, -%% MaskedDB2 = <<0:ZLen, NZ:NZLen, MaskedDB1/binary>>, -%% <<MaskedDB2/binary, H/binary, 16#BC>>. - - -%% emsa_pss_verify(M, EM, EMBits) -> -%% emsa_pss_verify(M, EM, EMBits, 0). - -%% emsa_pss_verify(M, EM, EMBits, SLen) -> -%% ?ssh_assert(size(M) =< 16#ffffffffffffffff, message_to_long), -%% EMLen = (EMBits + 7) div 8, -%% MHash = ?HASH(M), -%% ?ssh_assert(EMLen >= ?HLen + SLen + 2, inconsistent), -%% MaskLen = (EMLen - ?HLen - 1)-1, -%% ZLen = 8*EMLen - EMBits, -%% NZLen = (8 - (ZLen rem 8)) rem 8, -%% case EM of -%% <<0:ZLen,Nz:NZLen,MaskedDB1:MaskLen/binary, H:?HLen/binary, 16#BC>> -> -%% MaskedDB = <<0:ZLen,Nz:NZLen,MaskedDB1/binary>>, -%% DbMask = ?MGF(H, EMLen - ?HLen - 1), -%% DB = ssh_bits:xor_bits(MaskedDB, DbMask), -%% PSLen1 = (EMLen - SLen - ?HLen - 2) - 1, -%% PS = ssh_bits:fill_bits(PSLen1, 0), -%% case DB of -%% <<_:ZLen,0:NZLen,PS:PSLen1/binary,16#01,Salt:SLen/binary>> -> -%% M1 = [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00, -%% MHash, Salt], -%% case ?HASH(M1) of -%% H -> ok; -%% _ -> exit(inconsistent) -%% end; -%% _ -> -%% exit(inconsistent) -%% end; -%% _ -> -%% exit(inconsistent) -%% end. - - - -%% Mask generating function MGF1 -%% mgf1(MGFSeed, MaskLen) -> -%% T = mgf1_loop(0, ((MaskLen + ?HLen -1) div ?HLen) - 1, MGFSeed, ""), -%% <<R:MaskLen/binary, _/binary>> = T, -%% R. - -%% mgf1_loop(Counter, N, _, T) when Counter > N -> -%% list_to_binary(T); -%% mgf1_loop(Counter, N, MGFSeed, T) -> -%% C = i2osp(Counter, 4), -%% mgf1_loop(Counter+1, N, MGFSeed, [T, ?HASH([MGFSeed, C])]). - - - - -alg_name() -> - "ssh-rsa". diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl index da91817fd7..8cc414f83a 100644 --- a/lib/ssh/src/ssh_sftpd.erl +++ b/lib/ssh/src/ssh_sftpd.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -231,8 +231,6 @@ handle_op(?SSH_FXP_REALPATH, ReqId, case Res of {ok, AbsPath} -> NewAbsPath = chroot_filename(AbsPath, State), - ?dbg(true, "handle_op ?SSH_FXP_REALPATH: RelPath=~p AbsPath=~p\n", - [RelPath, NewAbsPath]), XF = State#state.xf, Attr = #ssh_xfer_attr{type=directory}, ssh_xfer:xf_send_name(XF, ReqId, NewAbsPath, Attr), @@ -463,7 +461,6 @@ get_handle(Handles, BinHandle) -> read_dir(State0 = #state{file_handler = FileMod, max_files = MaxLength, file_state = FS0}, XF, ReqId, Handle, RelPath, {cache, Files}) -> AbsPath = relate_file_name(RelPath, State0), - ?dbg(true, "read_dir: AbsPath=~p\n", [AbsPath]), if length(Files) > MaxLength -> {ToSend, NewCache} = lists:split(MaxLength, Files), @@ -484,7 +481,6 @@ read_dir(State0 = #state{file_handler = FileMod, max_files = MaxLength, file_sta read_dir(State0 = #state{file_handler = FileMod, max_files = MaxLength, file_state = FS0}, XF, ReqId, Handle, RelPath, _Status) -> AbsPath = relate_file_name(RelPath, State0), - ?dbg(true, "read_dir: AbsPath=~p\n", [AbsPath]), {Res, FS1} = FileMod:list_dir(AbsPath, FS0), case Res of {ok, Files} when MaxLength == 0 orelse MaxLength > length(Files) -> @@ -516,7 +512,6 @@ get_attrs(_RelPath, [], _FileMod, FS, Acc) -> {lists:reverse(Acc), FS}; get_attrs(RelPath, [F | Rest], FileMod, FS0, Acc) -> Path = filename:absname(F, RelPath), - ?dbg(true, "get_attrs fun: F=~p\n", [F]), case FileMod:read_link_info(Path, FS0) of {{ok, Info}, FS1} -> Attrs = ssh_sftp:info_to_attr(Info), @@ -560,7 +555,6 @@ stat(ReqId, RelPath, State0=#state{file_handler=FileMod, file_state=FS0}, F) -> AbsPath = relate_file_name(RelPath, State0), XF = State0#state.xf, - ?dbg(false, "stat: AbsPath=~p\n", [AbsPath]), {Res, FS1} = FileMod:F(AbsPath, FS0), State1 = State0#state{file_state = FS1}, case Res of @@ -605,6 +599,8 @@ decode_4_access_flag(add_subdirectory) -> [read]; decode_4_access_flag(append_data) -> [append]; +decode_4_access_flag(write_attributes) -> + [write]; decode_4_access_flag(_) -> [read]. @@ -619,8 +615,7 @@ open(Vsn, ReqId, Data, State) when Vsn =< 3 -> <<?UINT32(BLen), BPath:BLen/binary, ?UINT32(PFlags), _Attrs/binary>> = Data, Path = binary_to_list(BPath), - Flags = ssh_xfer:decode_open_flags(Vsn, PFlags) -- [creat, excl, trunc], - ?dbg(true, "open: Flags=~p\n", [Flags]), + Flags = ssh_xfer:decode_open_flags(Vsn, PFlags), do_open(ReqId, State, Path, Flags); open(Vsn, ReqId, Data, State) when Vsn >= 4 -> <<?UINT32(BLen), BPath:BLen/binary, ?UINT32(Access), @@ -628,7 +623,6 @@ open(Vsn, ReqId, Data, State) when Vsn >= 4 -> Path = binary_to_list(BPath), FlagBits = ssh_xfer:decode_open_flags(Vsn, PFlags), AcessBits = ssh_xfer:decode_ace_mask(Access), - ?dbg(true, "open: Fl=~p\n", [FlagBits]), %% TODO: This is to make sure the Access flags are not ignored %% but this should be thought through better. This solution should %% be considered a hack in order to buy some time. At least @@ -638,15 +632,12 @@ open(Vsn, ReqId, Data, State) when Vsn >= 4 -> AcessFlags = decode_4_acess(AcessBits), Flags = lists:append(lists:umerge( [[decode_4_flags(FlagBits)] | AcessFlags])), - - ?dbg(true, "open: Flags=~p\n", [Flags]), - do_open(ReqId, State, Path, Flags). do_open(ReqId, State0, Path, Flags) -> #state{file_handler = FileMod, file_state = FS0, root = Root} = State0, XF = State0#state.xf, - F = [raw, binary | Flags], + F = [binary | Flags], %% case FileMod:is_dir(Path) of %% This is version 6 we still have 5 %% true -> %% ssh_xfer:xf_send_status(State#state.xf, ReqId, @@ -895,14 +886,11 @@ set_stat(Attr, Path, State0 = #state{file_handler=FileMod, file_state=FS0}) -> {DecodedAttr, _Rest} = ssh_xfer:decode_ATTR((State0#state.xf)#ssh_xfer.vsn, Attr), - ?dbg(true, "set_stat DecodedAttr=~p\n", [DecodedAttr]), Info = ssh_sftp:attr_to_info(DecodedAttr), {Res1, FS1} = FileMod:read_link_info(Path, FS0), case Res1 of {ok, OldInfo} -> NewInfo = set_file_info(Info, OldInfo), - ?dbg(true, "set_stat Path=~p\nInfo=~p\nOldInfo=~p\nNewInfo=~p\n", - [Path, Info, OldInfo, NewInfo]), {Res2, FS2} = FileMod:write_file_info(Path, NewInfo, FS1), State1 = State0#state{file_state = FS2}, {Res2, State1}; diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl index de3e29e2f1..6140c87f6e 100644 --- a/lib/ssh/src/ssh_transport.erl +++ b/lib/ssh/src/ssh_transport.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -23,10 +23,11 @@ -module(ssh_transport). --include("ssh_transport.hrl"). +-include_lib("public_key/include/public_key.hrl"). +-include_lib("kernel/include/inet.hrl"). +-include("ssh_transport.hrl"). -include("ssh.hrl"). --include_lib("kernel/include/inet.hrl"). -export([connect/5, accept/4]). -export([versions/2, hello_version_msg/1]). @@ -38,17 +39,8 @@ handle_kex_dh_gex_group/2, handle_kex_dh_gex_reply/2, handle_new_keys/2, handle_kex_dh_gex_request/2, handle_kexdh_reply/2, - unpack/3, decompress/2, ssh_packet/2, pack/2, msg_data/1]). - -%% debug flagso --define(DBG_ALG, true). --define(DBG_KEX, true). --define(DBG_CRYPTO, false). --define(DBG_PACKET, false). --define(DBG_MESSAGE, true). --define(DBG_BIN_MESSAGE, true). --define(DBG_MAC, false). --define(DBG_ZLIB, true). + unpack/3, decompress/2, ssh_packet/2, pack/2, msg_data/1, + sign/3, verify/4]). versions(client, Options)-> Vsn = proplists:get_value(vsn, Options, ?DEFAULT_CLIENT_VERSION), @@ -212,24 +204,24 @@ key_exchange_init_msg(Ssh0) -> {SshPacket, Ssh} = ssh_packet(Msg, Ssh0), {Msg, SshPacket, Ssh}. -kex_init(#ssh{role = Role, opts = Opts}) -> +kex_init(#ssh{role = Role, opts = Opts, available_host_keys = HostKeyAlgs}) -> Random = ssh_bits:random(16), Compression = case proplists:get_value(compression, Opts, none) of zlib -> ["zlib", "none"]; none -> ["none", "zlib"] end, - kexinit_messsage(Role, Random, Compression). + kexinit_messsage(Role, Random, Compression, HostKeyAlgs). key_init(client, Ssh, Value) -> Ssh#ssh{c_keyinit = Value}; key_init(server, Ssh, Value) -> Ssh#ssh{s_keyinit = Value}. -kexinit_messsage(client, Random, Compression) -> +kexinit_messsage(client, Random, Compression, HostKeyAlgs) -> #ssh_msg_kexinit{ cookie = Random, kex_algorithms = ["diffie-hellman-group1-sha1"], - server_host_key_algorithms = ["ssh-rsa", "ssh-dss"], + server_host_key_algorithms = HostKeyAlgs, encryption_algorithms_client_to_server = ["aes128-cbc","3des-cbc"], encryption_algorithms_server_to_client = ["aes128-cbc","3des-cbc"], mac_algorithms_client_to_server = ["hmac-sha1"], @@ -240,11 +232,11 @@ kexinit_messsage(client, Random, Compression) -> languages_server_to_client = [] }; -kexinit_messsage(server, Random, Compression) -> +kexinit_messsage(server, Random, Compression, HostKeyAlgs) -> #ssh_msg_kexinit{ cookie = Random, kex_algorithms = ["diffie-hellman-group1-sha1"], - server_host_key_algorithms = ["ssh-dss"], + server_host_key_algorithms = HostKeyAlgs, encryption_algorithms_client_to_server = ["aes128-cbc","3des-cbc"], encryption_algorithms_server_to_client = ["aes128-cbc","3des-cbc"], mac_algorithms_client_to_server = ["hmac-sha1"], @@ -300,7 +292,6 @@ install_messages('diffie-hellman-group-exchange-sha1') -> key_exchange_first_msg('diffie-hellman-group1-sha1', Ssh0) -> {G, P} = dh_group1(), {Private, Public} = dh_gen_key(G, P, 1024), - %%?dbg(?DBG_KEX, "public: ~p~n", [Public]), {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_init{e = Public}, Ssh0), {ok, SshPacket, Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}}}}; @@ -320,7 +311,6 @@ key_exchange_first_msg('diffie-hellman-group-exchange-sha1', Ssh0) -> handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, Ssh0) -> {G, P} = dh_group1(), {Private, Public} = dh_gen_key(G, P, 1024), - %%?dbg(?DBG_KEX, "public: ~p~n", [Public]), K = ssh_math:ipow(E, Private, P), {Key, K_S} = get_host_key(Ssh0), H = kex_h(Ssh0, K_S, E, Public, K), @@ -329,8 +319,7 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, Ssh0) -> f = Public, h_sig = H_SIG }, Ssh0), - %%?dbg(?DBG_KEX, "shared_secret: ~s ~n", [fmt_binary(K, 16, 4)]), - %%?dbg(?DBG_KEX, "hash: ~s ~n", [fmt_binary(H, 16, 4)]), + {ok, SshPacket, Ssh1#ssh{keyex_key = {{Private, Public}, {G, P}}, shared_secret = K, exchanged_hash = H, @@ -338,7 +327,6 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, Ssh0) -> handle_kex_dh_gex_group(#ssh_msg_kex_dh_gex_group{p = P, g = G}, Ssh0) -> {Private, Public} = dh_gen_key(G,P,1024), - %%?dbg(?DBG_KEX, "public: ~p ~n", [Public]), {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kex_dh_gex_init{e = Public}, Ssh0), {ok, SshPacket, @@ -362,8 +350,7 @@ handle_kexdh_reply(#ssh_msg_kexdh_reply{public_host_key = HostKey, f = F, #ssh{keyex_key = {{Private, Public}, {_G, P}}} = Ssh0) -> K = ssh_math:ipow(F, Private, P), H = kex_h(Ssh0, HostKey, Public, F, K), - %%?dbg(?DBG_KEX, "shared_secret: ~s ~n", [fmt_binary(K, 16, 4)]), - %%?dbg(?DBG_KEX, "hash: ~s ~n", [fmt_binary(H, 16, 4)]), + case verify_host_key(Ssh0, HostKey, H, H_SIG) of ok -> {SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0), @@ -396,8 +383,7 @@ handle_kex_dh_gex_reply(#ssh_msg_kex_dh_gex_reply{public_host_key = HostKey, Ssh0) -> K = ssh_math:ipow(F, Private, P), H = kex_h(Ssh0, HostKey, Min, NBits, Max, P, G, Public, F, K), - %%?dbg(?DBG_KEX, "shared_secret: ~s ~n", [fmt_binary(K, 16, 4)]), - %%?dbg(?DBG_KEX, "hash: ~s ~n", [fmt_binary(H, 16, 4)]), + case verify_host_key(Ssh0, HostKey, H, H_SIG) of ok -> {SshPacket, Ssh} = ssh_packet(#ssh_msg_newkeys{}, Ssh0), @@ -423,83 +409,68 @@ sid(#ssh{session_id = Id}, _) -> %% get_host_key(SSH) -> #ssh{key_cb = Mod, opts = Opts, algorithms = ALG} = SSH, - Scope = proplists:get_value(key_scope, Opts, system), - case ALG#alg.hkey of - 'ssh-rsa' -> - case Mod:private_host_rsa_key(Scope, Opts) of - {ok,Key=#ssh_key { public={N,E}} } -> - %%?dbg(true, "x~n", []), - {Key, - ssh_bits:encode(["ssh-rsa",E,N],[string,mpint,mpint])}; - Error -> - %%?dbg(true, "y~n", []), - exit(Error) - end; - 'ssh-dss' -> - case Mod:private_host_dsa_key(Scope, Opts) of - {ok,Key=#ssh_key { public={P,Q,G,Y}}} -> - {Key, ssh_bits:encode(["ssh-dss",P,Q,G,Y], - [string,mpint,mpint,mpint,mpint])}; - Error -> - exit(Error) - end; - _ -> - exit({error, bad_key_type}) + + case Mod:host_key(ALG#alg.hkey, Opts) of + {ok, #'RSAPrivateKey'{modulus = N, publicExponent = E} = Key} -> + {Key, + ssh_bits:encode(["ssh-rsa",E,N],[string,mpint,mpint])}; + {ok, #'DSAPrivateKey'{y = Y, p = P, q = Q, g = G} = Key} -> + {Key, ssh_bits:encode(["ssh-dss",P,Q,G,Y], + [string,mpint,mpint,mpint,mpint])}; + Result -> + exit({error, {Result, unsupported_key_type}}) end. -sign_host_key(Ssh, Private, H) -> - ALG = Ssh#ssh.algorithms, - Module = case ALG#alg.hkey of - 'ssh-rsa' -> - ssh_rsa; - 'ssh-dss' -> - ssh_dsa - end, - case catch Module:sign(Private, H) of - {'EXIT', Reason} -> - error_logger:format("SIGN FAILED: ~p\n", [Reason]), - {error, Reason}; - SIG -> - ssh_bits:encode([Module:alg_name() ,SIG],[string,binary]) - end. +sign_host_key(_Ssh, #'RSAPrivateKey'{} = Private, H) -> + Hash = sha, %% Option ?! + Signature = sign(H, Hash, Private), + ssh_bits:encode(["ssh-rsa", Signature],[string, binary]); +sign_host_key(_Ssh, #'DSAPrivateKey'{} = Private, H) -> + Hash = sha, %% Option ?! + RawSignature = sign(H, Hash, Private), + ssh_bits:encode(["ssh-dss", RawSignature],[string, binary]). verify_host_key(SSH, K_S, H, H_SIG) -> ALG = SSH#ssh.algorithms, case ALG#alg.hkey of 'ssh-rsa' -> - case ssh_bits:decode(K_S,[string,mpint,mpint]) of - ["ssh-rsa", E, N] -> - ["ssh-rsa",SIG] = ssh_bits:decode(H_SIG,[string,binary]), - Public = #ssh_key { type=rsa, public={N,E} }, - case catch ssh_rsa:verify(Public, H, SIG) of - {'EXIT', Reason} -> - error_logger:format("VERIFY FAILED: ~p\n", [Reason]), - {error, bad_signature}; - ok -> - known_host_key(SSH, Public, "ssh-rsa") - end; - _ -> - {error, bad_format} - end; + verify_host_key_rsa(SSH, K_S, H, H_SIG); 'ssh-dss' -> - case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of - ["ssh-dss",P,Q,G,Y] -> - ["ssh-dss",SIG] = ssh_bits:decode(H_SIG,[string,binary]), - Public = #ssh_key { type=dsa, public={P,Q,G,Y} }, - case catch ssh_dsa:verify(Public, H, SIG) of - {'EXIT', Reason} -> - error_logger:format("VERIFY FAILED: ~p\n", [Reason]), - {error, bad_signature}; - ok -> - known_host_key(SSH, Public, "ssh-dss") - end; - _ -> - {error, bad_host_key_format} - end; + verify_host_key_dss(SSH, K_S, H, H_SIG); _ -> {error, bad_host_key_algorithm} end. +verify_host_key_rsa(SSH, K_S, H, H_SIG) -> + case ssh_bits:decode(K_S,[string,mpint,mpint]) of + ["ssh-rsa", E, N] -> + ["ssh-rsa",SIG] = ssh_bits:decode(H_SIG,[string,binary]), + Public = #'RSAPublicKey'{publicExponent = E, modulus = N}, + case verify(H, sha, SIG, Public) of + false -> + {error, bad_signature}; + true -> + known_host_key(SSH, Public, "ssh-rsa") + end; + _ -> + {error, bad_format} + end. + +verify_host_key_dss(SSH, K_S, H, H_SIG) -> + case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of + ["ssh-dss",P,Q,G,Y] -> + ["ssh-dss",SIG] = ssh_bits:decode(H_SIG,[string,binary]), + Public = {Y, #'Dss-Parms'{p = P, q = Q, g = G}}, + case verify(H, sha, SIG, Public) of + false -> + {error, bad_signature}; + true -> + known_host_key(SSH, Public, "ssh-dss") + end; + _ -> + {error, bad_host_key_format} + end. + accepted_host(Ssh, PeerName, Opts) -> case proplists:get_value(silently_accept_hosts, Opts, false) of true -> @@ -511,14 +482,10 @@ accepted_host(Ssh, PeerName, Opts) -> known_host_key(#ssh{opts = Opts, key_cb = Mod, peer = Peer} = Ssh, Public, Alg) -> PeerName = peer_name(Peer), - case Mod:lookup_host_key(PeerName, Alg, Opts) of - {ok, Public} -> + case Mod:is_host_key(Public, PeerName, Alg, Opts) of + true -> ok; - {ok, BadPublic} -> - error_logger:format("known_host_key: Public ~p BadPublic ~p\n", - [Public, BadPublic]), - {error, bad_public_key}; - {error, not_found} -> + false -> case accepted_host(Ssh, PeerName, Opts) of yes -> Mod:add_host_key(PeerName, Public, Opts); @@ -621,7 +588,6 @@ install_alg(SSH) -> alg_setup(SSH) -> ALG = SSH#ssh.algorithms, - %%?dbg(?DBG_ALG, "ALG: setup ~p ~n", [ALG]), SSH#ssh{kex = ALG#alg.kex, hkey = ALG#alg.hkey, encrypt = ALG#alg.encrypt, @@ -638,7 +604,6 @@ alg_setup(SSH) -> }. alg_init(SSH0) -> - %%?dbg(?DBG_ALG, "ALG: init~n", []), {ok,SSH1} = send_mac_init(SSH0), {ok,SSH2} = recv_mac_init(SSH1), {ok,SSH3} = encrypt_init(SSH2), @@ -648,7 +613,6 @@ alg_init(SSH0) -> SSH6. alg_final(SSH0) -> - %%?dbg(?DBG_ALG, "ALG: final ~n", []), {ok,SSH1} = send_mac_final(SSH0), {ok,SSH2} = recv_mac_final(SSH1), {ok,SSH3} = encrypt_final(SSH2), @@ -669,19 +633,15 @@ select(CL, SL) -> [] -> undefined; [ALG|_] -> ALG end, - %%?dbg(?DBG_ALG, "ALG: select: ~p ~p = ~p~n", [CL, SL, C]), C. ssh_packet(#ssh_msg_kexinit{} = Msg, Ssh0) -> BinMsg = ssh_bits:encode(Msg), Ssh = key_init(Ssh0#ssh.role, Ssh0, BinMsg), - %%?dbg(?DBG_MESSAGE, "SEND_MSG: ~p~n", [Msg]), pack(BinMsg, Ssh); ssh_packet(Msg, Ssh) -> BinMsg = ssh_bits:encode(Msg), - %%?dbg(?DBG_MESSAGE, "SEND_MSG: ~p~n", [Msg]), - %%?dbg(?DBG_BIN_MESSAGE, "Encoded: ~p~n", [BinMsg]), pack(BinMsg, Ssh). pack(Data0, #ssh{encrypt_block_size = BlockSize, @@ -732,17 +692,20 @@ msg_data(PacketData) -> _:PaddingLen/binary>> = PacketData, Data. +sign(SigData, Hash, #'DSAPrivateKey'{} = Key) -> + DerSignature = public_key:sign(SigData, Hash, Key), + #'Dss-Sig-Value'{r = R, s = S} = public_key:der_decode('Dss-Sig-Value', DerSignature), + <<R:160/big-unsigned-integer, S:160/big-unsigned-integer>>; +sign(SigData, Hash, Key) -> + public_key:sign(SigData, Hash, Key). -%% Send a disconnect message -%% terminate(S, SSH, Code, Message) -> -%% M = #ssh_msg_disconnect{code=Code, -%% description = Message, -%% language = "en"}, -%% send_msg(S, SSH, M), -%% gen_tcp:close(S), -%% {error, M}. +verify(PlainText, Hash, Sig, {_, #'Dss-Parms'{}} = Key) -> + <<R:160/big-unsigned-integer, S:160/big-unsigned-integer>> = Sig, + Signature = public_key:der_encode('Dss-Sig-Value', #'Dss-Sig-Value'{r = R, s = S}), + public_key:verify(PlainText, Hash, Signature, Key); +verify(PlainText, Hash, Sig, Key) -> + public_key:verify(PlainText, Hash, Sig, Key). - %% public key algorithms %% %% ssh-dss REQUIRED sign Raw DSS Key @@ -761,9 +724,6 @@ msg_data(PacketData) -> %% %% - - - %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Encryption %% @@ -833,19 +793,13 @@ encrypt(#ssh{encrypt = none} = Ssh, Data) -> encrypt(#ssh{encrypt = '3des-cbc', encrypt_keys = {K1,K2,K3}, encrypt_ctx = IV0} = Ssh, Data) -> - %%?dbg(?DBG_CRYPTO, "encrypt: IV=~p K1=~p, K2=~p, K3=~p ~n", - %% [IV0,K1,K2,K3]), Enc = crypto:des3_cbc_encrypt(K1,K2,K3,IV0,Data), - %%?dbg(?DBG_CRYPTO, "encrypt: ~p -> ~p ~n", [Data, Enc]), IV = crypto:des_cbc_ivec(Enc), {Ssh#ssh{encrypt_ctx = IV}, Enc}; encrypt(#ssh{encrypt = 'aes128-cbc', encrypt_keys = K, encrypt_ctx = IV0} = Ssh, Data) -> - %%?dbg(?DBG_CRYPTO, "encrypt: IV=~p K=~p ~n", - %% [IV0,K]), Enc = crypto:aes_cbc_128_encrypt(K,IV0,Data), - %%?dbg(?DBG_CRYPTO, "encrypt: ~p -> ~p ~n", [Data, Enc]), IV = crypto:aes_cbc_ivec(Enc), {Ssh#ssh{encrypt_ctx = IV}, Enc}. @@ -893,18 +847,12 @@ decrypt(#ssh{decrypt = none} = Ssh, Data) -> decrypt(#ssh{decrypt = '3des-cbc', decrypt_keys = Keys, decrypt_ctx = IV0} = Ssh, Data) -> {K1, K2, K3} = Keys, - %%?dbg(?DBG_CRYPTO, "decrypt: IV=~p K1=~p, K2=~p, K3=~p ~n", - %%[IV0,K1,K2,K3]), Dec = crypto:des3_cbc_decrypt(K1,K2,K3,IV0,Data), - %%?dbg(?DBG_CRYPTO, "decrypt: ~p -> ~p ~n", [Data, Dec]), IV = crypto:des_cbc_ivec(Data), {Ssh#ssh{decrypt_ctx = IV}, Dec}; decrypt(#ssh{decrypt = 'aes128-cbc', decrypt_keys = Key, decrypt_ctx = IV0} = Ssh, Data) -> - %%?dbg(?DBG_CRYPTO, "decrypt: IV=~p Key=~p ~n", - %% [IV0,Key]), Dec = crypto:aes_cbc_128_decrypt(Key,IV0,Data), - %%?dbg(?DBG_CRYPTO, "decrypt: ~p -> ~p ~n", [Data, Dec]), IV = crypto:aes_cbc_ivec(Data), {Ssh#ssh{decrypt_ctx = IV}, Dec}. @@ -936,7 +884,6 @@ compress(#ssh{compress = none} = Ssh, Data) -> {Ssh, Data}; compress(#ssh{compress = zlib, compress_ctx = Context} = Ssh, Data) -> Compressed = zlib:deflate(Context, Data, sync), - %%?dbg(?DBG_ZLIB, "deflate: ~p -> ~p ~n", [Data, Compressed]), {Ssh, list_to_binary(Compressed)}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -960,7 +907,6 @@ decompress(#ssh{decompress = none} = Ssh, Data) -> {Ssh, Data}; decompress(#ssh{decompress = zlib, decompress_ctx = Context} = Ssh, Data) -> Decompressed = zlib:inflate(Context, Data), - %%?dbg(?DBG_ZLIB, "inflate: ~p -> ~p ~n", [Data, Decompressed]), {Ssh, list_to_binary(Decompressed)}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1039,7 +985,6 @@ hash(SSH, Char, N, HASH) -> K1 = HASH([K, H, Char, SessionID]), Sz = N div 8, <<Key:Sz/binary, _/binary>> = hash(K, H, K1, N-128, HASH), - %%?dbg(?DBG_KEX, "Key ~s: ~s ~n", [Char, fmt_binary(Key, 16, 4)]), Key. hash(_K, _H, Ki, N, _HASH) when N =< 0 -> @@ -1055,6 +1000,7 @@ kex_h(SSH, K_S, E, F, K) -> [string,string,binary,binary,binary, mpint,mpint,mpint]), crypto:sha(L). + kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) -> L = if Min==-1; Max==-1 -> @@ -1075,7 +1021,7 @@ kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) -> Prime, Gen, E,F,K], Ts) end, crypto:sha(L). - + mac_key_size('hmac-sha1') -> 20*8; mac_key_size('hmac-sha1-96') -> 20*8; mac_key_size('hmac-md5') -> 16*8; @@ -1105,9 +1051,6 @@ dh_gen_key(G, P, _Bits) -> Public = ssh_math:ipow(G, Private, P), {Private,Public}. -%% trim(Str) -> -%% lists:reverse(trim_head(lists:reverse(trim_head(Str)))). - trim_tail(Str) -> lists:reverse(trim_head(lists:reverse(Str))). @@ -1116,48 +1059,3 @@ trim_head([$\t|Cs]) -> trim_head(Cs); trim_head([$\n|Cs]) -> trim_head(Cs); trim_head([$\r|Cs]) -> trim_head(Cs); trim_head(Cs) -> Cs. - -%% Retrieve session_id from ssh, needed by public-key auth -%get_session_id(SSH) -> -% {ok, SessionID} = call(SSH, get_session_id), - -%% DEBUG utils -%% Format integers and binaries as hex blocks -%% -%% -ifdef(debug). -%% fmt_binary(B, BlockSize, GroupSize) -> -%% fmt_block(fmt_bin(B), BlockSize, GroupSize). - -%% fmt_block(Bin, BlockSize, GroupSize) -> -%% fmt_block(Bin, BlockSize, 0, GroupSize). - - -%% fmt_block(Bin, 0, _I, _G) -> -%% binary_to_list(Bin); -%% fmt_block(Bin, Sz, G, G) when G =/= 0 -> -%% ["~n#" | fmt_block(Bin, Sz, 0, G)]; -%% fmt_block(Bin, Sz, I, G) -> -%% case Bin of -%% <<Block:Sz/binary, Tail/binary>> -> -%% if Tail == <<>> -> -%% [binary_to_list(Block)]; -%% true -> -%% [binary_to_list(Block), " " | fmt_block(Tail, Sz, I+1, G)] -%% end; -%% <<>> -> -%% []; -%% _ -> -%% [binary_to_list(Bin)] -%% end. - -%% %% Format integer or binary as hex -%% fmt_bin(X) when integer(X) -> -%% list_to_binary(io_lib:format("~p", [X])); -%% fmt_bin(X) when binary(X) -> -%% Sz = size(X)*8, -%% <<Y:Sz/unsigned-big>> = X, -%% %%Fmt = "~"++integer_to_list(size(X)*2)++"~p", -%% list_to_binary(io_lib:format("~p", [Y])). - -%% -endif. - diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl index c9631a73b1..d5b6dd03d1 100644 --- a/lib/ssh/src/ssh_xfer.erl +++ b/lib/ssh/src/ssh_xfer.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -298,8 +298,6 @@ xf_send_names(#ssh_xfer{cm = CM, channel = Channel, vsn = Vsn}, Size = 1 + 4 + 4 + Len, ToSend = [<<?UINT32(Size), ?SSH_FXP_NAME, ?UINT32(ReqId), ?UINT32(Count)>>, Data], - %%?dbg(true, "xf_send_names: Size=~p size(ToSend)=~p\n", - %% [Size, size(list_to_binary(ToSend))]), ssh_connection:send(CM, Channel, ToSend). xf_send_status(XF, ReqId, ErrorCode) -> @@ -353,7 +351,6 @@ xf_reply(_XF, <<?SSH_FXP_DATA, ?UINT32(ReqID), {data, ReqID, Data}; xf_reply(XF, <<?SSH_FXP_NAME, ?UINT32(ReqID), ?UINT32(Count), AData/binary>>) -> - %%?dbg(true, "xf_reply ?SSH_FXP_NAME: AData=~p\n", [AData]), {name, ReqID, decode_names(XF#ssh_xfer.vsn, Count, AData)}; xf_reply(XF, <<?SSH_FXP_ATTRS, ?UINT32(ReqID), AData/binary>>) -> @@ -579,7 +576,6 @@ encode_attr_flags(Vsn, Flags) -> end, Flags). encode_file_type(Type) -> - %%?dbg(true, "encode_file_type(~p)\n", [Type]), case Type of regular -> ?SSH_FILEXFER_TYPE_REGULAR; directory -> ?SSH_FILEXFER_TYPE_DIRECTORY; @@ -660,15 +656,12 @@ encode_ATTR(Vsn, A) -> {extended, A#ssh_xfer_attr.extensions}], 0, []), Type = encode_file_type(A#ssh_xfer_attr.type), - %%?dbg(true, "encode_ATTR: Vsn=~p A=~p As=~p Flags=~p Type=~p", - %% [Vsn, A, As, Flags, Type]), Result = list_to_binary([?uint32(Flags), if Vsn >= 5 -> ?byte(Type); true -> (<<>>) end, As]), - %% ?dbg(true, " Result=~p\n", [Result]), Result. @@ -722,7 +715,6 @@ encode_As(_Vsn, [], Flags, Acc) -> decode_ATTR(Vsn, <<?UINT32(Flags), Tail/binary>>) -> - %%?dbg(true, "decode_ATTR: Vsn=~p Flags=~p Tail=~p\n", [Vsn, Flags, Tail]), {Type,Tail2} = if Vsn =< 3 -> {?SSH_FILEXFER_TYPE_UNKNOWN, Tail}; @@ -751,7 +743,6 @@ decode_ATTR(Vsn, <<?UINT32(Flags), Tail/binary>>) -> Tail2). decode_As(Vsn, [{AName, AField}|As], R, Flags, Tail) -> - %%?dbg(false, "decode_As: Vsn=~p AName=~p AField=~p Flags=~p Tail=~p\n", [Vsn, AName, AField, Flags, Tail]), case AName of size when ?is_set(?SSH_FILEXFER_ATTR_SIZE, Flags) -> <<?UINT64(X), Tail2/binary>> = Tail, @@ -762,7 +753,6 @@ decode_As(Vsn, [{AName, AField}|As], R, Flags, Tail) -> ownergroup when ?is_set(?SSH_FILEXFER_ATTR_OWNERGROUP, Flags),Vsn>=5 -> <<?UINT32(Len), Bin:Len/binary, Tail2/binary>> = Tail, X = binary_to_list(Bin), - %%?dbg(true, "ownergroup X=~p\n", [X]), decode_As(Vsn, As, setelement(AField, R, X), Flags, Tail2); permissions when ?is_set(?SSH_FILEXFER_ATTR_PERMISSIONS,Flags),Vsn>=5-> @@ -824,13 +814,11 @@ decode_names(Vsn, I, <<?UINT32(Len), FileName:Len/binary, ?UINT32(LLen), _LongName:LLen/binary, Tail/binary>>) when Vsn =< 3 -> Name = binary_to_list(FileName), - %%?dbg(true, "decode_names: ~p\n", [Name]), {A, Tail2} = decode_ATTR(Vsn, Tail), [{Name, A} | decode_names(Vsn, I-1, Tail2)]; decode_names(Vsn, I, <<?UINT32(Len), FileName:Len/binary, Tail/binary>>) when Vsn >= 4 -> Name = binary_to_list(FileName), - %%?dbg(true, "decode_names: ~p\n", [Name]), {A, Tail2} = decode_ATTR(Vsn, Tail), [{Name, A} | decode_names(Vsn, I-1, Tail2)]. @@ -839,8 +827,6 @@ encode_names(Vsn, NamesAndAttrs) -> encode_name(Vsn, {Name,Attr}, Len) when Vsn =< 3 -> NLen = length(Name), - %%?dbg(true, "encode_name: Vsn=~p Name=~p Attr=~p\n", - %% [Vsn, Name, Attr]), EncAttr = encode_ATTR(Vsn, Attr), ALen = size(EncAttr), NewLen = Len + NLen*2 + 4 + 4 + ALen, diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile index 1820924ed6..145d5d2ad6 100644 --- a/lib/ssh/test/Makefile +++ b/lib/ssh/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2004-2011. All Rights Reserved. +# Copyright Ericsson AB 2004-2012. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -32,7 +32,6 @@ VSN=$(GS_VSN) MODULES= \ ssh_test_lib \ - ssh_SUITE \ ssh_basic_SUITE \ ssh_to_openssh_SUITE \ ssh_sftp_SUITE \ diff --git a/lib/ssh/test/ssh_SUITE.erl b/lib/ssh/test/ssh_SUITE.erl deleted file mode 100644 index 953c9080f9..0000000000 --- a/lib/ssh/test/ssh_SUITE.erl +++ /dev/null @@ -1,72 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% - -%% -%%%---------------------------------------------------------------- -%%% Purpose:ssh application test suite. -%%%----------------------------------------------------------------- --module(ssh_SUITE). --include_lib("common_test/include/ct.hrl"). --include("test_server_line.hrl"). - -% Default timetrap timeout (set in init_per_testcase). --define(default_timeout, ?t:minutes(1)). --define(application, ssh). - -% Test server specific exports --export([all/0,groups/0,init_per_group/2,end_per_group/2]). --export([init_per_testcase/2, end_per_testcase/2]). - -% Test cases must be exported. --export([app_test/1]). --define(cases, [app_test]). - -%% -%% all/1 -%% -all() -> - [app_test]. - -groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -init_per_testcase(_Case, Config) -> - Dog=test_server:timetrap(?default_timeout), - [{watchdog, Dog}|Config]. -end_per_testcase(_Case, Config) -> - Dog=?config(watchdog, Config), - test_server:timetrap_cancel(Dog), - ok. -% -% Test cases starts here. -% -app_test(suite) -> - []; -app_test(doc) -> - ["Application consistency test."]; -app_test(Config) when is_list(Config) -> - ?t:app_test(?application), - ok. diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index 5ea0d98980..9c13180159 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -41,9 +41,6 @@ init_per_suite(Config) -> case catch crypto:start() of ok -> - Dir = ?config(priv_dir, Config), - {ok, _} = ssh_test_lib:get_id_keys(Dir), - ssh_test_lib:make_dsa_files(Config), Config; _Else -> {skip, "Crypto could not be started!"} @@ -55,10 +52,9 @@ init_per_suite(Config) -> %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after the whole suite %%-------------------------------------------------------------------- -end_per_suite(Config) -> - Dir = ?config(priv_dir, Config), +end_per_suite(_Config) -> + ssh:stop(), crypto:stop(), - ssh_test_lib:remove_id_keys(Dir), ok. %%-------------------------------------------------------------------- @@ -75,7 +71,6 @@ end_per_suite(Config) -> %% Description: Initialization before each test case %%-------------------------------------------------------------------- init_per_testcase(_TestCase, Config) -> - ssh_test_lib:known_hosts(backup), ssh:start(), Config. @@ -87,9 +82,16 @@ init_per_testcase(_TestCase, Config) -> %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after each test case %%-------------------------------------------------------------------- -end_per_testcase(_TestCase, _Config) -> + +end_per_testcase(TestCase, Config) when TestCase == server_password_option; + TestCase == server_userpassword_option -> + UserDir = filename:join(?config(priv_dir, Config), nopubkey), + ssh_test_lib:del_dirs(UserDir), + end_per_testcase(Config); +end_per_testcase(TestCase, Config) -> + end_per_testcase(Config). +end_per_testcase(_Config) -> ssh:stop(), - ssh_test_lib:known_hosts(restore), ok. %%-------------------------------------------------------------------- @@ -101,31 +103,72 @@ end_per_testcase(_TestCase, _Config) -> %% Description: Returns a list of all test cases in this test suite %%-------------------------------------------------------------------- all() -> - [exec, exec_compressed, shell, daemon_already_started, - server_password_option, server_userpassword_option, - known_hosts]. + [app_test, + {group, dsa_key}, + {group, rsa_key}, + {group, dsa_pass_key}, + {group, rsa_pass_key}, + daemon_already_started, + server_password_option, server_userpassword_option]. groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. + [{dsa_key, [], [exec, exec_compressed, shell, known_hosts]}, + {rsa_key, [], [exec, exec_compressed, shell, known_hosts]}, + {dsa_pass_key, [], [pass_phrase]}, + {rsa_pass_key, [], [pass_phrase]} + ]. + +init_per_group(dsa_key, Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:setup_dsa(DataDir, PrivDir), + Config; +init_per_group(rsa_key, Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:setup_rsa(DataDir, PrivDir), + Config; +init_per_group(rsa_pass_key, Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:setup_rsa_pass_pharse(DataDir, PrivDir, "Password"), + [{pass_phrase, {rsa_pass_phrase, "Password"}}| Config]; +init_per_group(dsa_pass_key, Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:setup_dsa_pass_pharse(DataDir, PrivDir, "Password"), + [{pass_phrase, {dsa_pass_phrase, "Password"}}| Config]; +init_per_group(_, Config) -> + Config. -end_per_group(_GroupName, Config) -> - Config. +end_per_group(dsa_key, Config) -> + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:clean_dsa(PrivDir), + Config; +end_per_group(rsa_key, Config) -> + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:clean_rsa(PrivDir), + Config; +end_per_group(dsa_pass_key, Config) -> + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:clean_dsa(PrivDir), + Config; +end_per_group(rsa_pass_key, Config) -> + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:clean_rsa(PrivDir), + Config; +end_per_group(_, Config) -> + Config. %% Test cases starts here. %%-------------------------------------------------------------------- -sign_and_verify_rsa(doc) -> - ["Test api function ssh:sign_data and ssh:verify_data"]; - -sign_and_verify_rsa(suite) -> +app_test(suite) -> []; -sign_and_verify_rsa(Config) when is_list(Config) -> - Data = ssh:sign_data(<<"correct data">>, "ssh-rsa"), - ok = ssh:verify_data(<<"correct data">>, Data, "ssh-rsa"), - {error,invalid_signature} = ssh:verify_data(<<"incorrect data">>, Data,"ssh-rsa"). - +app_test(doc) -> + ["Application consistency test."]; +app_test(Config) when is_list(Config) -> + ?t:app_test(ssh), + ok. exec(doc) -> ["Test api function ssh_connection:exec"]; @@ -135,11 +178,15 @@ exec(suite) -> exec(Config) when is_list(Config) -> process_flag(trap_exit, true), - SystemDir = ?config(data_dir, Config), + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, UserDir}, {failfun, fun ssh_test_lib:failfun/2}]), ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, {user_interaction, false}]), {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity), success = ssh_connection:exec(ConnectionRef, ChannelId0, @@ -177,13 +224,16 @@ exec_compressed(suite) -> exec_compressed(Config) when is_list(Config) -> process_flag(trap_exit, true), - SystemDir = ?config(data_dir, Config), - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, {compression, zlib}, {failfun, fun ssh_test_lib:failfun/2}]), ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_dir, UserDir}, {user_interaction, false}]), {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), success = ssh_connection:exec(ConnectionRef, ChannelId, @@ -208,13 +258,15 @@ shell(suite) -> shell(Config) when is_list(Config) -> process_flag(trap_exit, true), - SystemDir = ?config(data_dir, Config), - {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + + {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir}, {failfun, fun ssh_test_lib:failfun/2}]), test_server:sleep(500), IO = ssh_test_lib:start_io_server(), - Shell = ssh_test_lib:start_shell(Port, IO), + Shell = ssh_test_lib:start_shell(Port, IO, UserDir), receive ErlShellStart -> test_server:format("Erlang shell start: ~p~n", [ErlShellStart]) @@ -278,9 +330,13 @@ daemon_already_started(suite) -> daemon_already_started(Config) when is_list(Config) -> SystemDir = ?config(data_dir, Config), + UserDir = ?config(priv_dir, Config), + {Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, UserDir}, {failfun, fun ssh_test_lib:failfun/2}]), {error, eaddrinuse} = ssh_test_lib:daemon(Port, [{system_dir, SystemDir}, + {user_dir, UserDir}, {failfun, fun ssh_test_lib:failfun/2}]), ssh:stop_daemon(Pid). @@ -291,9 +347,12 @@ server_password_option(doc) -> server_password_option(suite) -> []; server_password_option(Config) when is_list(Config) -> - UserDir = ?config(data_dir, Config), % to make sure we don't use - SysDir = ?config(data_dir, Config), % public-key-auth + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, UserDir}, {password, "morot"}]), ConnectionRef = @@ -321,9 +380,12 @@ server_userpassword_option(doc) -> server_userpassword_option(suite) -> []; server_userpassword_option(Config) when is_list(Config) -> - UserDir = ?config(data_dir, Config), % to make sure we don't use - SysDir = ?config(data_dir, Config), % public-key-auth + PrivDir = ?config(priv_dir, Config), + UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth + file:make_dir(UserDir), + SysDir = ?config(data_dir, Config), {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, PrivDir}, {user_passwords, [{"vego", "morot"}]}]), ConnectionRef = @@ -362,16 +424,16 @@ known_hosts(suite) -> []; known_hosts(Config) when is_list(Config) -> SystemDir = ?config(data_dir, Config), - UserDir = ?config(priv_dir, Config), - - {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + PrivDir = ?config(priv_dir, Config), + + {Pid, Host, Port} = ssh_test_lib:daemon([{user_dir, PrivDir},{system_dir, SystemDir}, {failfun, fun ssh_test_lib:failfun/2}]), - KnownHosts = filename:join(UserDir, "known_hosts"), + KnownHosts = filename:join(PrivDir, "known_hosts"), file:delete(KnownHosts), {error, enoent} = file:read_file(KnownHosts), ConnectionRef = - ssh_test_lib:connect(Host, Port, [{user_dir, UserDir}, + ssh_test_lib:connect(Host, Port, [{user_dir, PrivDir}, {user_interaction, false}, silently_accept_hosts]), {ok, _Channel} = ssh_connection:session_channel(ConnectionRef, infinity), @@ -382,7 +444,30 @@ known_hosts(Config) when is_list(Config) -> [HostAndIp, Alg, _KeyData] = string:tokens(Line, " "), [Host, _Ip] = string:tokens(HostAndIp, ","), "ssh-" ++ _ = Alg, - ssh:stop_daemon(Pid). + ssh:stop_daemon(Pid). + +pass_phrase(doc) -> + ["Test that we can use keyes protected by pass phrases"]; + +pass_phrase(suite) -> + []; + +pass_phrase(Config) when is_list(Config) -> + process_flag(trap_exit, true), + SystemDir = filename:join(?config(priv_dir, Config), system), + UserDir = ?config(priv_dir, Config), + PhraseArg = ?config(pass_phrase, Config), + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {user_dir, UserDir}, + {failfun, fun ssh_test_lib:failfun/2}]), + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + PhraseArg, + {user_dir, UserDir}, + {user_interaction, false}]), + {ok, _ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), + ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- %% Internal functions diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_dsa b/lib/ssh/test/ssh_basic_SUITE_data/id_dsa new file mode 100644 index 0000000000..d306f8b26e --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/id_dsa @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ +APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod +/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP +kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW +JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD +OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt ++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e +uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX +Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE +ZU8w8Q+H7z0j+a+70x2iAw== +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_basic_SUITE_data/id_rsa b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa new file mode 100644 index 0000000000..9d7e0dd5fb --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/id_rsa @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQD1OET+3O/Bvj/dtjxDTXmj1oiJt4sIph5kGy0RfjoPrZfaS+CU +DhakCmS6t2ivxWFgtpKWaoGMZMJqWj6F6ZsumyFl3FPBtujwY/35cgifrI9Ns4Tl +zR1uuengNBmV+WRQ5cd9F2qS6Z8aDQihzt0r8JUqLcK+VQbrmNzboCCQQwIDAQAB +AoGAPQEyqPTt8JUT7mRXuaacjFXiweAXhp9NEDpyi9eLOjtFe9lElZCrsUOkq47V +TGUeRKEm9qSodfTbKPoqc8YaBJGJPhUaTAcha+7QcDdfHBvIsgxvU7ePVnlpXRp3 +CCUEMPhlnx6xBoTYP+fRU0e3+xJIPVyVCqX1jAdUMkzfRoECQQD6ux7B1QJAIWyK +SGkbDUbBilNmzCFNgIpOP6PA+bwfi5d16diTpra5AX09keQABAo/KaP1PdV8Vg0p +z4P3A7G3AkEA+l+AKG6m0kQTTBMJDqOdVPYwe+5GxunMaqmhokpEbuGsrZBl5Dvd +WpcBjR7jmenrhKZRIuA+Fz5HPo/UQJPl1QJBAKxstDkeED8j/S2XoFhPKAJ+6t39 +sUVICVTIZQeXdmzHJXCcUSkw8+WEhakqw/3SyW0oaK2FSWQJFWJUZ+8eJj8CQEh3 +xeduB5kKnS9CvzdeghZqX6QvVosSdtlUmfUYW/BgH5PpHKTP8wTaeld3XldZTpMJ +dKiMkUw2+XYROVUrubUCQD+Na1LhULlpn4ISEtIEfqpdlUhxDgO15Wg8USmsng+x +ICliVOSQtwaZjm8kwaFt0W7XnpnDxbRs37vIEbIMWak= +-----END RSA PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..51ab6fbd88 --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK +wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q +diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA +l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X +skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF +Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP +ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah +/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U +ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W +Lv62jKcdskxNyz2NQoBx +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key.pub new file mode 100644 index 0000000000..4dbb1305b0 --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_dsa_key.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j +YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2 +KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU +aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI +fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT +MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh +DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48 +wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2 +/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key new file mode 100644 index 0000000000..79968bdd7d --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key @@ -0,0 +1,16 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8semM4q843337 +zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RWRWzjaxSB +6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4QIDAQAB +AoGANmvJzJO5hkLuvyDZHKfAnGTtpifcR1wtSa9DjdKUyn8vhKF0mIimnbnYQEmW +NUUb3gXCZLi9PvkpRSVRrASDOZwcjoU/Kvww163vBUVb2cOZfFhyn6o2Sk88Tt++ +udH3hdjpf9i7jTtUkUe+QYPsia+wgvvrmn4QrahLAH86+kECQQDx5gFeXTME3cnW +WMpFz3PPumduzjqgqMMWEccX4FtQkMX/gyGa5UC7OHFyh0N/gSWvPbRHa8A6YgIt +n8DO+fh5AkEAzbqX4DOn8NY6xJIi42q7l/2jIA0RkB6P7YugW5NblhqBZ0XDnpA5 +sMt+rz+K07u9XZtxgh1xi7mNfwY6lEAMqQJBAJBEauCKmRj35Z6OyeQku59SPsnY ++SJEREVvSNw2lH9SOKQQ4wPsYlTGbvKtNVZgAcen91L5MmYfeckYE/fdIZECQQCt +64zxsTnM1I8iFxj/gP/OYlJBikrKt8udWmjaghzvLMEw+T2DExJyb9ZNeT53+UMB +m6O+B/4xzU/djvp+0hbhAkAemIt+rA5kTmYlFndhpvzkSSM8a2EXsO4XIPgGWCTT +tQKS/tTly0ADMjN/TVy11+9d6zcqadNVuHXHGtR4W0GR +-----END RSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key.pub b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key.pub new file mode 100644 index 0000000000..75d2025c71 --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE_data/ssh_host_rsa_key.pub @@ -0,0 +1,5 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1yc2EAAAADAQABAAAAgQDCZX+4FBDwZIh9y/Uxee1VJnEXlowpz2yDKwj8 +semM4q843337zbNfxHmladB1lpz2NqyxI175xMIJuDxogyZdsOxGnFAzAnthR4dqL/RW +RWzjaxSB6IAO9SPYVVlrpZ+1hsjLW79fwXK/yc8VdhRuWTeQiRgYY2ek8+OKbOqz4Q== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl index c96b6de3ea..7644db155d 100644 --- a/lib/ssh/test/ssh_sftp_SUITE.erl +++ b/lib/ssh/test/ssh_sftp_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2011. All Rights Reserved. +%% Copyright Ericsson AB 2005-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -24,14 +24,12 @@ -compile(export_all). -include_lib("common_test/include/ct.hrl"). --include("test_server_line.hrl"). -include_lib("kernel/include/file.hrl"). % Default timetrap timeout -define(default_timeout, ?t:minutes(1)). --define(SFPD_PORT, 9999). -define(USER, "Alladin"). -define(PASSWD, "Sesame"). @@ -46,18 +44,12 @@ %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) -> - case {catch crypto:start(),catch ssh:start()} of - {ok,ok} -> - Dir = ?config(priv_dir, Config), - {ok, _} = ssh_test_lib:get_id_keys(Dir), - ssh_test_lib:make_dsa_files(Config), + case (catch crypto:start()) of + ok -> + ssh:start(), Config; - {ok,_} -> - {skip,"Could not start ssh!"}; - {_,ok} -> - {skip,"Could not start crypto!"}; - {_,_} -> - {skip,"Could not start crypto and ssh!"} + _ -> + {skip,"Could not start crypto!"} end. %%-------------------------------------------------------------------- @@ -67,9 +59,8 @@ init_per_suite(Config) -> %% Description: Cleanup after the whole suite %%-------------------------------------------------------------------- end_per_suite(Config) -> + ssh:stop(), crypto:stop(), - Dir = ?config(priv_dir, Config), - ssh_test_lib:remove_id_keys(Dir), Config. %%-------------------------------------------------------------------- @@ -90,27 +81,30 @@ init_per_testcase(_Case, Config) -> TmpConfig0 = lists:keydelete(watchdog, 1, Config), TmpConfig = lists:keydelete(sftp, 1, TmpConfig0), Dog = test_server:timetrap(?default_timeout), - Dir = ?config(priv_dir, Config), + PrivDir = ?config(priv_dir, Config), SysDir = ?config(data_dir, Config), Host = ssh_test_lib:hostname(), - Sftp = case (catch ssh_sftp:start_channel(Host, - [{user_dir, Dir}, - {user_interaction, false}, + %% Run test against openssh server if available + Sftp = case (catch ssh_sftp:start_channel(Host, + [{user_interaction, false}, {silently_accept_hosts, true}])) of {ok, ChannelPid, Connection} -> + test_server:format("Running against openssh"), {ChannelPid, Connection}; - _Error -> - {_Sftpd, _Host, _Port} = - ssh_test_lib:daemon(Host, ?SFPD_PORT, - [{system_dir, SysDir}, + _Error -> %% Start own sftp + test_server:format("Running against erlang ssh"), + {_Sftpd, Host1, Port} = + ssh_test_lib:daemon([{system_dir, SysDir}, + {user_dir, PrivDir}, {user_passwords, [{?USER, ?PASSWD}]}, {failfun, fun ssh_test_lib:failfun/2}]), - Result = (catch ssh_sftp:start_channel(Host, ?SFPD_PORT, + Result = (catch ssh_sftp:start_channel(Host1, Port, [{user, ?USER}, {password, ?PASSWD}, + {user_dir, PrivDir}, {user_interaction, false}, {silently_accept_hosts, true}])), {ok, ChannelPid, Connection} = Result, diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa b/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa deleted file mode 100644 index 7e3f885f5d..0000000000 --- a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQDLKYTdRnGzphcN+pF8UuI3sYB7rxZUHbOT87K3vh8XOLkDOsS3 -8VREtNS8Wb3uYXsRtyDoUvrLIDnyllOfJSDupWLr4ibckUZd/nhFAaC6WryVmH6k -GlQLLp9KU+vcn2DwYeo14gbwHYDB3pmv4CWAlnO1m/BkX4aLz1zC314OkQIBIwKB -gD/Z2UzboBPjvhpWEHeHw3CW3zzQoJ4X9pw2peH57IOkHOPCA0/A3/hWFvleCH4e -owWRU3w3ViKVGYbBh/7RJ5rllN+ENUmVn536srJTxLKUtvb5jRGj3W6EWgAGHSUB -hm83Kt9Lb5hprL7dPrNGvSseBm/LQSfBQ4vUUyiVRKGPAkEA/rPxWoLdBBP+FZtE -fGzz9izPM6Fe6o8ZGNZIlRBProOhgEvvIqdgzQWObgLVVrw+M/YApPpiYS3PEmWj -b2b+jwJBAMwyYeL6coKTl8swDu8HvLnshgUFJFTtHhOTXsKtXQNI1b24xhUrB3Sb -X8fmoByyRNRpOfvg4Jdqi3Z6KfIcsN8CQQDEfC83McBw3DkJWoVKCugVrYnmACSm -USH9N5cT6AL0VupNB2C0VTwL37cEaJXyc/V4ipLIaWHV8CNl9qKmZWVJAkEAurG4 -lQI8zyfbPW3EgsU+1d+QeZ5NGnJkpC73jWtNudwxIn0M4CdXRgpmMxwAGjyWs5No -Nr75OfsDKn5SPHIAywJAKrtONlOizgDiG3EvAXZlwFtOb+HkQ7lrFwczrQu9m7yi -brSAcnTrLKI6CrR33b/QJLvb9C/HTEZojFABGq8M7A== ------END RSA PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub b/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub deleted file mode 100644 index 77f57de4af..0000000000 --- a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAyymE3UZxs6YXDfqRfFLiN7GAe68WVB2zk/Oyt74fFzi5AzrEt/FURLTUvFm97mF7Ebcg6FL6yyA58pZTnyUg7qVi6+Im3JFGXf54RQGgulq8lZh+pBpUCy6fSlPr3J9g8GHqNeIG8B2Awd6Zr+AlgJZztZvwZF+Gi89cwt9eDpE= jakob@balin diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..51ab6fbd88 --- /dev/null +++ b/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK +wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q +diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA +l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X +skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF +Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP +ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah +/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U +ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W +Lv62jKcdskxNyz2NQoBx +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key.pub new file mode 100644 index 0000000000..4dbb1305b0 --- /dev/null +++ b/lib/ssh/test/ssh_sftp_SUITE_data/ssh_host_dsa_key.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j +YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2 +KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU +aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI +fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT +MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh +DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48 +wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2 +/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl index bfe54a3e75..6e4480ee9d 100644 --- a/lib/ssh/test/ssh_sftpd_SUITE.erl +++ b/lib/ssh/test/ssh_sftpd_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2011. All Rights Reserved. +%% Copyright Ericsson AB 2006-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -53,16 +53,18 @@ %% variable, but should NOT alter/remove any existing entries. %%-------------------------------------------------------------------- init_per_suite(Config) -> - case {catch ssh:stop(),catch crypto:start()} of - {ok,ok} -> - ssh_test_lib:make_dsa_files(Config), + case (catch crypto:start()) of + ok -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:setup_dsa(DataDir, PrivDir), + %% to make sure we don't use public-key-auth + %% this should be tested by other test suites + UserDir = filename:join(?config(priv_dir, Config), nopubkey), + file:make_dir(UserDir), Config; - {ok,_} -> - {skip,"Could not start ssh!"}; - {_,ok} -> - {skip,"Could not start crypto!"}; - {_,_} -> - {skip,"Could not start crypto and ssh!"} + _ -> + {skip,"Could not start crypto!"} end. %%-------------------------------------------------------------------- @@ -71,7 +73,12 @@ init_per_suite(Config) -> %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after the whole suite %%-------------------------------------------------------------------- -end_per_suite(_Config) -> +end_per_suite(Config) -> + SysDir = ?config(priv_dir, Config), + ssh_test_lib:clean_dsa(SysDir), + UserDir = filename:join(?config(priv_dir, Config), nopubkey), + file:del_dir(UserDir), + ssh:stop(), crypto:stop(), ok. @@ -91,15 +98,18 @@ end_per_suite(_Config) -> init_per_testcase(TestCase, Config) -> ssh:start(), prep(Config), - SysDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ClientUserDir = filename:join(PrivDir, nopubkey), + SystemDir = filename:join(?config(priv_dir, Config), system), + {ok, Sftpd} = - ssh_sftpd:listen(?SFPD_PORT, [{system_dir, SysDir}, + ssh_sftpd:listen(?SFPD_PORT, [{system_dir, SystemDir}, + {user_dir, PrivDir}, {user_passwords,[{?USER, ?PASSWD}]}, {pwdfun, fun(_,_) -> true end}]), Cm = ssh_test_lib:connect(?SFPD_PORT, - [{system_dir, SysDir}, - {user_dir, SysDir}, + [{user_dir, ClientUserDir}, {user, ?USER}, {password, ?PASSWD}, {user_interaction, false}, {silently_accept_hosts, true}, @@ -542,7 +552,7 @@ set_attributes(Config) when is_list(Config) -> {ok, FileInfo} = file:read_file_info(FileName), OrigPermissions = FileInfo#file_info.mode, - Permissions = 8#400, %% User read-only + Permissions = 8#600, %% User read-write-only Flags = ?SSH_FILEXFER_ATTR_PERMISSIONS, diff --git a/lib/ssh/test/ssh_sftpd_SUITE_data/id_dsa b/lib/ssh/test/ssh_sftpd_SUITE_data/id_dsa new file mode 100644 index 0000000000..d306f8b26e --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_SUITE_data/id_dsa @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ +APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod +/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP +kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW +JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD +OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt ++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e +uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX +Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE +ZU8w8Q+H7z0j+a+70x2iAw== +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..51ab6fbd88 --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK +wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q +diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA +l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X +skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF +Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP +ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah +/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U +ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W +Lv62jKcdskxNyz2NQoBx +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub new file mode 100644 index 0000000000..4dbb1305b0 --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_SUITE_data/ssh_host_dsa_key.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j +YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2 +KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU +aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI +fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT +MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh +DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48 +wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2 +/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl index 2209af05d5..4c469ed5f7 100644 --- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -28,7 +28,6 @@ -include_lib("kernel/include/file.hrl"). --define(SSHD_PORT, 9999). -define(USER, "Alladin"). -define(PASSWD, "Sesame"). -define(SSH_MAX_PACKET_SIZE, 32768). @@ -48,13 +47,14 @@ init_per_suite(Config) -> case catch crypto:start() of ok -> DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), FileAlt = filename:join(DataDir, "ssh_sftpd_file_alt.erl"), c:c(FileAlt), FileName = filename:join(DataDir, "test.txt"), {ok, FileInfo} = file:read_file_info(FileName), ok = file:write_file_info(FileName, FileInfo#file_info{mode = 8#400}), - ssh_test_lib:make_dsa_files(Config), + ssh_test_lib:setup_dsa(DataDir, PrivDir), Config; _Else -> {skip,"Could not start ssh!"} @@ -66,7 +66,11 @@ init_per_suite(Config) -> %% A list of key/value pairs, holding the test case configuration. %% Description: Cleanup after the whole suite %%-------------------------------------------------------------------- -end_per_suite(_Config) -> +end_per_suite(Config) -> + UserDir = filename:join(?config(priv_dir, Config), nopubkey), + file:del_dir(UserDir), + SysDir = ?config(priv_dir, Config), + ssh_test_lib:clean_dsa(SysDir), crypto:stop(), ok. @@ -85,7 +89,8 @@ end_per_suite(_Config) -> %%-------------------------------------------------------------------- init_per_testcase(TestCase, Config) -> ssh:start(), - DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + SystemDir = filename:join(PrivDir, system), Options = case atom_to_list(TestCase) of @@ -93,50 +98,39 @@ init_per_testcase(TestCase, Config) -> Spec = ssh_sftpd:subsystem_spec([{file_handler, ssh_sftpd_file_alt}]), - [{user_passwords,[{?USER, ?PASSWD}]}, - {pwdfun, fun(_,_) -> true end}, - {system_dir, DataDir}, - {user_dir, DataDir}, + [{system_dir, SystemDir}, + {user_dir, PrivDir}, {subsystems, [Spec]}]; "root_dir" -> Privdir = ?config(priv_dir, Config), Root = filename:join(Privdir, root), file:make_dir(Root), Spec = ssh_sftpd:subsystem_spec([{root,Root}]), - [{user_passwords,[{?USER, ?PASSWD}]}, - {pwdfun, fun(_,_) -> true end}, - {system_dir, DataDir}, - {user_dir, DataDir}, + [{system_dir, SystemDir}, + {user_dir, PrivDir}, {subsystems, [Spec]}]; "list_dir_limited" -> Spec = ssh_sftpd:subsystem_spec([{max_files,1}]), - [{user_passwords,[{?USER, ?PASSWD}]}, - {pwdfun, fun(_,_) -> true end}, - {system_dir, DataDir}, - {user_dir, DataDir}, + [{system_dir, SystemDir}, + {user_dir, PrivDir}, {subsystems, [Spec]}]; _ -> - [{user_passwords,[{?USER, ?PASSWD}]}, - {pwdfun, fun(_,_) -> true end}, - {user_dir, DataDir}, - {system_dir, DataDir}] + [{user_dir, PrivDir}, + {system_dir, SystemDir}] end, - {Sftpd, Host, _Port} = ssh_test_lib:daemon(any, ?SSHD_PORT, Options), + {Sftpd, Host, Port} = ssh_test_lib:daemon(Options), {ok, ChannelPid, Connection} = - ssh_sftp:start_channel(Host, ?SSHD_PORT, + ssh_sftp:start_channel(Host, Port, [{silently_accept_hosts, true}, - {user, ?USER}, {password, ?PASSWD}, - {pwdfun, fun(_,_) -> true end}, - {system_dir, DataDir}, - {user_dir, DataDir}, + {user_dir, PrivDir}, {timeout, 30000}]), TmpConfig = lists:keydelete(sftp, 1, Config), NewConfig = lists:keydelete(sftpd, 1, TmpConfig), - [{sftp, {ChannelPid, Connection}}, {sftpd, Sftpd} | NewConfig]. + [{port, Port}, {sftp, {ChannelPid, Connection}}, {sftpd, Sftpd} | NewConfig]. %%-------------------------------------------------------------------- %% Function: end_per_testcase(TestCase, Config) -> _ @@ -216,6 +210,8 @@ quit_OTP_6349(suite) -> quit_OTP_6349(Config) when is_list(Config) -> DataDir = ?config(data_dir, Config), FileName = filename:join(DataDir, "test.txt"), + UserDir = ?config(priv_dir, Config), + Port = ?config(port, Config), {Sftp, _} = ?config(sftp, Config), @@ -226,11 +222,10 @@ quit_OTP_6349(Config) when is_list(Config) -> Host = ssh_test_lib:hostname(), timer:sleep(5000), - {ok, NewSftp, _Conn} = ssh_sftp:start_channel(Host, ?SSHD_PORT, + {ok, NewSftp, _Conn} = ssh_sftp:start_channel(Host, Port, [{silently_accept_hosts, true}, {pwdfun, fun(_,_) -> true end}, - {system_dir, DataDir}, - {user_dir, DataDir}, + {user_dir, UserDir}, {user, ?USER}, {password, ?PASSWD}]), {ok, <<_/binary>>} = ssh_sftp:read_file(NewSftp, FileName), diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/id_dsa b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/id_dsa new file mode 100644 index 0000000000..d306f8b26e --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/id_dsa @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBvAIBAAKBgQDfi2flSTZZofwT4yQT0NikX/LGNT7UPeB/XEWe/xovEYCElfaQ +APFixXvEgXwoojmZ5kiQRKzLM39wBP0jPERLbnZXfOOD0PDnw0haMh7dD7XKVMod +/EigVgHf/qBdM2M8yz1s/rRF7n1UpLSypziKjkzCm7JoSQ2zbWIPdmBIXwIVAMgP +kpr7Sq3O7sHdb8D601DRjoExAoGAMOQxDfB2Fd8ouz6G96f/UOzRMI/Kdv8kYYKW +JIGY+pRYrLPyYzUeJznwZreOJgrczAX+luHnKFWJ2Dnk5CyeXk67Wsr7pJ/4MBMD +OKeIS0S8qoSBN8+Krp79fgA+yS3IfqbkJLtLu4EBaCX4mKQIX4++k44d4U5lc8pt ++9hlEI8CgYEAznKxx9kyC6bVo7LUYKaGhofRFt0SYFc5PVmT2VUGRs1R6+6DPD+e +uEO6IhFct7JFSRbP9p0JD4Uk+3zlZF+XX6b2PsZkeV8f/02xlNGUSmEzCSiNg1AX +Cy/WusYhul0MncWCHMcOZB5rIvU/aP5EJJtn3xrRaz6u0SThF6AnT34CFQC63czE +ZU8w8Q+H7z0j+a+70x2iAw== +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..51ab6fbd88 --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK +wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q +diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA +l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X +skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF +Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP +ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah +/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U +ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W +Lv62jKcdskxNyz2NQoBx +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub new file mode 100644 index 0000000000..4dbb1305b0 --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_host_dsa_key.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j +YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2 +KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU +aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI +fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT +MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh +DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48 +wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2 +/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl index 425fae22c1..26bbdf5c5c 100644 --- a/lib/ssh/test/ssh_test_lib.erl +++ b/lib/ssh/test/ssh_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% Copyright Ericsson AB 2004-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -68,15 +68,14 @@ daemon(Host, Port, Options) -> Error end. - - +start_shell(Port, IOServer, UserDir) -> + spawn_link(?MODULE, init_shell, [Port, IOServer, [{user_dir, UserDir}]]). start_shell(Port, IOServer) -> - spawn_link(?MODULE, init_shell, [Port, IOServer]). + spawn_link(?MODULE, init_shell, [Port, IOServer, []]). -init_shell(Port, IOServer) -> +init_shell(Port, IOServer, UserDir) -> Host = hostname(), - UserDir = get_user_dir(), Options = [{user_interaction, false}, {silently_accept_hosts, true}] ++ UserDir, group_leader(IOServer, self()), @@ -95,13 +94,10 @@ init_io_server(TestCase) -> loop_io_server(TestCase, Buff0) -> receive {input, TestCase, Line} -> - %io:format("~p~n",[{input, TestCase, Line}]), loop_io_server(TestCase, Buff0 ++ [Line]); {io_request, From, ReplyAs, Request} -> - %io:format("request -> ~p~n",[Request]), {ok, Reply, Buff} = io_request(Request, TestCase, From, ReplyAs, Buff0), - %io:format("reply -> ~p~n",[Reply]), io_reply(From, ReplyAs, Reply), loop_io_server(TestCase, Buff); {'EXIT',_, _} -> @@ -139,12 +135,18 @@ reply(TestCase, Result) -> receive_exec_result(Msg) -> test_server:format("Expect data! ~p", [Msg]), receive + {ssh_cm,_,{data,_,1, Data}} -> + test_server:format("StdErr: ~p~n", [Data]), + receive_exec_result(Msg); Msg -> test_server:format("1: Collected data ~p", [Msg]), expected; Other -> + test_server:format("Other ~p", [Other]), {unexpected_msg, Other} end. + + receive_exec_end(ConnectionRef, ChannelId) -> Eof = {ssh_cm, ConnectionRef, {eof, ChannelId}}, ExitStatus = {ssh_cm, ConnectionRef, {exit_status, ChannelId, 0}}, @@ -181,27 +183,21 @@ inet_port()-> gen_tcp:close(Socket), Port. - -%% copy private keys to given dir from ~/.ssh -get_id_keys(DstDir) -> - SrcDir = filename:join(os:getenv("HOME"), ".ssh"), - RsaOk = copyfile(SrcDir, DstDir, "id_rsa"), - DsaOk = copyfile(SrcDir, DstDir, "id_dsa"), - case {RsaOk, DsaOk} of - {{ok, _}, {ok, _}} -> {ok, both}; - {{ok, _}, _} -> {ok, rsa}; - {_, {ok, _}} -> {ok, dsa}; - {Error, _} -> Error - end. - -remove_id_keys(Dir) -> - file:delete(filename:join(Dir, "id_rsa")), - file:delete(filename:join(Dir, "id_dsa")). - -copyfile(SrcDir, DstDir, Fn) -> - file:copy(filename:join(SrcDir, Fn), - filename:join(DstDir, Fn)). - +setup_ssh_auth_keys(RSAFile, DSAFile, Dir) -> + Entries = ssh_file_entry(RSAFile) ++ ssh_file_entry(DSAFile), + AuthKeys = public_key:ssh_encode(Entries , auth_keys), + AuthKeysFile = filename:join(Dir, "authorized_keys"), + file:write_file(AuthKeysFile, AuthKeys). + +ssh_file_entry(PubFile) -> + case file:read_file(PubFile) of + {ok, Ssh} -> + [{Key, _}] = public_key:ssh_decode(Ssh, public_key), + [{Key, [{comment, "Test"}]}]; + _ -> + [] + end. + failfun(_User, {authmethod,none}) -> ok; failfun(User, Reason) -> @@ -222,463 +218,123 @@ known_hosts(BR) -> file:rename(B, KnownHosts) end. - -get_user_dir() -> - case os:type() of - {win32, _} -> - [{user_dir, filename:join([os:getenv("HOME"), ".ssh"])}]; - _ -> - [] - end. - - -make_dsa_cert_files(Config) -> - make_dsa_cert_files("", Config). - -make_dsa_cert_files(RoleStr, Config) -> - - CaInfo = {CaCert, _} = make_cert([{key, dsa}]), - {Cert, CertKey} = make_cert([{key, dsa}, {issuer, CaInfo}]), - CaCertFile = filename:join([?config(data_dir, Config), - RoleStr, "dsa_cacerts.pem"]), - CertFile = filename:join([?config(data_dir, Config), - RoleStr, "dsa_cert.pem"]), - KeyFile = filename:join([?config(data_dir, Config), - RoleStr, "dsa_key.pem"]), +setup_dsa(DataDir, UserDir) -> + file:copy(filename:join(DataDir, "id_dsa"), filename:join(UserDir, "id_dsa")), + System = filename:join(UserDir, "system"), + file:make_dir(System), + file:copy(filename:join(DataDir, "ssh_host_dsa_key"), filename:join(System, "ssh_host_dsa_key")), + file:copy(filename:join(DataDir, "ssh_host_dsa_key.pub"), filename:join(System, "ssh_host_dsa_key.pub")), + setup_dsa_known_host(DataDir, UserDir), + setup_dsa_auth_keys(DataDir, UserDir). - der_to_pem(CaCertFile, [{'Certificate', CaCert, not_encrypted}]), - der_to_pem(CertFile, [{'Certificate', Cert, not_encrypted}]), - der_to_pem(KeyFile, [CertKey]), - {CaCertFile, CertFile, KeyFile}. - -make_dsa_files(Config) -> - make_dsa_files(Config, rfc4716_public_key). -make_dsa_files(Config, Type) -> - {DSA, EncodedKey} = ssh_test_lib:gen_dsa(128, 20), - PKey = DSA#'DSAPrivateKey'.y, - P = DSA#'DSAPrivateKey'.p, - Q = DSA#'DSAPrivateKey'.q, - G = DSA#'DSAPrivateKey'.g, - Dss = #'Dss-Parms'{p=P, q=Q, g=G}, +setup_rsa(DataDir, UserDir) -> + file:copy(filename:join(DataDir, "id_rsa"), filename:join(UserDir, "id_rsa")), + System = filename:join(UserDir, "system"), + file:make_dir(System), + file:copy(filename:join(DataDir, "ssh_host_rsa_key"), filename:join(System, "ssh_host_rsa_key")), + file:copy(filename:join(DataDir, "ssh_host_rsa_key"), filename:join(System, "ssh_host_rsa_key.pub")), + setup_rsa_known_host(DataDir, UserDir), + setup_rsa_auth_keys(DataDir, UserDir). + +clean_dsa(UserDir) -> + del_dirs(filename:join(UserDir, "system")), + file:delete(filename:join(UserDir,"id_dsa")), + file:delete(filename:join(UserDir,"known_hosts")), + file:delete(filename:join(UserDir,"authorized_keys")). + +clean_rsa(UserDir) -> + del_dirs(filename:join(UserDir, "system")), + file:delete(filename:join(UserDir,"id_rsa")), + file:delete(filename:join(UserDir,"known_hosts")), + file:delete(filename:join(UserDir,"authorized_keys")). + +setup_dsa_pass_pharse(DataDir, UserDir, Phrase) -> + {ok, KeyBin} = file:read_file(filename:join(DataDir, "id_dsa")), + setup_pass_pharse(KeyBin, filename:join(UserDir, "id_dsa"), Phrase), + System = filename:join(UserDir, "system"), + file:make_dir(System), + file:copy(filename:join(DataDir, "ssh_host_dsa_key"), filename:join(System, "ssh_host_dsa_key")), + file:copy(filename:join(DataDir, "ssh_host_dsa_key.pub"), filename:join(System, "ssh_host_dsa_key.pub")), + setup_dsa_known_host(DataDir, UserDir), + setup_dsa_auth_keys(DataDir, UserDir). + +setup_rsa_pass_pharse(DataDir, UserDir, Phrase) -> + {ok, KeyBin} = file:read_file(filename:join(DataDir, "id_rsa")), + setup_pass_pharse(KeyBin, filename:join(UserDir, "id_rsa"), Phrase), + System = filename:join(UserDir, "system"), + file:make_dir(System), + file:copy(filename:join(DataDir, "ssh_host_rsa_key"), filename:join(System, "ssh_host_rsa_key")), + file:copy(filename:join(DataDir, "ssh_host_rsa_key.pub"), filename:join(System, "ssh_host_rsa_key.pub")), + setup_rsa_known_host(DataDir, UserDir), + setup_rsa_auth_keys(DataDir, UserDir). + +setup_pass_pharse(KeyBin, OutFile, Phrase) -> + [{KeyType, _,_} = Entry0] = public_key:pem_decode(KeyBin), + Key = public_key:pem_entry_decode(Entry0), + Salt = crypto:rand_bytes(8), + Entry = public_key:pem_entry_encode(KeyType, Key, + {{"DES-CBC", Salt}, Phrase}), + Pem = public_key:pem_encode([Entry]), + file:write_file(OutFile, Pem). + +setup_dsa_known_host(SystemDir, UserDir) -> + {ok, SshBin} = file:read_file(filename:join(SystemDir, "ssh_host_dsa_key.pub")), + [{Key, _}] = public_key:ssh_decode(SshBin, public_key), + setup_known_hosts(Key, UserDir). + +setup_rsa_known_host(SystemDir, UserDir) -> + {ok, SshBin} = file:read_file(filename:join(SystemDir, "ssh_host_rsa_key.pub")), + [{Key, _}] = public_key:ssh_decode(SshBin, public_key), + setup_known_hosts(Key, UserDir). + +setup_known_hosts(Key, UserDir) -> {ok, Hostname} = inet:gethostname(), {ok, {A, B, C, D}} = inet:getaddr(Hostname, inet), IP = lists:concat([A, ".", B, ".", C, ".", D]), - Attributes = [], % Could be [{comment,"user@" ++ Hostname}], - HostNames = [{hostnames,[IP, IP]}], - PublicKey = [{{PKey, Dss}, Attributes}], - KnownHosts = [{{PKey, Dss}, HostNames}], - + HostNames = [{hostnames,[Hostname, IP]}], + KnownHosts = [{Key, HostNames}], KnownHostsEnc = public_key:ssh_encode(KnownHosts, known_hosts), - KnownHosts = public_key:ssh_decode(KnownHostsEnc, known_hosts), - - PublicKeyEnc = public_key:ssh_encode(PublicKey, Type), -% PublicKey = public_key:ssh_decode(PublicKeyEnc, Type), - - SystemTmpDir = ?config(data_dir, Config), - filelib:ensure_dir(SystemTmpDir), - file:make_dir(SystemTmpDir), - - DSAFile = filename:join(SystemTmpDir, "ssh_host_dsa_key.pub"), - file:delete(DSAFile), - - DSAPrivateFile = filename:join(SystemTmpDir, "ssh_host_dsa_key"), - file:delete(DSAPrivateFile), + KHFile = filename:join(UserDir, "known_hosts"), + file:write_file(KHFile, KnownHostsEnc). - KHFile = filename:join(SystemTmpDir, "known_hosts"), - file:delete(KHFile), - - PemBin = public_key:pem_encode([EncodedKey]), - - file:write_file(DSAFile, PublicKeyEnc), - file:write_file(KHFile, KnownHostsEnc), - file:write_file(DSAPrivateFile, PemBin), - ok. - -%%-------------------------------------------------------------------- -%% Create and return a der encoded certificate -%% Option Default -%% ------------------------------------------------------- -%% digest sha1 -%% validity {date(), date() + week()} -%% version 3 -%% subject [] list of the following content -%% {name, Name} -%% {email, Email} -%% {city, City} -%% {state, State} -%% {org, Org} -%% {org_unit, OrgUnit} -%% {country, Country} -%% {serial, Serial} -%% {title, Title} -%% {dnQualifer, DnQ} -%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created) -%% (obs IssuerKey migth be {Key, Password} -%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key -%% -%% -%% (OBS: The generated keys are for testing only) -%% make_cert([{::atom(), ::term()}]) -> {Cert::binary(), Key::binary()} -%%-------------------------------------------------------------------- -make_cert(Opts) -> - SubjectPrivateKey = get_key(Opts), - {TBSCert, IssuerKey} = make_tbs(SubjectPrivateKey, Opts), - Cert = public_key:pkix_sign(TBSCert, IssuerKey), - true = verify_signature(Cert, IssuerKey, undef), %% verify that the keys where ok - {Cert, encode_key(SubjectPrivateKey)}. - -%%-------------------------------------------------------------------- -%% Writes cert files in Dir with FileName and FileName ++ Suffix -%% write_cert(::string(), ::string(), {Cert,Key}) -> ok -%%-------------------------------------------------------------------- -write_cert(Dir, FileName, Suffix, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) -> - ok = der_to_pem(filename:join(Dir, FileName), - [{'Certificate', Cert, not_encrypted}]), - ok = der_to_pem(filename:join(Dir, FileName ++ Suffix), [Key]). - -%%-------------------------------------------------------------------- -%% Creates a rsa key (OBS: for testing only) -%% the size are in bytes -%% gen_rsa(::integer()) -> {::atom(), ::binary(), ::opaque()} -%%-------------------------------------------------------------------- -gen_rsa(Size) when is_integer(Size) -> - Key = gen_rsa2(Size), - {Key, encode_key(Key)}. - -%%-------------------------------------------------------------------- -%% Creates a dsa key (OBS: for testing only) -%% the sizes are in bytes -%% gen_dsa(::integer()) -> {::atom(), ::binary(), ::opaque()} -%%-------------------------------------------------------------------- -gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) -> - Key = gen_dsa2(LSize, NSize), - {Key, encode_key(Key)}. - -%%-------------------------------------------------------------------- -%% Verifies cert signatures -%% verify_signature(::binary(), ::tuple()) -> ::boolean() -%%-------------------------------------------------------------------- -verify_signature(DerEncodedCert, DerKey, _KeyParams) -> - Key = decode_key(DerKey), - case Key of - #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} -> - public_key:pkix_verify(DerEncodedCert, - #'RSAPublicKey'{modulus=Mod, publicExponent=Exp}); - #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} -> - public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}) - end. - -%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -get_key(Opts) -> - case proplists:get_value(key, Opts) of - undefined -> make_key(rsa, Opts); - rsa -> make_key(rsa, Opts); - dsa -> make_key(dsa, Opts); - Key -> - Password = proplists:get_value(password, Opts, no_passwd), - decode_key(Key, Password) - end. - -decode_key({Key, Pw}) -> - decode_key(Key, Pw); -decode_key(Key) -> - decode_key(Key, no_passwd). - - -decode_key(#'RSAPublicKey'{} = Key,_) -> - Key; -decode_key(#'RSAPrivateKey'{} = Key,_) -> - Key; -decode_key(#'DSAPrivateKey'{} = Key,_) -> - Key; -decode_key(PemEntry = {_,_,_}, Pw) -> - public_key:pem_entry_decode(PemEntry, Pw); -decode_key(PemBin, Pw) -> - [KeyInfo] = public_key:pem_decode(PemBin), - decode_key(KeyInfo, Pw). - -encode_key(Key = #'RSAPrivateKey'{}) -> - {ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key), - {'RSAPrivateKey', list_to_binary(Der), not_encrypted}; -encode_key(Key = #'DSAPrivateKey'{}) -> - {ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key), - {'DSAPrivateKey', list_to_binary(Der), not_encrypted}. - -make_tbs(SubjectKey, Opts) -> - Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))), - - IssuerProp = proplists:get_value(issuer, Opts, true), - {Issuer, IssuerKey} = issuer(IssuerProp, Opts, SubjectKey), - - {Algo, Parameters} = sign_algorithm(IssuerKey, Opts), - - SignAlgo = #'SignatureAlgorithm'{algorithm = Algo, - parameters = Parameters}, - Subject = case IssuerProp of - true -> %% Is a Root Ca - Issuer; - _ -> - subject(proplists:get_value(subject, Opts),false) - end, - - {#'OTPTBSCertificate'{serialNumber = trunc(random:uniform()*100000000)*10000 + 1, - signature = SignAlgo, - issuer = Issuer, - validity = validity(Opts), - subject = Subject, - subjectPublicKeyInfo = publickey(SubjectKey), - version = Version, - extensions = extensions(Opts) - }, IssuerKey}. - -issuer(true, Opts, SubjectKey) -> - %% Self signed - {subject(proplists:get_value(subject, Opts), true), SubjectKey}; -issuer({Issuer, IssuerKey}, _Opts, _SubjectKey) when is_binary(Issuer) -> - {issuer_der(Issuer), decode_key(IssuerKey)}; -issuer({File, IssuerKey}, _Opts, _SubjectKey) when is_list(File) -> - {ok, [{cert, Cert, _}|_]} = pem_to_der(File), - {issuer_der(Cert), decode_key(IssuerKey)}. - -issuer_der(Issuer) -> - Decoded = public_key:pkix_decode_cert(Issuer, otp), - #'OTPCertificate'{tbsCertificate=Tbs} = Decoded, - #'OTPTBSCertificate'{subject=Subject} = Tbs, - Subject. - -subject(undefined, IsRootCA) -> - User = if IsRootCA -> "RootCA"; true -> os:getenv("USER") end, - Opts = [{email, User ++ "@erlang.org"}, - {name, User}, - {city, "Stockholm"}, - {country, "SE"}, - {org, "erlang"}, - {org_unit, "testing dep"}], - subject(Opts); -subject(Opts, _) -> - subject(Opts). - -subject(SubjectOpts) when is_list(SubjectOpts) -> - Encode = fun(Opt) -> - {Type,Value} = subject_enc(Opt), - [#'AttributeTypeAndValue'{type=Type, value=Value}] - end, - {rdnSequence, [Encode(Opt) || Opt <- SubjectOpts]}. - -%% Fill in the blanks -subject_enc({name, Name}) -> {?'id-at-commonName', {printableString, Name}}; -subject_enc({email, Email}) -> {?'id-emailAddress', Email}; -subject_enc({city, City}) -> {?'id-at-localityName', {printableString, City}}; -subject_enc({state, State}) -> {?'id-at-stateOrProvinceName', {printableString, State}}; -subject_enc({org, Org}) -> {?'id-at-organizationName', {printableString, Org}}; -subject_enc({org_unit, OrgUnit}) -> {?'id-at-organizationalUnitName', {printableString, OrgUnit}}; -subject_enc({country, Country}) -> {?'id-at-countryName', Country}; -subject_enc({serial, Serial}) -> {?'id-at-serialNumber', Serial}; -subject_enc({title, Title}) -> {?'id-at-title', {printableString, Title}}; -subject_enc({dnQualifer, DnQ}) -> {?'id-at-dnQualifier', DnQ}; -subject_enc(Other) -> Other. - - -extensions(Opts) -> - case proplists:get_value(extensions, Opts, []) of - false -> - asn1_NOVALUE; - Exts -> - lists:flatten([extension(Ext) || Ext <- default_extensions(Exts)]) - end. - -default_extensions(Exts) -> - Def = [{key_usage,undefined}, - {subject_altname, undefined}, - {issuer_altname, undefined}, - {basic_constraints, default}, - {name_constraints, undefined}, - {policy_constraints, undefined}, - {ext_key_usage, undefined}, - {inhibit_any, undefined}, - {auth_key_id, undefined}, - {subject_key_id, undefined}, - {policy_mapping, undefined}], - Filter = fun({Key, _}, D) -> lists:keydelete(Key, 1, D) end, - Exts ++ lists:foldl(Filter, Def, Exts). - -extension({_, undefined}) -> []; -extension({basic_constraints, Data}) -> - case Data of - default -> - #'Extension'{extnID = ?'id-ce-basicConstraints', - extnValue = #'BasicConstraints'{cA=true}, - critical=true}; - false -> - []; - Len when is_integer(Len) -> - #'Extension'{extnID = ?'id-ce-basicConstraints', - extnValue = #'BasicConstraints'{cA=true, pathLenConstraint=Len}, - critical=true}; +setup_dsa_auth_keys(Dir, UserDir) -> + {ok, Pem} = file:read_file(filename:join(Dir, "id_dsa")), + DSA = public_key:pem_entry_decode(hd(public_key:pem_decode(Pem))), + PKey = DSA#'DSAPrivateKey'.y, + P = DSA#'DSAPrivateKey'.p, + Q = DSA#'DSAPrivateKey'.q, + G = DSA#'DSAPrivateKey'.g, + Dss = #'Dss-Parms'{p=P, q=Q, g=G}, + setup_auth_keys([{{PKey, Dss}, [{comment, "Test"}]}], UserDir). + +setup_rsa_auth_keys(Dir, UserDir) -> + {ok, Pem} = file:read_file(filename:join(Dir, "id_rsa")), + RSA = public_key:pem_entry_decode(hd(public_key:pem_decode(Pem))), + #'RSAPrivateKey'{publicExponent = E, modulus = N} = RSA, + PKey = #'RSAPublicKey'{publicExponent = E, modulus = N}, + setup_auth_keys([{ PKey, [{comment, "Test"}]}], UserDir). + +setup_auth_keys(Keys, Dir) -> + AuthKeys = public_key:ssh_encode(Keys, auth_keys), + AuthKeysFile = filename:join(Dir, "authorized_keys"), + file:write_file(AuthKeysFile, AuthKeys). + + +del_dirs(Dir) -> + case file:list_dir(Dir) of + {ok, []} -> + file:del_dir(Dir); + {ok, Files} -> + lists:foreach(fun(File) -> + FullPath = filename:join(Dir,File), + case filelib:is_dir(FullPath) of + true -> + del_dirs(FullPath), + file:del_dir(FullPath); + false -> + file:delete(FullPath) + end + end, Files); _ -> - #'Extension'{extnID = ?'id-ce-basicConstraints', - extnValue = Data} - end; -extension({Id, Data, Critical}) -> - #'Extension'{extnID = Id, extnValue = Data, critical = Critical}. - - -publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) -> - Public = #'RSAPublicKey'{modulus=N, publicExponent=E}, - Algo = #'PublicKeyAlgorithm'{algorithm= ?rsaEncryption, parameters='NULL'}, - #'OTPSubjectPublicKeyInfo'{algorithm = Algo, - subjectPublicKey = Public}; -publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) -> - Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa', - parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}}, - #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}. - -validity(Opts) -> - DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1), - DefTo0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+7), - {DefFrom, DefTo} = proplists:get_value(validity, Opts, {DefFrom0, DefTo0}), - Format = fun({Y,M,D}) -> lists:flatten(io_lib:format("~w~2..0w~2..0w000000Z",[Y,M,D])) end, - #'Validity'{notBefore={generalTime, Format(DefFrom)}, - notAfter ={generalTime, Format(DefTo)}}. - -sign_algorithm(#'RSAPrivateKey'{}, Opts) -> - Type = case proplists:get_value(digest, Opts, sha1) of - sha1 -> ?'sha1WithRSAEncryption'; - sha512 -> ?'sha512WithRSAEncryption'; - sha384 -> ?'sha384WithRSAEncryption'; - sha256 -> ?'sha256WithRSAEncryption'; - md5 -> ?'md5WithRSAEncryption'; - md2 -> ?'md2WithRSAEncryption' - end, - {Type, 'NULL'}; -sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) -> - {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}. - -make_key(rsa, _Opts) -> - %% (OBS: for testing only) - gen_rsa2(64); -make_key(dsa, _Opts) -> - gen_dsa2(128, 20). %% Bytes i.e. {1024, 160} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% RSA key generation (OBS: for testing only) -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - --define(SMALL_PRIMES, [65537,97,89,83,79,73,71,67,61,59,53, - 47,43,41,37,31,29,23,19,17,13,11,7,5,3]). - -gen_rsa2(Size) -> - P = prime(Size), - Q = prime(Size), - N = P*Q, - Tot = (P - 1) * (Q - 1), - [E|_] = lists:dropwhile(fun(Candidate) -> (Tot rem Candidate) == 0 end, ?SMALL_PRIMES), - {D1,D2} = extended_gcd(E, Tot), - D = erlang:max(D1,D2), - case D < E of - true -> - gen_rsa2(Size); - false -> - {Co1,Co2} = extended_gcd(Q, P), - Co = erlang:max(Co1,Co2), - #'RSAPrivateKey'{version = 'two-prime', - modulus = N, - publicExponent = E, - privateExponent = D, - prime1 = P, - prime2 = Q, - exponent1 = D rem (P-1), - exponent2 = D rem (Q-1), - coefficient = Co - } + ok end. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% DSA key generation (OBS: for testing only) -%% See http://en.wikipedia.org/wiki/Digital_Signature_Algorithm -%% and the fips_186-3.pdf -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -gen_dsa2(LSize, NSize) -> - Q = prime(NSize), %% Choose N-bit prime Q - X0 = prime(LSize), - P0 = prime((LSize div 2) +1), - - %% Choose L-bit prime modulus P such that p-1 is a multiple of q. - case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of - error -> - gen_dsa2(LSize, NSize); - P -> - G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q. - %% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used. - - X = prime(20), %% Choose x by some random method, where 0 < x < q. - Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p. - - #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X} - end. - -%% See fips_186-3.pdf -dsa_search(T, P0, Q, Iter) when Iter > 0 -> - P = 2*T*Q*P0 + 1, - case is_prime(crypto:mpint(P), 50) of - true -> P; - false -> dsa_search(T+1, P0, Q, Iter-1) - end; -dsa_search(_,_,_,_) -> - error. - - -%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -prime(ByteSize) -> - Rand = odd_rand(ByteSize), - crypto:erlint(prime_odd(Rand, 0)). - -prime_odd(Rand, N) -> - case is_prime(Rand, 50) of - true -> - Rand; - false -> - NotPrime = crypto:erlint(Rand), - prime_odd(crypto:mpint(NotPrime+2), N+1) - end. - -%% see http://en.wikipedia.org/wiki/Fermat_primality_test -is_prime(_, 0) -> true; -is_prime(Candidate, Test) -> - CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate), - case crypto:mod_exp(CoPrime, Candidate, Candidate) of - CoPrime -> is_prime(Candidate, Test-1); - _ -> false - end. - -odd_rand(Size) -> - Min = 1 bsl (Size*8-1), - Max = (1 bsl (Size*8))-1, - odd_rand(crypto:mpint(Min), crypto:mpint(Max)). - -odd_rand(Min,Max) -> - Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max), - BitSkip = (Sz+4)*8-1, - case Rand of - Odd = <<_:BitSkip, 1:1>> -> Odd; - Even = <<_:BitSkip, 0:1>> -> - crypto:mpint(crypto:erlint(Even)+1) - end. - -extended_gcd(A, B) -> - case A rem B of - 0 -> - {0, 1}; - N -> - {X, Y} = extended_gcd(B, N), - {Y, X-Y*(A div B)} - end. - -pem_to_der(File) -> - {ok, PemBin} = file:read_file(File), - public_key:pem_decode(PemBin). - -der_to_pem(File, Entries) -> - PemBin = public_key:pem_encode(Entries), - file:write_file(File, PemBin). diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl index f959d50484..dfe526564d 100644 --- a/lib/ssh/test/ssh_to_openssh_SUITE.erl +++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -42,8 +42,12 @@ init_per_suite(Config) -> case catch crypto:start() of ok -> - ssh_test_lib:make_dsa_files(Config), - Config; + case gen_tcp:connect("localhost", 22, []) of + {error,econnrefused} -> + {skip,"No openssh deamon"}; + _ -> + Config + end; _Else -> {skip,"Could not start crypto!"} end. @@ -100,26 +104,38 @@ all() -> false -> {skip, "openSSH not installed on host"}; _ -> - [erlang_shell_client_openssh_server, - erlang_client_openssh_server_exec, - erlang_client_openssh_server_exec_compressed, - erlang_server_openssh_client_exec, - erlang_server_openssh_client_exec_compressed, - erlang_client_openssh_server_setenv, - erlang_client_openssh_server_publickey_rsa, - erlang_client_openssh_server_publickey_dsa, - erlang_server_openssh_client_pulic_key_dsa, - erlang_client_openssh_server_password] + [{group, erlang_client}, + {group, erlang_server} + ] end. groups() -> - []. - -init_per_group(_GroupName, Config) -> - Config. + [{erlang_client, [], [erlang_shell_client_openssh_server, + erlang_client_openssh_server_exec, + erlang_client_openssh_server_exec_compressed, + erlang_client_openssh_server_setenv, + erlang_client_openssh_server_publickey_rsa, + erlang_client_openssh_server_publickey_dsa, + erlang_client_openssh_server_password]}, + {erlang_server, [], [erlang_server_openssh_client_exec, + erlang_server_openssh_client_exec_compressed, + erlang_server_openssh_client_pulic_key_dsa]} + ]. + +init_per_group(erlang_server, Config) -> + DataDir = ?config(data_dir, Config), + UserDir = ?config(priv_dir, Config), + ssh_test_lib:setup_dsa_known_host(DataDir, UserDir), + Config; +init_per_group(_, Config) -> + Config. -end_per_group(_GroupName, Config) -> - Config. +end_per_group(erlang_server, Config) -> + UserDir = ?config(priv_dir, Config), + ssh_test_lib:clean_dsa(UserDir), + Config; +end_per_group(_, Config) -> + Config. %% TEST cases starts here. %%-------------------------------------------------------------------- @@ -229,7 +245,9 @@ erlang_server_openssh_client_exec(suite) -> erlang_server_openssh_client_exec(Config) when is_list(Config) -> SystemDir = ?config(data_dir, Config), - + PrivDir = ?config(priv_dir, Config), + KnownHosts = filename:join(PrivDir, "known_hosts"), + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, {failfun, fun ssh_test_lib:failfun/2}]), @@ -237,7 +255,10 @@ erlang_server_openssh_client_exec(Config) when is_list(Config) -> test_server:sleep(500), Cmd = "ssh -p " ++ integer_to_list(Port) ++ - " -o StrictHostKeyChecking=no "++ Host ++ " 1+1.", + " -o UserKnownHostsFile=" ++ KnownHosts ++ " " ++ Host ++ " 1+1.", + + test_server:format("Cmd: ~p~n", [Cmd]), + SshPort = open_port({spawn, Cmd}, [binary]), receive @@ -258,6 +279,9 @@ erlang_server_openssh_client_exec_compressed(suite) -> erlang_server_openssh_client_exec_compressed(Config) when is_list(Config) -> SystemDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + KnownHosts = filename:join(PrivDir, "known_hosts"), + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, {compression, zlib}, {failfun, fun ssh_test_lib:failfun/2}]), @@ -265,7 +289,7 @@ erlang_server_openssh_client_exec_compressed(Config) when is_list(Config) -> test_server:sleep(500), Cmd = "ssh -p " ++ integer_to_list(Port) ++ - " -o StrictHostKeyChecking=no -C "++ Host ++ " 1+1.", + " -o UserKnownHostsFile=" ++ KnownHosts ++ " -C "++ Host ++ " 1+1.", SshPort = open_port({spawn, Cmd}, [binary]), receive @@ -330,24 +354,27 @@ erlang_client_openssh_server_publickey_rsa(suite) -> []; erlang_client_openssh_server_publickey_rsa(Config) when is_list(Config) -> {ok,[[Home]]} = init:get_argument(home), - SrcDir = filename:join(Home, ".ssh"), - UserDir = ?config(priv_dir, Config), - case ssh_test_lib:copyfile(SrcDir, UserDir, "id_rsa") of - {ok, _} -> - ConnectionRef = - ssh_test_lib:connect(?SSH_DEFAULT_PORT, - [{user_dir, UserDir}, - {public_key_alg, ssh_rsa}, - {user_interaction, false}, - silently_accept_hosts]), - {ok, Channel} = - ssh_connection:session_channel(ConnectionRef, infinity), - ok = ssh_connection:close(ConnectionRef, Channel), - ok = ssh:close(ConnectionRef), - ok = file:delete(filename:join(UserDir, "id_rsa")); - {error, enoent} -> - {skip, "no ~/.ssh/id_rsa"} + KeyFile = filename:join(Home, ".ssh/id_rsa"), + case file:read_file(KeyFile) of + {ok, Pem} -> + case public_key:pem_decode(Pem) of + [{_,_, not_encrypted}] -> + ConnectionRef = + ssh_test_lib:connect(?SSH_DEFAULT_PORT, + [{public_key_alg, ssh_rsa}, + {user_interaction, false}, + silently_accept_hosts]), + {ok, Channel} = + ssh_connection:session_channel(ConnectionRef, infinity), + ok = ssh_connection:close(ConnectionRef, Channel), + ok = ssh:close(ConnectionRef); + _ -> + {skip, {error, "Has pass phrase can not be used by automated test case"}} + end; + _ -> + {skip, "no ~/.ssh/id_rsa"} end. + %%-------------------------------------------------------------------- erlang_client_openssh_server_publickey_dsa(doc) -> @@ -356,25 +383,26 @@ erlang_client_openssh_server_publickey_dsa(suite) -> []; erlang_client_openssh_server_publickey_dsa(Config) when is_list(Config) -> {ok,[[Home]]} = init:get_argument(home), - SrcDir = filename:join(Home, ".ssh"), - UserDir = ?config(priv_dir, Config), - case ssh_test_lib:copyfile(SrcDir, UserDir, "id_dsa") of - {ok, _} -> - ConnectionRef = - ssh_test_lib:connect(?SSH_DEFAULT_PORT, - [{user_dir, UserDir}, - {public_key_alg, ssh_dsa}, - {user_interaction, false}, - silently_accept_hosts]), - {ok, Channel} = - ssh_connection:session_channel(ConnectionRef, infinity), - ok = ssh_connection:close(ConnectionRef, Channel), - ok = ssh:close(ConnectionRef), - ok = file:delete(filename:join(UserDir, "id_dsa")); - {error, enoent} -> - {skip, "no ~/.ssh/id_dsa"} + KeyFile = filename:join(Home, ".ssh/id_dsa"), + case file:read_file(KeyFile) of + {ok, Pem} -> + case public_key:pem_decode(Pem) of + [{_,_, not_encrypted}] -> + ConnectionRef = + ssh_test_lib:connect(?SSH_DEFAULT_PORT, + [{public_key_alg, ssh_dsa}, + {user_interaction, false}, + silently_accept_hosts]), + {ok, Channel} = + ssh_connection:session_channel(ConnectionRef, infinity), + ok = ssh_connection:close(ConnectionRef, Channel), + ok = ssh:close(ConnectionRef); + _ -> + {skip, {error, "Has pass phrase can not be used by automated test case"}} + end; + _ -> + {skip, "no ~/.ssh/id_dsa"} end. - %%-------------------------------------------------------------------- erlang_server_openssh_client_pulic_key_dsa(doc) -> ["Validate using dsa publickey."]; @@ -384,6 +412,9 @@ erlang_server_openssh_client_pulic_key_dsa(suite) -> erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) -> SystemDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + KnownHosts = filename:join(PrivDir, "known_hosts"), + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, {public_key_alg, ssh_dsa}, {failfun, fun ssh_test_lib:failfun/2}]), @@ -391,7 +422,8 @@ erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) -> test_server:sleep(500), Cmd = "ssh -p " ++ integer_to_list(Port) ++ - " -o StrictHostKeyChecking=no "++ Host ++ " 1+1.", + " -o UserKnownHostsFile=" ++ KnownHosts ++ + " " ++ Host ++ " 1+1.", SshPort = open_port({spawn, Cmd}, [binary]), receive @@ -399,7 +431,6 @@ erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) -> ok after ?TIMEOUT -> test_server:fail("Did not receive answer") - end, ssh:stop_daemon(Pid). diff --git a/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key new file mode 100644 index 0000000000..51ab6fbd88 --- /dev/null +++ b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key @@ -0,0 +1,13 @@ +-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQCClaHzE2ul0gKSUxah5W0W8UiJLy4hXngKEqpaUq9SSdVdY2LK +wVfKH1gt5iuaf1FfzOhsIC9G/GLnjYttXZc92cv/Gfe3gR+s0ni2++MX+T++mE/Q +diltXv/Hp27PybS67SmiFW7I+RWnT2OKlMPtw2oUuKeztCe5UWjaj/y5FQIVAPLA +l9RpiU30Z87NRAHY3NTRaqtrAoGANMRxw8UfdtNVR0CrQj3AgPaXOGE4d+G4Gp4X +skvnCHycSVAjtYxebUkzUzt5Q6f/IabuLUdge3gXrc8BetvrcKbp+XZgM0/Vj2CF +Ymmy3in6kzGZq7Fw1sZaku6AOU8vLa5woBT2vAcHLLT1bLAzj7viL048T6MfjrOP +ef8nHvACgYBhDWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah +/XcF3DeRF+eEoz48wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+U +ykSTXYUbtsfTNRFQGBW2/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0CgIVAN4wtL5W +Lv62jKcdskxNyz2NQoBx +-----END DSA PRIVATE KEY----- + diff --git a/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub new file mode 100644 index 0000000000..4dbb1305b0 --- /dev/null +++ b/lib/ssh/test/ssh_to_openssh_SUITE_data/ssh_host_dsa_key.pub @@ -0,0 +1,11 @@ +---- BEGIN SSH2 PUBLIC KEY ---- +AAAAB3NzaC1kc3MAAACBAIKVofMTa6XSApJTFqHlbRbxSIkvLiFeeAoSqlpSr1JJ1V1j +YsrBV8ofWC3mK5p/UV/M6GwgL0b8YueNi21dlz3Zy/8Z97eBH6zSeLb74xf5P76YT9B2 +KW1e/8enbs/JtLrtKaIVbsj5FadPY4qUw+3DahS4p7O0J7lRaNqP/LkVAAAAFQDywJfU +aYlN9GfOzUQB2NzU0WqrawAAAIA0xHHDxR9201VHQKtCPcCA9pc4YTh34bganheyS+cI +fJxJUCO1jF5tSTNTO3lDp/8hpu4tR2B7eBetzwF62+twpun5dmAzT9WPYIViabLeKfqT +MZmrsXDWxlqS7oA5Ty8trnCgFPa8BwcstPVssDOPu+IvTjxPox+Os495/yce8AAAAIBh +DWFQJ1mf99sg92LalVq1dHLmVXb3PTJDfCO/Gz5NFmj9EZbAtdah/XcF3DeRF+eEoz48 +wQF/ExVxSMIhLdL+o+ElpVhlM7Yii+T7dPhkQfEul6zZXu+UykSTXYUbtsfTNRFQGBW2 +/GfnEc0mnIxfn9v10NEWMzlq5z9wT9P0Cg== +---- END SSH2 PUBLIC KEY ---- diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml index 5df2632149..1e1fe0d119 100644 --- a/lib/ssl/doc/src/notes.xml +++ b/lib/ssl/doc/src/notes.xml @@ -30,7 +30,101 @@ </header> <p>This document describes the changes made to the SSL application.</p> - <section><title>SSL 4.1.6</title> + <section><title>SSL 5.0</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Invalidation handling of sessions could cause the + time_stamp field in the session record to be set to + undefined crashing the session clean up process. This did + not affect the connections but would result in that the + session table would grow.</p> + <p> + Own Id: OTP-9696 Aux Id: seq11947 </p> + </item> + <item> + <p> + Changed code to use ets:foldl and throw instead of + ets:next traversal, avoiding the need to explicitly call + ets:safe_fixtable. It was possible to get a badarg-crash + under special circumstances.</p> + <p> + Own Id: OTP-9703 Aux Id: seq11947 </p> + </item> + <item> + <p> + Send ssl_closed notification to active ssl user when a + tcp error occurs.</p> + <p> + Own Id: OTP-9734 Aux Id: seq11946 </p> + </item> + <item> + <p> + If a passive receive was ongoing during a renegotiation + the process evaluating ssl:recv could be left hanging for + ever.</p> + <p> + Own Id: OTP-9744</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Support for the old ssl implementation is dropped and the + code is removed.</p> + <p> + Own Id: OTP-7048</p> + </item> + <item> + <p> + The erlang distribution can now be run over the new ssl + implementation. All options can currently not be set but + it is enough to replace to old ssl implementation.</p> + <p> + Own Id: OTP-7053</p> + </item> + <item> + <p> + public_key, ssl and crypto now supports PKCS-8</p> + <p> + Own Id: OTP-9312</p> + </item> + <item> + <p> + Implements a CBC timing attack counter measure. Thanks to + Andreas Schultz for providing the patch.</p> + <p> + Own Id: OTP-9683</p> + </item> + <item> + <p> + Mitigates an SSL/TLS Computational DoS attack by + disallowing the client to renegotiate many times in a row + in a short time interval, thanks to Tuncer Ayaz for + alerting us about this.</p> + <p> + Own Id: OTP-9739</p> + </item> + <item> + <p> + Implements the 1/n-1 splitting countermeasure to the + Rizzo Duong BEAST attack, affects SSL 3.0 and TLS 1.0. + Thanks to Tuncer Ayaz for alerting us about this.</p> + <p> + Own Id: OTP-9750</p> + </item> + </list> + </section> + +</section> + +<section><title>SSL 4.1.6</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl index 115527aae0..bc395cb6d5 100644 --- a/lib/ssl/src/inet_tls_dist.erl +++ b/lib/ssl/src/inet_tls_dist.erl @@ -57,7 +57,7 @@ accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) -> setup(Node, Type, MyNode, LongOrShortNames,SetupTime) -> Kernel = self(), - spawn(fun() -> do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) end). + spawn_opt(fun() -> do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) end, [link, {priority, max}]). do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> [Name, Address] = splitnode(Node, LongOrShortNames), @@ -229,9 +229,7 @@ connect_hs_data(Kernel, Node, MyNode, Socket, Timer, Version, Ip, TcpPort, Addre accept_hs_data(Kernel, MyNode, Socket, Timer, Allowed) -> common_hs_data(Kernel, MyNode, Socket, Timer, #hs_data{ allowed = Allowed, - f_address = fun(S, N) -> - ssl_tls_dist_proxy:get_remote_id(S, N) - end + f_address = fun get_remote_id/2 }). common_hs_data(Kernel, MyNode, Socket, Timer, HsData) -> @@ -273,3 +271,11 @@ common_hs_data(Kernel, MyNode, Socket, Timer, HsData) -> P = proplists:get_value(send_pend, Stats, 0), {ok, R,W,P} end}. + +get_remote_id(Socket, _Node) -> + case ssl_tls_dist_proxy:get_tcp_address(Socket) of + {ok, Address} -> + Address; + {error, _Reason} -> + ?shutdown(no_node) + end. diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index 371f475c85..542033e6ce 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -188,14 +188,14 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef, ValidationFunAndState = case VerifyFunAndState of undefined -> - {fun(OtpCert, ExtensionOrError, SslState) -> + {fun(OtpCert, ExtensionOrVerifyResult, SslState) -> ssl_certificate:validate_extension(OtpCert, - ExtensionOrError, SslState) + ExtensionOrVerifyResult, SslState) end, Role}; {Fun, UserState0} -> - {fun(OtpCert, ExtensionOrError, {SslState, UserState}) -> + {fun(OtpCert, {extension, _} = Extension, {SslState, UserState}) -> case ssl_certificate:validate_extension(OtpCert, - ExtensionOrError, + Extension, SslState) of {valid, NewSslState} -> {valid, {NewSslState, UserState}}; @@ -204,8 +204,11 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef, SslState); {unknown, _} -> apply_user_fun(Fun, OtpCert, - ExtensionOrError, UserState, SslState) - end + Extension, UserState, SslState) + end; + (OtpCert, VerifyResult, {SslState, UserState}) -> + apply_user_fun(Fun, OtpCert, VerifyResult, UserState, + SslState) end, {Role, UserState0}} end, diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl index d63eada571..1c61eb7ccc 100644 --- a/lib/ssl/src/ssl_tls_dist_proxy.erl +++ b/lib/ssl/src/ssl_tls_dist_proxy.erl @@ -19,7 +19,7 @@ -module(ssl_tls_dist_proxy). --export([listen/1, accept/1, connect/2, get_remote_id/2]). +-export([listen/1, accept/1, connect/2, get_tcp_address/1]). -export([init/1, start_link/0, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, ssl_options/2]). @@ -47,9 +47,6 @@ accept(Listen) -> connect(Ip, Port) -> gen_server:call(?MODULE, {connect, Ip, Port}, infinity). -get_remote_id(Socket, Node) -> - gen_server:call(?MODULE, {get_remote_id, {Socket,Node}}, infinity). - %%==================================================================== %% gen_server callbacks %%==================================================================== @@ -65,8 +62,8 @@ handle_call({listen, Name}, _From, State) -> case gen_tcp:listen(0, [{active, false}, {packet,?PPRE}]) of {ok, Socket} -> {ok, World} = gen_tcp:listen(0, [{active, false}, binary, {packet,?PPRE}]), - TcpAddress = get_tcp_address(Socket), - WorldTcpAddress = get_tcp_address(World), + {ok, TcpAddress} = get_tcp_address(Socket), + {ok, WorldTcpAddress} = get_tcp_address(World), {_,Port} = WorldTcpAddress#net_address.address, {ok, Creation} = erl_epmd:register_node(Name, Port), {reply, {ok, {Socket, TcpAddress, Creation}}, @@ -87,17 +84,16 @@ handle_call({connect, Ip, Port}, {From, _}, State) -> receive {Pid, go_ahead, LPort} -> Res = {ok, Socket} = try_connect(LPort), - ok = gen_tcp:controlling_process(Socket, From), - flush_old_controller(From, Socket), - {reply, Res, State}; + case gen_tcp:controlling_process(Socket, From) of + {error, badarg} = Error -> {reply, Error, State}; % From is dead anyway. + ok -> + flush_old_controller(From, Socket), + {reply, Res, State} + end; {Pid, Error} -> {reply, Error, State} end; -handle_call({get_remote_id, {Socket,_Node}}, _From, State) -> - Address = get_tcp_address(Socket), - {reply, Address, State}; - handle_call(_What, _From, State) -> {reply, ok, State}. @@ -117,14 +113,18 @@ code_change(_OldVsn, St, _Extra) -> %%% Internal functions %%-------------------------------------------------------------------- get_tcp_address(Socket) -> - {ok, Address} = inet:sockname(Socket), - {ok, Host} = inet:gethostname(), - #net_address{ + case inet:sockname(Socket) of + {ok, Address} -> + {ok, Host} = inet:gethostname(), + NetAddress = #net_address{ address = Address, host = Host, protocol = proxy, family = inet - }. + }, + {ok, NetAddress}; + {error, _} = Error -> Error + end. accept_loop(Proxy, erts = Type, Listen, Extra) -> process_flag(priority, max), @@ -178,8 +178,8 @@ setup_proxy(Ip, Port, Parent) -> Opts = get_ssl_options(client), case ssl:connect(Ip, Port, [{active, true}, binary, {packet,?PPRE}] ++ Opts) of {ok, World} -> - {ok, ErtsL} = gen_tcp:listen(0, [{active, true}, binary, {packet,?PPRE}]), - #net_address{address={_,LPort}} = get_tcp_address(ErtsL), + {ok, ErtsL} = gen_tcp:listen(0, [{active, true}, {ip, {127,0,0,1}}, binary, {packet,?PPRE}]), + {ok, #net_address{address={_,LPort}}} = get_tcp_address(ErtsL), Parent ! {self(), go_ahead, LPort}, case gen_tcp:accept(ErtsL) of {ok, Erts} -> @@ -194,7 +194,7 @@ setup_proxy(Ip, Port, Parent) -> setup_connection(World, ErtsListen) -> process_flag(trap_exit, true), - TcpAddress = get_tcp_address(ErtsListen), + {ok, TcpAddress} = get_tcp_address(ErtsListen), {_Addr,Port} = TcpAddress#net_address.address, {ok, Erts} = gen_tcp:connect({127,0,0,1}, Port, [{active, true}, binary, {packet,?PPRE}]), ssl:setopts(World, [{active,true}, {packet,?PPRE}]), @@ -223,7 +223,11 @@ loop_conn_setup(World, Erts) -> loop_conn_setup(World, Erts); {tcp, Erts, Data} -> ssl:send(World, Data), - loop_conn_setup(World, Erts) + loop_conn_setup(World, Erts); + {tcp_closed, Erts} -> + ssl:close(World); + {ssl_closed, World} -> + gen_tcp:close(Erts) end. loop_conn(World, Erts) -> diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 527263363c..590ecf33ca 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -250,6 +250,8 @@ all() -> no_authority_key_identifier, invalid_signature_client, invalid_signature_server, cert_expired, client_with_cert_cipher_suites_handshake, + verify_fun_always_run_client, + verify_fun_always_run_server, unknown_server_ca_fail, der_input, unknown_server_ca_accept_verify_none, unknown_server_ca_accept_verify_peer, @@ -3217,6 +3219,105 @@ client_with_cert_cipher_suites_handshake(Config) when is_list(Config) -> ssl_test_lib:check_result(Server, ok, Client, ok), ssl_test_lib:close(Server), ssl_test_lib:close(Client). + +%%-------------------------------------------------------------------- +verify_fun_always_run_client(doc) -> + ["Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"]; +verify_fun_always_run_client(suite) -> + []; +verify_fun_always_run_client(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + %% If user verify fun is called correctly we fail the connection. + %% otherwise we can not tell this case apart form where we miss + %% to call users verify fun + FunAndState = {fun(_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, valid, [ChainLen]) -> + {valid, [ChainLen + 1]}; + (_, valid_peer, [2]) -> + {fail, "verify_fun_was_always_run"}; + (_, valid_peer, UserState) -> + {valid, UserState} + end, [0]}, + + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, FunAndState} + | ClientOpts]}]), + %% Server error may be esslaccept or closed depending on timing + %% this is not a bug it is a circumstance of how tcp works! + receive + {Server, ServerError} -> + test_server:format("Server Error ~p~n", [ServerError]) + end, + + ssl_test_lib:check_result(Client, {error, esslconnect}). + +%%-------------------------------------------------------------------- +verify_fun_always_run_server(doc) -> + ["Verify that user verify_fun is always run (for valid and valid_peer not only unknown_extension)"]; +verify_fun_always_run_server(suite) -> + []; +verify_fun_always_run_server(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + %% If user verify fun is called correctly we fail the connection. + %% otherwise we can not tell this case apart form where we miss + %% to call users verify fun + FunAndState = {fun(_,{extension, _}, UserState) -> + {unknown, UserState}; + (_, valid, [ChainLen]) -> + {valid, [ChainLen + 1]}; + (_, valid_peer, [2]) -> + {fail, "verify_fun_was_always_run"}; + (_, valid_peer, UserState) -> + {valid, UserState} + end, [0]}, + + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, + [{verify, verify_peer}, + {verify_fun, FunAndState} | + ServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, + no_result, []}}, + {options, + [{verify, verify_peer} + | ClientOpts]}]), + + %% Client error may be esslconnect or closed depending on timing + %% this is not a bug it is a circumstance of how tcp works! + receive + {Client, ClientError} -> + test_server:format("Client Error ~p~n", [ClientError]) + end, + + ssl_test_lib:check_result(Server, {error, esslaccept}). + %%-------------------------------------------------------------------- unknown_server_ca_fail(doc) -> ["Test that the client fails if the ca is unknown in verify_peer mode"]; @@ -3924,7 +4025,7 @@ renegotiate(Socket, Data) -> end. renegotiate_reuse_session(Socket, Data) -> - %% Make sure session is registerd + %% Make sure session is registered test_server:sleep(?SLEEP), renegotiate(Socket, Data). diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl index 8fe55ee7a4..06182970e3 100644 --- a/lib/ssl/test/ssl_dist_SUITE.erl +++ b/lib/ssl/test/ssl_dist_SUITE.erl @@ -26,7 +26,7 @@ -define(DEFAULT_TIMETRAP_SECS, 240). --define(AWAIT_SLL_NODE_UP_TIMEOUT, 30000). +-define(AWAIT_SSL_NODE_UP_TIMEOUT, 30000). -record(node_handle, {connection_handler, @@ -120,6 +120,12 @@ basic(Config) when is_list(Config) -> pang = net_adm:ping(Node1), pang = net_adm:ping(Node2), + %% SSL nodes should not be able to communicate with the test_server node + %% either (and ping should return eventually). + TestServer = node(), + pang = apply_on_ssl_node(NH1, fun () -> net_adm:ping(TestServer) end), + pang = apply_on_ssl_node(NH2, fun () -> net_adm:ping(TestServer) end), + %% %% Check that we are able to communicate over the erlang %% distribution between the ssl nodes. @@ -380,7 +386,7 @@ mk_node_cmdline(ListenPort, Name, Args) -> %% await_ssl_node_up(Name, LSock) -> - case gen_tcp:accept(LSock, ?AWAIT_SLL_NODE_UP_TIMEOUT) of + case gen_tcp:accept(LSock, ?AWAIT_SSL_NODE_UP_TIMEOUT) of timeout -> gen_tcp:close(LSock), ?t:format("Timeout waiting for ssl node ~s to come up~n", diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl index f04ab9af50..01fca1f166 100644 --- a/lib/ssl/test/ssl_to_openssl_SUITE.erl +++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1446,8 +1446,8 @@ check_sane_openssl_renegotaite(Config) -> check_sane_openssl_sslv2(Config) -> case os:cmd("openssl version") of - "OpenSSL 1.0.0e" ++ _ -> - {skip, "Known option bug"}; + "OpenSSL 1.0.0" ++ _ -> + {skip, "sslv2 by default turned of in 1.*"}; _ -> Config end. diff --git a/lib/stdlib/doc/src/binary.xml b/lib/stdlib/doc/src/binary.xml index 88ce77e0d0..7ce2defb72 100644 --- a/lib/stdlib/doc/src/binary.xml +++ b/lib/stdlib/doc/src/binary.xml @@ -505,7 +505,7 @@ <type> <v>Subject = binary()</v> <v>Pos = integer() >= 0</v> - <v>Len = integer() >= 0</v> + <v>Len = integer()</v> </type> <desc> <p>The same as <c>part(Subject, {Pos, Len})</c>.</p> diff --git a/lib/stdlib/doc/src/io.xml b/lib/stdlib/doc/src/io.xml index 667d758e29..e6d262466c 100644 --- a/lib/stdlib/doc/src/io.xml +++ b/lib/stdlib/doc/src/io.xml @@ -70,7 +70,7 @@ <desc> <p>Either <c>standard_io</c>, <c>standard_error</c>, a registered name, or a pid handling IO protocols (returned from - <seealso marker="file#open/2">file:open/2</seealso>).</p> + <seealso marker="kernel:file#open/2">file:open/2</seealso>).</p> </desc> </datatype> <datatype> diff --git a/lib/stdlib/doc/src/ms_transform.xml b/lib/stdlib/doc/src/ms_transform.xml index f81f8bda96..ad5f8bd5ac 100644 --- a/lib/stdlib/doc/src/ms_transform.xml +++ b/lib/stdlib/doc/src/ms_transform.xml @@ -308,7 +308,7 @@ ets:select(emp_tab, ets:fun2ms( Erlang code. Also arithmetics is allowed, as well as ordinary guard bif's. Here's a list of bif's and expressions:</p> <list type="bulleted"> - <item>The type tests: is_atom, is_constant, is_float, is_integer, + <item>The type tests: is_atom, is_float, is_integer, is_list, is_number, is_pid, is_port, is_reference, is_tuple, is_binary, is_function, is_record</item> <item>The boolean operators: not, and, or, andalso, orelse </item> @@ -318,7 +318,7 @@ ets:select(emp_tab, ets:fun2ms( <item>The guard bif's: abs, element, hd, length, node, round, size, tl, trunc, self</item> <item>The obsolete type test (only in guards): - atom, constant, float, integer, + atom, float, integer, list, number, pid, port, reference, tuple, binary, function, record</item> </list> diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml index d9c220b996..42a26ee44a 100644 --- a/lib/stdlib/doc/src/notes.xml +++ b/lib/stdlib/doc/src/notes.xml @@ -30,6 +30,297 @@ </header> <p>This document describes the changes made to the STDLIB application.</p> +<section><title>STDLIB 1.18</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Improved algorithm in module <c>random</c>. Avoid seed + values that are even divisors of the primes and by that + prevent getting sub-seeds that are stuck on zero. Worst + case was random:seed(0,0,0) that produced a series of + only zeros. This is an incompatible change in the sense + that applications that relies on reproducing a specific + series for a given seed will fail. The pseudo random + output is still deterministic but different compared to + earlier versions.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-8713</p> + </item> + <item> + <p> Calls to <c>global:whereis_name/1</c> have been + substituted for calls to + <c>global:safe_whereis_name/1</c> since the latter is not + safe at all.</p> + <p>The reason for not doing this earlier is that setting + a global lock masked out a bug concerning the restart of + supervised children. The bug has now been fixed by a + modification of <c>global:whereis_name/1</c>. (Thanks to + Ulf Wiger for code contribution.)</p> + <p>A minor race conditions in <c>gen_fsm:start*</c> has + been fixed: if one of these functions returned <c>{error, + Reason}</c> or ignore, the name could still be registered + (either locally or in <c>global</c>. (This is the same + modification as was done for gen_server in OTP-7669.)</p> + <p>The undocumented function + <c>global:safe_whereis_name/1</c> has been removed. </p> + <p> + Own Id: OTP-9212 Aux Id: seq7117, OTP-4174 </p> + </item> + <item> + <p> + If a child of a supervisor terminates with reason + {shutdown,Term} it is now handled by the supervisor as if + the reason was 'shutdown'. </p> + <p> + For children with restart type 'permanent', this implies + no change. For children with restart type 'transient', + the child will no longer be restarted and no supervisor + report will be written. For children with restart type + 'temporary', no supervisor report will be written.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9222</p> + </item> + <item> + <p> + Minor improvement of documentation regarding supervisor + restart strategy for temporary and transient child + processes.</p> + <p> + Own Id: OTP-9381</p> + </item> + <item> + <p>A Dets table with sufficiently large buckets could not + always be repaired. This bug has been fixed. </p> <p>The + format of Dets files has been modified. When downgrading + tables created with the new system will be repaired. + Otherwise the modification should not be noticeable. </p> + <p> + Own Id: OTP-9607</p> + </item> + <item> + <p> A few contracts in the <c>lists</c> module have been + corrected. </p> + <p> + Own Id: OTP-9616</p> + </item> + <item> + <p> + Add '-callback' attributes in stdlib's behaviours</p> + <p> + Replace the behaviour_info(callbacks) export in stdlib's + behaviours with -callback' attributes for all the + callbacks. Update the documentation with information on + the callback attribute Automatically generate + 'behaviour_info' function from '-callback' attributes</p> + <p> + 'behaviour_info(callbacks)' is a special function that is + defined in a module which describes a behaviour and + returns a list of its callbacks.</p> + <p> + This function is now automatically generated using the + '-callback' specs. An error is returned by lint if user + defines both '-callback' attributes and the + behaviour_info/1 function. If no type info is needed for + a callback use a generic spec for it. Add '-callback' + attribute to language syntax</p> + <p> + Behaviours may define specs for their callbacks using the + familiar spec syntax, replacing the '-spec' keyword with + '-callback'. Simple lint checks are performed to ensure + that no callbacks are defined twice and all types + referred are declared.</p> + <p> + These attributes can be then used by tools to provide + documentation to the behaviour or find discrepancies in + the callback definitions in the callback module.</p> + <p> + Add callback specs into 'application' module in kernel + Add callback specs to tftp module following internet + documentation Add callback specs to inets_service module + following possibly deprecated comments</p> + <p> + Own Id: OTP-9621</p> + </item> + <item> + <p> If a Dets table had been properly closed but the + space management data could not been read, it was not + possible to repair the file. This bug has been fixed. + </p> + <p> + Own Id: OTP-9622</p> + </item> + <item> + <p> + The Unicode noncharacter code points 16#FFFE and 16#FFFE + were not allowed to be encoded or decoded using the + <c>unicode</c> module or bit syntax. That was + inconsistent with the other noncharacters 16#FDD0 to + 16#FDEF that could be encoded/decoded. To resolve the + inconsistency, 16#FFFE and 16#FFFE can now be encoded and + decoded. (Thanks to Alisdair Sullivan.)</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9624</p> + </item> + <item> + <p> + Make epp search directory of current file first when + including another file This completes a partial fix in + R11 that only worked for include_lib(). (Thanks to + Richard Carlsson)</p> + <p> + Own Id: OTP-9645</p> + </item> + <item> + <p> + ms_transform: Fix incorrect `variable shadowed' warnings</p> + <p> + This patch removes incorrect passing of variable bindings + from one function clause to another. (Thanks to Haitao + Li)</p> + <p> + Own Id: OTP-9646</p> + </item> + <item> + <p> + Explicitly kill dynamic children in supervisors</p> + <p> + According to the supervisor's documentation: "Important + note on simple-one-for-one supervisors: The dynamically + created child processes of a simple-one-for-one + supervisor are not explicitly killed, regardless of + shutdown strategy, but are expected to terminate when the + supervisor does (that is, when an exit signal from the + parent process is received)."</p> + <p> + All is fine as long as we stop simple_one_for_one + supervisor manually. Dynamic children catch the exit + signal from the supervisor and leave. But, if this + happens when we stop an application, after the top + supervisor has stopped, the application master kills all + remaining processes associated to this application. So, + dynamic children that trap exit signals can be killed + during their cleanup (here we mean inside terminate/2). + This is unpredictable and highly time-dependent.</p> + <p> + In this commit, supervisor module is patched to + explicitly terminate dynamic children accordingly to the + shutdown strategy.</p> + <p> + NOTE: Order in which dynamic children are stopped is not + defined. In fact, this is "almost" done at the same time.</p> + <p> + Stack errors when dynamic children are stopped</p> + <p> + Because a simple_one_for_one supervisor can have many + workers, we stack errors during its shutdown to report + only one message for each encountered error type. Instead + of reporting the child's pid, we use the number of + concerned children. (Thanks to Christopher Faulet)</p> + <p> + Own Id: OTP-9647</p> + </item> + <item> + <p> + Allow an infinite timeout to shutdown worker processes</p> + <p> + Now, in child specification, the shutdown value can also + be set to infinity for worker children. This restriction + was removed because this is not always possible to + predict the shutdown time for a worker. This is highly + application-dependent. Add a warning to docs about + workers' shutdown strategy (Thanks to Christopher Faulet)</p> + <p> + Own Id: OTP-9648</p> + </item> + <item> + <p> + A badarg would sometimes occur in supervisor when + printing error reports and the child pid was undefined. + This has been corrected.</p> + <p> + Own Id: OTP-9669</p> + </item> + <item> + <p> + Fix re:split spec not to accept option 'global'(Thanks to + Shunichi Shinohara)</p> + <p> + Own Id: OTP-9691</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> Fix a few tests that used to fail on the HiPE + platform. </p> + <p> + Own Id: OTP-9637</p> + </item> + <item> + <p>Variables are now now allowed in '<c>fun M:F/A</c>' as + suggested by Richard O'Keefe in EEP-23.</p> + <p>The representation of '<c>fun M:F/A</c>' in the + abstract format has been changed in an incompatible way. + Tools that directly read or manipulate the abstract + format (such as parse transforms) may need to be updated. + The compiler can handle both the new and the old format + (i.e. extracting the abstract format from a pre-R15 BEAM + file and compiling it using compile:forms/1,2 will work). + The <c>syntax_tools</c> application can also handle both + formats.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9643</p> + </item> + <item> + <p> + Tuple funs (a two-element tuple with a module name and a + function) are now officially deprecated and will be + removed in R16. Use '<c>fun M:F/A</c>' instead. To make + you aware that your system uses tuple funs, the very + first time a tuple fun is applied, a warning will be sent + to the error logger.</p> + <p> + Own Id: OTP-9649</p> + </item> + <item> + <p> + The deprecated '<c>regexp</c>' module has been removed. + Use the '<c>re</c>' module instead.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9737</p> + </item> + <item> + <p> + <c>filename:find_src/1,2</c> will now work on stripped + BEAM files (reported by Per Hedeland). The HiPE compiler + will also work on stripped BEAM files. The BEAM compiler + will no longer include compilation options given in the + source code itself in <c>M:module_info(compile)</c> + (because those options will be applied anyway if the + module is re-compiled).</p> + <p> + Own Id: OTP-9752</p> + </item> + </list> + </section> + +</section> + <section><title>STDLIB 1.17.5</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/stdlib/doc/src/sofs.xml b/lib/stdlib/doc/src/sofs.xml index 2e7768a1df..37c41501ae 100644 --- a/lib/stdlib/doc/src/sofs.xml +++ b/lib/stdlib/doc/src/sofs.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2001</year><year>2011</year> + <year>2001</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -317,7 +317,7 @@ but is to be preferred since it makes it possible to handle this case even more efficiently. Examples of SetFuns:</p> <pre> -{sofs, union} +fun sofs:union/1 fun(S) -> sofs:partition(1, S) end {external, fun(A) -> A end} {external, fun({A,_,C}) -> {C,A} end} @@ -711,7 +711,7 @@ fun(S) -> sofs:partition(1, S) end argument.</p> <pre> 1> <input>F1 = sofs:from_term([{a,[[1,2],[2,3]]},{b,[[]]}]),</input> -<input>F2 = sofs:family_projection({sofs, union}, F1),</input> +<input>F2 = sofs:family_projection(fun sofs:union/1, F1),</input> <input>sofs:to_external(F2).</input> [{a,[1,2,3]},{b,[]}]</pre> </desc> @@ -821,7 +821,7 @@ fun(S) -> sofs:partition(1, S) end <input>sofs:to_external(F2).</input> [{a,[1,2,3]},{b,[]}]</pre> <p><c>family_union(F)</c> is equivalent to - <c>family_projection({sofs,union}, F)</c>.</p> + <c>family_projection(fun sofs:union/1, F)</c>.</p> </desc> </func> <func> @@ -1438,7 +1438,7 @@ true</pre> 1> <input>R1 = sofs:relation([{a,1},{b,2}]),</input> <input>R2 = sofs:relation([{x,1},{x,2},{y,3}]),</input> <input>S1 = sofs:from_sets([R1,R2]),</input> -<input>S2 = sofs:specification({sofs,is_a_function}, S1),</input> +<input>S2 = sofs:specification(fun sofs:is_a_function/1, S1),</input> <input>sofs:to_external(S2).</input> [[{a,1},{b,2}]]</pre> </desc> diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml index cddb55e5c5..33a7f5bb6a 100644 --- a/lib/stdlib/doc/src/supervisor.xml +++ b/lib/stdlib/doc/src/supervisor.xml @@ -127,25 +127,18 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules} <p><c>StartFunc</c> defines the function call used to start the child process. It should be a module-function-arguments tuple <c>{M,F,A}</c> used as <c>apply(M,F,A)</c>.</p> - <p> <br></br> -</p> <p>The start function <em>must create and link to</em> the child process, and should return <c>{ok,Child}</c> or <c>{ok,Child,Info}</c> where <c>Child</c> is the pid of the child process and <c>Info</c> an arbitrary term which is ignored by the supervisor.</p> - <p> <br></br> -</p> <p>The start function can also return <c>ignore</c> if the child process for some reason cannot be started, in which case - the child specification will be kept by the supervisor but - the non-existing child process will be ignored.</p> - <p> <br></br> -</p> + the child specification will be kept by the supervisor + (unless it is a temporary child) but the non-existing child + process will be ignored.</p> <p>If something goes wrong, the function may also return an error tuple <c>{error,Error}</c>.</p> - <p> <br></br> -</p> <p>Note that the <c>start_link</c> functions of the different behaviour modules fulfill the above requirements.</p> </item> diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl index bf3c7b3504..95ba6b1096 100644 --- a/lib/stdlib/src/erl_eval.erl +++ b/lib/stdlib/src/erl_eval.erl @@ -947,7 +947,6 @@ type_test(integer) -> is_integer; type_test(float) -> is_float; type_test(number) -> is_number; type_test(atom) -> is_atom; -type_test(constant) -> is_constant; type_test(list) -> is_list; type_test(tuple) -> is_tuple; type_test(pid) -> is_pid; diff --git a/lib/stdlib/src/erl_expand_records.erl b/lib/stdlib/src/erl_expand_records.erl index 20fd247cea..1c69a131f9 100644 --- a/lib/stdlib/src/erl_expand_records.erl +++ b/lib/stdlib/src/erl_expand_records.erl @@ -452,8 +452,10 @@ conj([], _E) -> conj([{{Name,_Rp},L,R,Sz} | AL], E) -> NL = neg_line(L), T1 = {op,NL,'orelse', - {call,NL,{atom,NL,is_record},[R,{atom,NL,Name},{integer,NL,Sz}]}, - {atom,NL,fail}}, + {call,NL, + {remote,NL,{atom,NL,erlang},{atom,NL,is_record}}, + [R,{atom,NL,Name},{integer,NL,Sz}]}, + {atom,NL,fail}}, T2 = case conj(AL, none) of empty -> T1; C -> {op,NL,'and',C,T1} @@ -581,7 +583,9 @@ strict_get_record_field(Line, R, {atom,_,F}=Index, Name, St0) -> ExpRp = erl_lint:modify_line(ExpR, fun(_L) -> 0 end), RA = {{Name,ExpRp},Line,ExpR,length(Fs)+1}, St2 = St1#exprec{strict_ra = [RA | St1#exprec.strict_ra]}, - {{call,Line,{atom,Line,element},[I,ExpR]},St2} + {{call,Line, + {remote,Line,{atom,Line,erlang},{atom,Line,element}}, + [I,ExpR]},St2} end. record_pattern(I, I, Var, Sz, Line, Acc) -> @@ -593,7 +597,9 @@ record_pattern(_, _, _, _, _, Acc) -> reverse(Acc). sloppy_get_record_field(Line, R, Index, Name, St) -> Fs = record_fields(Name, St), I = index_expr(Line, Index, Name, Fs), - expr({call,Line,{atom,Line,element},[I,R]}, St). + expr({call,Line, + {remote,Line,{atom,Line,erlang},{atom,Line,element}}, + [I,R]}, St). strict_record_tests([strict_record_tests | _]) -> true; strict_record_tests([no_strict_record_tests | _]) -> false; @@ -710,7 +716,8 @@ record_setel(R, Name, Fs, Us0) -> {'case',Lr,R, [{clause,Lr,[{tuple,Lr,[{atom,Lr,Name} | Wildcards]}],[], [foldr(fun ({I,Lf,Val}, Acc) -> - {call,Lf,{atom,Lf,setelement},[I,Acc,Val]} end, + {call,Lf,{remote,Lf,{atom,Lf,erlang}, + {atom,Lf,setelement}},[I,Acc,Val]} end, R, Us)]}, {clause,NLr,[{var,NLr,'_'}],[], [call_error(NLr, {tuple,NLr,[{atom,NLr,badrecord},{atom,NLr,Name}]})]}]}. diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl index e5adb84932..a1af0057ca 100644 --- a/lib/stdlib/src/erl_lint.erl +++ b/lib/stdlib/src/erl_lint.erl @@ -1804,12 +1804,19 @@ guard_test(G, Vt, St0) -> %% Specially handle record type test here. guard_test2({call,Line,{atom,Lr,record},[E,A]}, Vt, St0) -> gexpr({call,Line,{atom,Lr,is_record},[E,A]}, Vt, St0); -guard_test2({call,_Line,{atom,_La,F},As}=G, Vt, St0) -> +guard_test2({call,Line,{atom,_La,F},As}=G, Vt, St0) -> {Asvt,St1} = gexpr_list(As, Vt, St0), %Always check this. A = length(As), case erl_internal:type_test(F, A) of - true when F =/= is_record -> {Asvt,St1}; - _ -> gexpr(G, Vt, St0) + true when F =/= is_record, A =/= 2 -> + case no_guard_bif_clash(St1, {F,A}) of + false -> + {Asvt,add_error(Line, {illegal_guard_local_call,{F,A}}, St1)}; + true -> + {Asvt,St1} + end; + _ -> + gexpr(G, Vt, St0) end; guard_test2(G, Vt, St) -> %% Everything else is a guard expression. @@ -1865,9 +1872,15 @@ gexpr({call,Line,{atom,_Lr,is_record},[E,R]}, Vt, St0) -> gexpr({call,Line,{remote,_Lr,{atom,_Lm,erlang},{atom,Lf,is_record}},[E,A]}, Vt, St0) -> gexpr({call,Line,{atom,Lf,is_record},[E,A]}, Vt, St0); -gexpr({call,_Line,{atom,_Lr,is_record},[E,{atom,_,_Name},{integer,_,_}]}, +gexpr({call,Line,{atom,_Lr,is_record},[E0,{atom,_,_Name},{integer,_,_}]}, Vt, St0) -> - gexpr(E, Vt, St0); + {E,St1} = gexpr(E0, Vt, St0), + case no_guard_bif_clash(St0, {is_record,3}) of + true -> + {E,St1}; + false -> + {E,add_error(Line, {illegal_guard_local_call,{is_record,3}}, St1)} + end; gexpr({call,Line,{atom,_Lr,is_record},[_,_,_]=Asvt0}, Vt, St0) -> {Asvt,St1} = gexpr_list(Asvt0, Vt, St0), {Asvt,add_error(Line, illegal_guard_expr, St1)}; @@ -3423,17 +3436,11 @@ obsolete_guard({call,Line,{atom,Lr,F},As}, St0) -> false -> deprecated_function(Line, erlang, F, As, St0); true -> - St1 = case F of - constant -> - deprecated_function(Lr, erlang, is_constant, As, St0); - _ -> - St0 - end, - case is_warn_enabled(obsolete_guard, St1) of + case is_warn_enabled(obsolete_guard, St0) of true -> - add_warning(Lr,{obsolete_guard, {F, Arity}}, St1); + add_warning(Lr,{obsolete_guard, {F, Arity}}, St0); false -> - St1 + St0 end end; obsolete_guard(_G, St) -> diff --git a/lib/stdlib/src/error_logger_file_h.erl b/lib/stdlib/src/error_logger_file_h.erl index ee4f0b3a51..08f1873803 100644 --- a/lib/stdlib/src/error_logger_file_h.erl +++ b/lib/stdlib/src/error_logger_file_h.erl @@ -104,7 +104,7 @@ code_change(_OldVsn, State, _Extra) -> %%% ------------------------------------------------------ tag_event(Event) -> - {erlang:localtime(), Event}. + {erlang:universaltime(), Event}. write_events(Fd, Events) -> write_events1(Fd, lists:reverse(Events)). @@ -169,23 +169,18 @@ write_event(_, _) -> maybe_utc(Time) -> UTC = case application:get_env(sasl, utc_log) of - {ok, Val} -> - Val; + {ok, Val} -> Val; undefined -> %% Backwards compatible: case application:get_env(stdlib, utc_log) of - {ok, Val} -> - Val; - undefined -> - false + {ok, Val} -> Val; + undefined -> false end end, - if - UTC =:= true -> - {utc, calendar:local_time_to_universal_time(Time)}; - true -> - Time - end. + maybe_utc(Time, UTC). + +maybe_utc(Time, true) -> {utc, Time}; +maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}. format_report(Rep) when is_list(Rep) -> case string_p(Rep) of @@ -238,7 +233,7 @@ write_time(Time) -> write_time(Time, "ERROR REPORT"). write_time({utc,{{Y,Mo,D},{H,Mi,S}}}, Type) -> io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n", [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]); -write_time({{Y,Mo,D},{H,Mi,S}}, Type) -> +write_time({local, {{Y,Mo,D},{H,Mi,S}}}, Type) -> io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s ===~n", [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]). diff --git a/lib/stdlib/src/error_logger_tty_h.erl b/lib/stdlib/src/error_logger_tty_h.erl index fa13fbb2bd..48e069a407 100644 --- a/lib/stdlib/src/error_logger_tty_h.erl +++ b/lib/stdlib/src/error_logger_tty_h.erl @@ -97,7 +97,7 @@ set_group_leader() -> end. tag_event(Event) -> - {erlang:localtime(), Event}. + {erlang:universaltime(), Event}. write_events(Events,IOMod) -> write_events1(lists:reverse(Events),IOMod). @@ -162,23 +162,18 @@ write_event({_Time, _Error},_IOMod) -> maybe_utc(Time) -> UTC = case application:get_env(sasl, utc_log) of - {ok, Val} -> - Val; + {ok, Val} -> Val; undefined -> %% Backwards compatible: case application:get_env(stdlib, utc_log) of - {ok, Val} -> - Val; - undefined -> - false + {ok, Val} -> Val; + undefined -> false end end, - if - UTC =:= true -> - {utc, calendar:local_time_to_universal_time(Time)}; - true -> - Time - end. + maybe_utc(Time, UTC). + +maybe_utc(Time, true) -> {utc, Time}; +maybe_utc(Time, _) -> {local, calendar:universal_time_to_local_time(Time)}. format(IOMod, String) -> format(IOMod, String, []). format(io_lib, String, Args) -> io_lib:format(String, Args); @@ -234,7 +229,7 @@ write_time(Time) -> write_time(Time, "ERROR REPORT"). write_time({utc,{{Y,Mo,D},{H,Mi,S}}},Type) -> io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s UTC ===~n", [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]); -write_time({{Y,Mo,D},{H,Mi,S}},Type) -> +write_time({local, {{Y,Mo,D},{H,Mi,S}}},Type) -> io_lib:format("~n=~s==== ~p-~s-~p::~s:~s:~s ===~n", [Type,D,month(Mo),Y,t(H),t(Mi),t(S)]). diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl index 57734a075c..80866c0806 100644 --- a/lib/stdlib/src/gen_fsm.erl +++ b/lib/stdlib/src/gen_fsm.erl @@ -320,7 +320,7 @@ name_to_pid(Name) -> undefined -> case global:whereis_name(Name) of undefined -> - exit(could_not_find_registerd_name); + exit(could_not_find_registered_name); Pid -> Pid end; diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl index af07bc988a..f720ec15f5 100644 --- a/lib/stdlib/src/gen_server.erl +++ b/lib/stdlib/src/gen_server.erl @@ -844,7 +844,7 @@ name_to_pid(Name) -> undefined -> case global:whereis_name(Name) of undefined -> - exit(could_not_find_registerd_name); + exit(could_not_find_registered_name); Pid -> Pid end; diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl index 63b397f3a5..4389fd457c 100644 --- a/lib/stdlib/src/ms_transform.erl +++ b/lib/stdlib/src/ms_transform.erl @@ -881,7 +881,6 @@ translate_language_element(Atom) -> end. old_bool_test(atom,1) -> is_atom; -old_bool_test(constant,1) -> is_constant; old_bool_test(float,1) -> is_float; old_bool_test(integer,1) -> is_integer; old_bool_test(list,1) -> is_list; @@ -896,7 +895,6 @@ old_bool_test(record,2) -> is_record; old_bool_test(_,_) -> undefined. bool_test(is_atom,1) -> true; -bool_test(is_constant,1) -> true; bool_test(is_float,1) -> true; bool_test(is_integer,1) -> true; bool_test(is_list,1) -> true; diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl index 7bacc05ff2..b9fbef9ed0 100644 --- a/lib/stdlib/src/otp_internal.erl +++ b/lib/stdlib/src/otp_internal.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% Copyright Ericsson AB 1999-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -337,11 +337,11 @@ obsolete_1(public_key, decode_private_key, A) when A =:= 1; A =:= 2 -> %% Added in R14B03. obsolete_1(docb_gen, _, _) -> - {deprecated,"the DocBuilder application is deprecated (will be removed in R15B)"}; + {removed,"the DocBuilder application was removed in R15B"}; obsolete_1(docb_transform, _, _) -> - {deprecated,"the DocBuilder application is deprecated (will be removed in R15B)"}; + {removed,"the DocBuilder application was removed in R15B"}; obsolete_1(docb_xml_check, _, _) -> - {deprecated,"the DocBuilder application is deprecated (will be removed in R15B)"}; + {removed,"the DocBuilder application was removed in R15B"}; %% Added in R15B obsolete_1(asn1rt, F, _) when F == load_driver; F == unload_driver -> @@ -350,10 +350,18 @@ obsolete_1(ssl, pid, 1) -> {deprecated,"deprecated (will be removed in R17); is no longer needed"}; obsolete_1(inviso, _, _) -> {deprecated,"the inviso application has been deprecated and will be removed in R16"}; + +%% Added in R15B01. +obsolete_1(gs, _, _) -> + {deprecated,"the gs application has been deprecated and will be removed in R16; use the wx application instead"}; +obsolete_1(ssh, sign_data, 2) -> + {deprecated,"deprecated (will be removed in R16A); use public_key:pem_decode/1, public_key:pem_entry_decode/1 " + "and public_key:sign/3 instead"}; +obsolete_1(ssh, verify_data, 3) -> + {deprecated,"deprecated (will be removed in R16A); use public_key:ssh_decode/1, and public_key:verify/4 instead"}; obsolete_1(_, _, _) -> no. - -spec is_snmp_agent_function(atom(), byte()) -> boolean(). is_snmp_agent_function(c, 1) -> true; diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl index 42ea42f42e..ac5b078c29 100644 --- a/lib/stdlib/src/supervisor.erl +++ b/lib/stdlib/src/supervisor.erl @@ -270,6 +270,8 @@ start_children(Children, SupName) -> start_children(Children, [], SupName). start_children([Child|Chs], NChildren, SupName) -> case do_start_child(SupName, Child) of + {ok, undefined} when Child#child.restart_type =:= temporary -> + start_children(Chs, NChildren, SupName); {ok, Pid} -> start_children(Chs, [Child#child{pid = Pid}|NChildren], SupName); {ok, Pid, _Extra} -> @@ -325,6 +327,8 @@ handle_call({start_child, EArgs}, _From, State) when ?is_simple(State) -> #child{mfargs = {M, F, A}} = Child, Args = A ++ EArgs, case do_start_child_i(M, F, Args) of + {ok, undefined} when Child#child.restart_type =:= temporary -> + {reply, {ok, undefined}, State}; {ok, Pid} -> NState = save_dynamic_child(Child#child.restart_type, Pid, Args, State), {reply, {ok, Pid}, NState}; @@ -611,12 +615,12 @@ handle_start_child(Child, State) -> case get_child(Child#child.name, State) of false -> case do_start_child(State#state.name, Child) of + {ok, undefined} when Child#child.restart_type =:= temporary -> + {{ok, undefined}, State}; {ok, Pid} -> - {{ok, Pid}, - save_child(Child#child{pid = Pid}, State)}; + {{ok, Pid}, save_child(Child#child{pid = Pid}, State)}; {ok, Pid, Extra} -> - {{ok, Pid, Extra}, - save_child(Child#child{pid = Pid}, State)}; + {{ok, Pid, Extra}, save_child(Child#child{pid = Pid}, State)}; {error, What} -> {{error, {What, Child}}, State} end; diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl index 369d8b224e..ca2f18a05a 100644 --- a/lib/stdlib/test/erl_eval_SUITE.erl +++ b/lib/stdlib/test/erl_eval_SUITE.erl @@ -1167,15 +1167,22 @@ do_funs(LFH, EFH) -> [[[0]]], ['F'], LFH, EFH), %% Tests for a bug found by the Dialyzer - used to crash. - ?line check(fun() -> Pmod = erl_eval_helper:new(42), Pmod:add(5) end, - "begin Pmod = erl_eval_helper:new(42), Pmod:add(5) end.", - 47, - ['Pmod'], LFH, EFH), - ?line check(fun() -> Pmod = erl_eval_helper:new(42), B = Pmod:add(7), B end, - "begin Pmod = erl_eval_helper:new(42), B = Pmod:add(7), B end.", - 49, - ['B','Pmod'], LFH, EFH), - + case test_server:is_native(erl_eval) of + true -> + %% Parameterized modules are not supported by HiPE. + ok; + false -> + check(fun() -> Pmod = erl_eval_helper:new(42), Pmod:add(5) end, + "begin Pmod = erl_eval_helper:new(42), Pmod:add(5) end.", + 47, + ['Pmod'], LFH, EFH), + check(fun() -> Pmod = erl_eval_helper:new(42), + B = Pmod:add(7), B end, + "begin Pmod = erl_eval_helper:new(42), " + "B = Pmod:add(7), B end.", + 49, + ['B','Pmod'], LFH, EFH) + end, ok. count_down(F, N) when N > 0 -> diff --git a/lib/stdlib/test/erl_expand_records_SUITE.erl b/lib/stdlib/test/erl_expand_records_SUITE.erl index f8c1ad783c..8b162cfda0 100644 --- a/lib/stdlib/test/erl_expand_records_SUITE.erl +++ b/lib/stdlib/test/erl_expand_records_SUITE.erl @@ -178,6 +178,9 @@ expr(Config) when is_list(Config) -> true -> not_ok end. + + is_record(_, _, _) -> + error(wrong_is_record). ">> ], @@ -366,6 +369,8 @@ strict(Config) when is_list(Config) -> end catch error:_ -> ok end. + element(_, _) -> + error(wrong_element). ">> ], ?line run(Config, Ts1, [strict_record_tests]), @@ -380,6 +385,8 @@ strict(Config) when is_list(Config) -> case foo of _ when A#r2.a =:= 1 -> ok end. + element(_, _) -> + error(wrong_element). ">> ], ?line run(Config, Ts2, [no_strict_record_tests]), @@ -415,6 +422,11 @@ update(Config) when is_list(Config) -> t2() -> R0 = #r{}, #r{_ = R0#r{a = ok}}. + + %% Implicit calls to setelement/3 must go to the BIF, + %% not to this function. + setelement(_, _, _) -> + erlang:error(wrong_setelement_called). ">> ], ?line run(Config, Ts), diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl index 9041adbe5c..4e93f056ad 100644 --- a/lib/stdlib/test/erl_lint_SUITE.erl +++ b/lib/stdlib/test/erl_lint_SUITE.erl @@ -2631,7 +2631,35 @@ bif_clash(Config) when is_list(Config) -> binary_part(A,B,C). ">>, [warn_unused_import], - {warnings,[{2,erl_lint,{redefine_bif_import,{binary_part,3}}}]}} + {warnings,[{2,erl_lint,{redefine_bif_import,{binary_part,3}}}]}}, + %% Don't accept call to a guard BIF if there is a local definition + %% or an import with the same name. Note: is_record/2 is an + %% exception, since it is more of syntatic sugar than a real BIF. + {clash21, + <<"-export([is_list/1]). + -import(x, [is_tuple/1]). + -record(r, {a,b}). + x(T) when is_tuple(T) -> ok; + x(T) when is_list(T) -> ok. + y(T) when is_tuple(T) =:= true -> ok; + y(T) when is_list(T) =:= true -> ok; + y(T) when is_record(T, r, 3) -> ok; + y(T) when is_record(T, r, 3) =:= true -> ok; + y(T) when is_record(T, r) =:= true -> ok. + is_list(_) -> + ok. + is_record(_, _) -> + ok. + is_record(_, _, _) -> + ok. + ">>, + [{no_auto_import,[{is_tuple,1}]}], + {errors,[{4,erl_lint,{illegal_guard_local_call,{is_tuple,1}}}, + {5,erl_lint,{illegal_guard_local_call,{is_list,1}}}, + {6,erl_lint,{illegal_guard_local_call,{is_tuple,1}}}, + {7,erl_lint,{illegal_guard_local_call,{is_list,1}}}, + {8,erl_lint,{illegal_guard_local_call,{is_record,3}}}, + {9,erl_lint,{illegal_guard_local_call,{is_record,3}}}],[]}} ], ?line [] = run(Config, Ts), diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl index 0e8849b5b3..101828fdef 100644 --- a/lib/stdlib/test/ets_SUITE.erl +++ b/lib/stdlib/test/ets_SUITE.erl @@ -74,7 +74,7 @@ -export([bad_table/1, types/1]). -export([otp_9423/1]). --export([init_per_testcase/2]). +-export([init_per_testcase/2, end_per_testcase/2]). %% Convenience for manual testing -export([random_test/0]). @@ -2385,6 +2385,8 @@ setopts_do(Opts) -> ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,{protection,private,false})), ?line {'EXIT',{badarg,_}} = (catch ets:setopts(T,protection)), ?line ets:delete(T), + unlink(Heir), + exit(Heir, bang), ok. bad_table(doc) -> ["All kinds of operations with bad table argument"]; @@ -5645,7 +5647,8 @@ spawn_logger(Procs) -> true -> exit(Proc, kill); _ -> ok end, - erlang:display(process_info(Proc)), + erlang:display({"Waiting for 'DOWN' from", Proc, + process_info(Proc), pid_status(Proc)}), receive {'DOWN', Mon, _, _, _} -> ok @@ -5656,6 +5659,15 @@ spawn_logger(Procs) -> spawn_logger([From]) end. +pid_status(Pid) -> + try + erts_debug:get_internal_state({process_status, Pid}) + catch + error:undef -> + erts_debug:set_internal_state(available_internal_state, true), + pid_status(Pid) + end. + start_spawn_logger() -> case whereis(ets_test_spawn_logger) of Pid when is_pid(Pid) -> true; diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl index c9688354b1..a17307b07b 100644 --- a/lib/stdlib/test/ms_transform_SUITE.erl +++ b/lib/stdlib/test/ms_transform_SUITE.erl @@ -455,7 +455,6 @@ old_guards(Config) when is_list(Config) -> ?line setup(Config), Tests = [ {atom,is_atom}, - {constant,is_constant}, {float,is_float}, {integer,is_integer}, {list,is_list}, @@ -490,7 +489,6 @@ old_guards(Config) when is_list(Config) -> ?line [{'$1',[{is_integer,'$1'}, {is_float,'$1'}, {is_atom,'$1'}, - {is_constant,'$1'}, {is_list,'$1'}, {is_number,'$1'}, {is_pid,'$1'}, @@ -502,7 +500,7 @@ old_guards(Config) when is_list(Config) -> [true]}] = compile_and_run(RD, << "ets:fun2ms(fun(X) when integer(X)," - "float(X), atom(X), constant(X)," + "float(X), atom(X)," "list(X), number(X), pid(X)," "port(X), reference(X), tuple(X)," "binary(X), record(X,a) -> true end)" @@ -530,7 +528,6 @@ autoimported(Config) when is_list(Config) -> {self,0}, %{float,1}, see float_1_function/1 {is_atom,1}, - {is_constant,1}, {is_float,1}, {is_integer,1}, {is_list,1}, diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl index 3b2e637c84..d6d946a28f 100644 --- a/lib/stdlib/test/re_SUITE.erl +++ b/lib/stdlib/test/re_SUITE.erl @@ -445,9 +445,17 @@ split_specials(Config) when is_list(Config) -> ok. -error_handling(doc) -> - ["Test that errors are handled correctly by the erlang code."]; -error_handling(Config) when is_list(Config) -> +%% Test that errors are handled correctly by the erlang code. +error_handling(_Config) -> + case test_server:is_native(re) of + true -> + %% Exceptions from native code look too different. + {skip,"re is native"}; + false -> + error_handling() + end. + +error_handling() -> % This test checks the exception tuples manufactured in the erlang % code to hide the trapping from the user at least when it comes to errors Dog = ?t:timetrap(?t:minutes(1)), @@ -455,14 +463,14 @@ error_handling(Config) when is_list(Config) -> % the trap to re:grun from grun, in the grun function clause % that handles precompiled expressions ?line {'EXIT',{badarg,[{re,run,["apa",{1,2,3,4},[global]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:run("apa",{1,2,3,4},[global])), % An invalid capture list will also cause a badarg late, % but with a non pre compiled RE, the exception should be thrown by the % grun function clause that handles RE's compiled implicitly by % the run/3 BIF before trapping. ?line {'EXIT',{badarg,[{re,run,["apa","p",[{capture,[1,{a}]},global]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:run("apa","p",[{capture,[1,{a}]},global])), % And so the case of a precompiled expression together with % a compile-option (binary and list subject): @@ -473,88 +481,88 @@ error_handling(Config) when is_list(Config) -> [<<"apa">>, {re_pattern,1,0,_}, [global,unicode]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:run(<<"apa">>,RE,[global,unicode])), ?line {'EXIT',{badarg,[{re,run, ["apa", {re_pattern,1,0,_}, [global,unicode]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:run("apa",RE,[global,unicode])), ?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[])), ?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[global])), % The replace errors: ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:replace("apa",{1,2,3,4},"X",[])), ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[global]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:replace("apa",{1,2,3,4},"X",[global])), ?line {'EXIT',{badarg,[{re,replace, ["apa", {re_pattern,1,0,_}, "X", [unicode]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:replace("apa",RE,"X",[unicode])), ?line <<"aXa">> = iolist_to_binary(re:replace("apa","p","X",[])), ?line {'EXIT',{badarg,[{re,replace, ["apa","p","X",[{capture,all,binary}]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch iolist_to_binary(re:replace("apa","p","X", [{capture,all,binary}]))), ?line {'EXIT',{badarg,[{re,replace, ["apa","p","X",[{capture,all}]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch iolist_to_binary(re:replace("apa","p","X", [{capture,all}]))), ?line {'EXIT',{badarg,[{re,replace, ["apa","p","X",[{return,banana}]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch iolist_to_binary(re:replace("apa","p","X", [{return,banana}]))), ?line {'EXIT',{badarg,_}} = (catch re:replace("apa","(p","X",[])), % Badarg, not compile error. ?line {'EXIT',{badarg,[{re,replace, ["apa","(p","X",[{return,banana}]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch iolist_to_binary(re:replace("apa","(p","X", [{return,banana}]))), % And the split errors: ?line [<<"a">>,<<"a">>] = (catch re:split("apa","p",[])), ?line [<<"a">>,<<"p">>,<<"a">>] = (catch re:split("apa",RE,[])), ?line {'EXIT',{badarg,[{re,split,["apa","p",[global]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa","p",[global])), ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all}]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa","p",[{capture,all}])), ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all,binary}]],_}, - {?MODULE, error_handling,1,_} | _]}} = + {?MODULE, error_handling,0,_} | _]}} = (catch re:split("apa","p",[{capture,all,binary}])), ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa",{1,2,3,4})), ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa",{1,2,3,4},[])), ?line {'EXIT',{badarg,[{re,split, ["apa", RE, [unicode]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa",RE,[unicode])), ?line {'EXIT',{badarg,[{re,split, ["apa", RE, [{return,banana}]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa",RE,[{return,banana}])), ?line {'EXIT',{badarg,[{re,split, ["apa", RE, [banana]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa",RE,[banana])), ?line {'EXIT',{badarg,_}} = (catch re:split("apa","(p")), %Exception on bad argument, not compilation error @@ -562,7 +570,7 @@ error_handling(Config) when is_list(Config) -> ["apa", "(p", [banana]],_}, - {?MODULE,error_handling,1,_} | _]}} = + {?MODULE,error_handling,0,_} | _]}} = (catch re:split("apa","(p",[banana])), ?t:timetrap_cancel(Dog), ok. diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl index b6019b86f0..a881742f13 100644 --- a/lib/stdlib/test/shell_SUITE.erl +++ b/lib/stdlib/test/shell_SUITE.erl @@ -2388,13 +2388,28 @@ otp_6554(Config) when is_list(Config) -> comm_err(<<"V = lists:seq(1, 20), case V of a -> ok end.">>), ?line "exception error: no function clause matching" = comm_err(<<"fun(P) when is_pid(P) -> true end(a).">>), - ?line "exception error: {function_clause," = - comm_err(<<"erlang:error(function_clause, [unproper | list]).">>), + case test_server:is_native(erl_eval) of + true -> + %% Native code has different exit reason. Don't bother + %% testing them. + ok; + false -> + "exception error: {function_clause," = + comm_err(<<"erlang:error(function_clause, " + "[unproper | list]).">>), + %% Cheating: + "exception error: no function clause matching " + "erl_eval:do_apply(4)" ++ _ = + comm_err(<<"erlang:error(function_clause, [4]).">>), + "exception error: no function clause matching " + "lists:reverse(" ++ _ = + comm_err(<<"F=fun() -> hello end, lists:reverse(F).">>), + "exception error: no function clause matching " + "lists:reverse(34) (lists.erl, line " ++ _ = + comm_err(<<"lists:reverse(34).">>) + end, ?line "exception error: function_clause" = comm_err(<<"erlang:error(function_clause, 4).">>), - %% Cheating: - ?line "exception error: no function clause matching erl_eval:do_apply(4)" ++ _ = - comm_err(<<"erlang:error(function_clause, [4]).">>), ?line "exception error: no function clause matching" ++ _ = comm_err(<<"fun(a, b, c, d) -> foo end" " (lists:seq(1,17)," @@ -2404,10 +2419,6 @@ otp_6554(Config) when is_list(Config) -> ?line "exception error: no function clause matching" = comm_err(<<"fun(P, q) when is_pid(P) -> true end(a, b).">>), - ?line "exception error: no function clause matching lists:reverse(" ++ _ = - comm_err(<<"F=fun() -> hello end, lists:reverse(F).">>), - ?line "exception error: no function clause matching lists:reverse(34) (lists.erl, line " ++ _ = - comm_err(<<"lists:reverse(34).">>), ?line "exception error: no true branch found when evaluating an if expression" = comm_err(<<"if length([a,b]) > 17 -> a end.">>), ?line "exception error: no such process or port" = diff --git a/lib/stdlib/test/sofs_SUITE.erl b/lib/stdlib/test/sofs_SUITE.erl index 73b282149a..f11c6ec4d6 100644 --- a/lib/stdlib/test/sofs_SUITE.erl +++ b/lib/stdlib/test/sofs_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2011. All Rights Reserved. +%% Copyright Ericsson AB 2001-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -536,7 +536,7 @@ projection(Conf) when is_list(Conf) -> from_term([], [[atom]]))), ?line {'EXIT', {badarg, _}} = (catch projection({external, fun(X) -> X end}, from_term([[a]]))), - ?line eval(projection({sofs,union}, + ?line eval(projection(fun sofs:union/1, from_term([[[1,2],[2,3]], [[a,b],[b,c]]])), from_term([[1,2,3], [a,b,c]])), ?line eval(projection(fun(_) -> from_term([a]) end, @@ -628,7 +628,7 @@ substitution(Conf) when is_list(Conf) -> ?line {'EXIT', {badarg, _}} = (catch substitution({external, fun(X) -> X end}, from_term([[a]]))), ?line eval(substitution(fun(X) -> X end, from_term([], [[atom]])), E), - ?line eval(substitution({sofs,union}, + ?line eval(substitution(fun sofs:union/1, from_term([[[1,2],[2,3]], [[a,b],[b,c]]])), from_term([{[[1,2],[2,3]],[1,2,3]}, {[[a,b],[b,c]],[a,b,c]}])), ?line eval(substitution(fun(_) -> from_term([a]) end, @@ -745,7 +745,7 @@ restriction(Conf) when is_list(Conf) -> ?line eval(restriction(Id, S3, E), E), ?line eval(restriction(Id, from_term([], [[atom]]), set([a])), from_term([], [[atom]])), - ?line eval(restriction({sofs,union}, + ?line eval(restriction(fun sofs:union/1, from_term([[[a],[b]], [[b],[c]], [[], [a,b]], [[1],[2]]]), from_term([[a,b],[1,2,3],[b,c]])), @@ -862,7 +862,7 @@ drestriction(Conf) when is_list(Conf) -> ?line eval(drestriction(Id, S3, E), S3), ?line eval(drestriction(Id, from_term([], [[atom]]), set([a])), from_term([], [[atom]])), - ?line eval(drestriction({sofs,union}, + ?line eval(drestriction(fun sofs:union/1, from_term([[[a],[b]], [[b],[c]], [[], [a,b]], [[1],[2]]]), from_term([[a,b],[1,2,3],[b,c]])), @@ -1028,7 +1028,7 @@ specification(Conf) when is_list(Conf) -> end, ?line eval(specification({external,Fun2x}, S2), from_term([[1],[3]])), - Fun3 = fun(_) -> neither_true_or_false end, + Fun3 = fun(_) -> neither_true_nor_false end, ?line {'EXIT', {badarg, _}} = (catch specification(Fun3, set([a]))), ?line {'EXIT', {badarg, _}} = @@ -1810,8 +1810,8 @@ partition_3(Conf) when is_list(Conf) -> S12a = from_term([[[a],[b]], [[b],[c]], [[], [a,b]], [[1],[2]]]), S12b = from_term([[a,b],[1,2,3],[b,c]]), - ?line eval(partition({sofs,union}, S12a, S12b), - lpartition({sofs,union}, S12a, S12b)), + ?line eval(partition(fun sofs:union/1, S12a, S12b), + lpartition(fun sofs:union/1, S12a, S12b)), Fun13 = fun(_) -> from_term([a]) end, S13a = from_term([], [[atom]]), @@ -1879,12 +1879,9 @@ digraph(Conf) when is_list(Conf) -> ?line {'EXIT', {badarg, _}} = (catch family_to_digraph(set([a]))), - ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_],_}|_]}} = - (catch family_to_digraph(set([a]), [foo])), - ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_],_}|_]}} = - (catch family_to_digraph(F, [foo])), - ?line {'EXIT', {cyclic, [{sofs,family_to_digraph,[_,_],_}|_]}} = - (catch family_to_digraph(family([{a,[a]}]),[acyclic])), + digraph_fail(badarg, catch family_to_digraph(set([a]), [foo])), + digraph_fail(badarg, catch family_to_digraph(F, [foo])), + digraph_fail(cyclic, catch family_to_digraph(family([{a,[a]}]),[acyclic])), ?line G1 = family_to_digraph(E), ?line {'EXIT', {badarg, _}} = (catch digraph_to_family(G1, foo)), @@ -1927,6 +1924,13 @@ digraph(Conf) when is_list(Conf) -> ?line true = T0 == ets:all(), ok. +digraph_fail(ExitReason, Fail) -> + {'EXIT', {ExitReason, [{sofs,family_to_digraph,A,_}|_]}} = Fail, + case {test_server:is_native(sofs),A} of + {false,[_,_]} -> ok; + {true,2} -> ok + end. + constant_function(suite) -> []; constant_function(doc) -> [""]; constant_function(Conf) when is_list(Conf) -> @@ -1952,10 +1956,8 @@ misc(Conf) when is_list(Conf) -> % the "functional" part: ?line eval(union(intersection(partition(1,S), partition(Id,S))), difference(S, RR)), - - %% The function external:foo/1 is undefined. ?line {'EXIT', {undef, _}} = - (catch projection({external,foo}, set([a,b,c]))), + (catch projection(fun external:foo/1, set([a,b,c]))), ok. relational_restriction(R) -> @@ -1968,19 +1970,19 @@ family_specification(doc) -> [""]; family_specification(Conf) when is_list(Conf) -> E = empty_set(), %% internal - ?line eval(family_specification({sofs, is_set}, E), E), + ?line eval(family_specification(fun sofs:is_set/1, E), E), ?line {'EXIT', {badarg, _}} = - (catch family_specification({sofs,is_set}, set([]))), + (catch family_specification(fun sofs:is_set/1, set([]))), ?line F1 = from_term([{1,[1]}]), - ?line eval(family_specification({sofs,is_set}, F1), F1), + ?line eval(family_specification(fun sofs:is_set/1, F1), F1), Fun = fun(S) -> is_subset(S, set([0,1,2,3,4])) end, ?line F2 = family([{a,[1,2]},{b,[3,4,5]}]), ?line eval(family_specification(Fun, F2), family([{a,[1,2]}])), ?line F3 = from_term([{a,[]},{b,[]}]), - ?line eval(family_specification({sofs,is_set}, F3), F3), + ?line eval(family_specification(fun sofs:is_set/1, F3), F3), Fun2 = fun(_) -> throw(fippla) end, ?line fippla = (catch family_specification(Fun2, family([{a,[1]}]))), - Fun3 = fun(_) -> neither_true_or_false end, + Fun3 = fun(_) -> neither_true_nor_false end, ?line {'EXIT', {badarg, _}} = (catch family_specification(Fun3, F3)), @@ -2095,22 +2097,22 @@ family_projection(Conf) when is_list(Conf) -> ?line eval(family_projection(fun(X) -> X end, family([])), E), ?line L1 = [{a,[]}], - ?line eval(family_projection({sofs,union}, E), E), - ?line eval(family_projection({sofs,union}, from_term(L1, SSType)), + ?line eval(family_projection(fun sofs:union/1, E), E), + ?line eval(family_projection(fun sofs:union/1, from_term(L1, SSType)), family(L1)), ?line {'EXIT', {badarg, _}} = - (catch family_projection({sofs,union}, set([]))), + (catch family_projection(fun sofs:union/1, set([]))), ?line {'EXIT', {badarg, _}} = - (catch family_projection({sofs,union}, from_term([{1,[1]}]))), + (catch family_projection(fun sofs:union/1, from_term([{1,[1]}]))), ?line F2 = from_term([{a,[[1],[2]]},{b,[[3,4],[5]]}], SSType), - ?line eval(family_projection({sofs,union}, F2), + ?line eval(family_projection(fun sofs:union/1, F2), family_union(F2)), ?line F3 = from_term([{1,[{a,b},{b,c},{c,d}]},{3,[]},{5,[{3,5}]}], SRType), - ?line eval(family_projection({sofs,domain}, F3), family_domain(F3)), - ?line eval(family_projection({sofs,range}, F3), family_range(F3)), + ?line eval(family_projection(fun sofs:domain/1, F3), family_domain(F3)), + ?line eval(family_projection(fun sofs:range/1, F3), family_range(F3)), ?line eval(family_projection(fun(_) -> E end, family([{a,[b,c]}])), from_term([{a,[]}])), @@ -2290,7 +2292,7 @@ partition_family(Conf) when is_list(Conf) -> ?line eval(partition_family(1, E), E), ?line eval(partition_family(2, E), E), - ?line eval(partition_family({sofs,union}, E), E), + ?line eval(partition_family(fun sofs:union/1, E), E), ?line eval(partition_family(1, ER), EF), ?line eval(partition_family(2, ER), EF), ?line {'EXIT', {badarg, _}} = (catch partition_family(1, set([]))), @@ -2354,7 +2356,7 @@ partition_family(Conf) when is_list(Conf) -> ?line {'EXIT', {badarg, _}} = (catch partition_family({external, fun(X) -> X end}, from_term([[a]]))), - ?line eval(partition_family({sofs,union}, + ?line eval(partition_family(fun sofs:union/1, from_term([[[1],[1,2]], [[1,2]]])), from_term([{[1,2], [[[1],[1,2]],[[1,2]]]}])), ?line eval(partition_family(fun(X) -> X end, diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl index fa6faa66f2..71b76c093f 100644 --- a/lib/stdlib/test/supervisor_SUITE.erl +++ b/lib/stdlib/test/supervisor_SUITE.erl @@ -34,8 +34,10 @@ %% API tests -export([ sup_start_normal/1, sup_start_ignore_init/1, - sup_start_ignore_child/1, sup_start_error_return/1, - sup_start_fail/1, sup_stop_infinity/1, + sup_start_ignore_child/1, sup_start_ignore_temporary_child/1, + sup_start_ignore_temporary_child_start_child/1, + sup_start_ignore_temporary_child_start_child_simple/1, + sup_start_error_return/1, sup_start_fail/1, sup_stop_infinity/1, sup_stop_timeout/1, sup_stop_brutal_kill/1, child_adm/1, child_adm_simple/1, child_specs/1, extra_return/1]). @@ -85,8 +87,10 @@ all() -> groups() -> [{sup_start, [], [sup_start_normal, sup_start_ignore_init, - sup_start_ignore_child, sup_start_error_return, - sup_start_fail]}, + sup_start_ignore_child, sup_start_ignore_temporary_child, + sup_start_ignore_temporary_child_start_child, + sup_start_ignore_temporary_child_start_child_simple, + sup_start_error_return, sup_start_fail]}, {sup_stop, [], [sup_stop_infinity, sup_stop_timeout, sup_stop_brutal_kill]}, @@ -191,6 +195,59 @@ sup_start_ignore_child(Config) when is_list(Config) -> [2,1,0,2] = get_child_counts(sup_test). %%------------------------------------------------------------------------- +%% Tests what happens if child's init-callback returns ignore for a +%% temporary child when ChildSpec is returned directly from supervisor +%% init callback. +%% Child spec shall NOT be saved!!! +sup_start_ignore_temporary_child(Config) when is_list(Config) -> + process_flag(trap_exit, true), + Child1 = {child1, {supervisor_1, start_child, [ignore]}, + temporary, 1000, worker, []}, + Child2 = {child2, {supervisor_1, start_child, []}, temporary, + 1000, worker, []}, + {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, [Child1,Child2]}}), + + [{child2, CPid2, worker, []}] = supervisor:which_children(sup_test), + true = is_pid(CPid2), + [1,1,0,1] = get_child_counts(sup_test). + +%%------------------------------------------------------------------------- +%% Tests what happens if child's init-callback returns ignore for a +%% temporary child when child is started with start_child/2. +%% Child spec shall NOT be saved!!! +sup_start_ignore_temporary_child_start_child(Config) when is_list(Config) -> + process_flag(trap_exit, true), + {ok, _Pid} = start_link({ok, {{one_for_one, 2, 3600}, []}}), + Child1 = {child1, {supervisor_1, start_child, [ignore]}, + temporary, 1000, worker, []}, + Child2 = {child2, {supervisor_1, start_child, []}, temporary, + 1000, worker, []}, + + {ok, undefined} = supervisor:start_child(sup_test, Child1), + {ok, CPid2} = supervisor:start_child(sup_test, Child2), + + [{child2, CPid2, worker, []}] = supervisor:which_children(sup_test), + [1,1,0,1] = get_child_counts(sup_test). + +%%------------------------------------------------------------------------- +%% Tests what happens if child's init-callback returns ignore for a +%% temporary child when child is started with start_child/2, and the +%% supervisor is simple_one_for_one. +%% Child spec shall NOT be saved!!! +sup_start_ignore_temporary_child_start_child_simple(Config) + when is_list(Config) -> + process_flag(trap_exit, true), + Child1 = {child1, {supervisor_1, start_child, [ignore]}, + temporary, 1000, worker, []}, + {ok, _Pid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child1]}}), + + {ok, undefined} = supervisor:start_child(sup_test, []), + {ok, CPid2} = supervisor:start_child(sup_test, []), + + [{undefined, CPid2, worker, []}] = supervisor:which_children(sup_test), + [1,1,0,1] = get_child_counts(sup_test). + +%%------------------------------------------------------------------------- %% Tests what happens if init-callback returns a invalid value. sup_start_error_return(Config) when is_list(Config) -> process_flag(trap_exit, true), diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk index 2f0ecd3863..694d39ce9c 100644 --- a/lib/stdlib/vsn.mk +++ b/lib/stdlib/vsn.mk @@ -1 +1 @@ -STDLIB_VSN = 1.18 +STDLIB_VSN = 1.18.1 diff --git a/lib/syntax_tools/doc/src/notes.xml b/lib/syntax_tools/doc/src/notes.xml index 5948f7ada3..b9ac587043 100644 --- a/lib/syntax_tools/doc/src/notes.xml +++ b/lib/syntax_tools/doc/src/notes.xml @@ -31,6 +31,38 @@ <p>This document describes the changes made to the Syntax_Tools application.</p> +<section><title>Syntax_Tools 1.6.7.2</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Variables are now now allowed in '<c>fun M:F/A</c>' as + suggested by Richard O'Keefe in EEP-23.</p> + <p>The representation of '<c>fun M:F/A</c>' in the + abstract format has been changed in an incompatible way. + Tools that directly read or manipulate the abstract + format (such as parse transforms) may need to be updated. + The compiler can handle both the new and the old format + (i.e. extracting the abstract format from a pre-R15 BEAM + file and compiling it using compile:forms/1,2 will work). + The <c>syntax_tools</c> application can also handle both + formats.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9643</p> + </item> + <item> + <p> + Eliminate use of deprecated regexp module</p> + <p> + Own Id: OTP-9810</p> + </item> + </list> + </section> + +</section> + <section><title>Syntax_Tools 1.6.7.1</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/syntax_tools/src/Makefile b/lib/syntax_tools/src/Makefile index 50369e633e..bac138e95a 100644 --- a/lib/syntax_tools/src/Makefile +++ b/lib/syntax_tools/src/Makefile @@ -26,7 +26,7 @@ EBIN = ../ebin ifeq ($(NATIVE_LIBS_ENABLED),yes) ERL_COMPILE_FLAGS += +native endif -ERL_COMPILE_FLAGS += +warn_unused_vars +nowarn_shadow_vars +warn_unused_import +warn_missing_spec +warn_untyped_record +ERL_COMPILE_FLAGS += +warn_unused_vars +nowarn_shadow_vars +warn_unused_import # +warn_missing_spec +warn_untyped_record SOURCES=erl_syntax.erl erl_prettypr.erl erl_syntax_lib.erl \ erl_comment_scan.erl erl_recomment.erl erl_tidy.erl \ diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl index 7f58fda519..32fd3722d6 100644 --- a/lib/syntax_tools/src/erl_syntax.erl +++ b/lib/syntax_tools/src/erl_syntax.erl @@ -6100,8 +6100,9 @@ implicit_fun_name(Node) -> arity_qualifier( set_pos(atom(Atom), Pos), set_pos(integer(Arity), Pos))); - {'fun', Pos, {function, Module, Atom, Arity}} -> + {'fun', _Pos, {function, Module, Atom, Arity}} -> %% New in R15: fun M:F/A. + %% XXX: Perhaps set position for this as well? module_qualifier(Module, arity_qualifier(Atom, Arity)); Node1 -> data(Node1) diff --git a/lib/syntax_tools/vsn.mk b/lib/syntax_tools/vsn.mk index cc7ea944f9..962492befd 100644 --- a/lib/syntax_tools/vsn.mk +++ b/lib/syntax_tools/vsn.mk @@ -1 +1 @@ -SYNTAX_TOOLS_VSN = 1.6.7.1 +SYNTAX_TOOLS_VSN = 1.6.7.2 diff --git a/lib/test_server/doc/src/notes.xml b/lib/test_server/doc/src/notes.xml index beeff55ffe..d90ad2c4ed 100644 --- a/lib/test_server/doc/src/notes.xml +++ b/lib/test_server/doc/src/notes.xml @@ -32,6 +32,49 @@ <file>notes.xml</file> </header> +<section><title>Test_Server 3.5</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + The test case group info function has been implemented in + Common Test. Before execution of a test case group, a + call is now made to <c>TestSuite:group(GroupName)</c>. + The function returns a list of test properties, e.g. to + specify timetrap values, require configuration data, etc + (analogue to the test suite- and test case info + function). The scope of the properties set by + <c>group(GroupName)</c> is all test cases and sub-groups + of group <c>GroupName</c>.</p> + <p> + Own Id: OTP-9235</p> + </item> + <item> + <p> + The look of the HTML log files generated by Common Test + and Test Server has been improved (and made easier to + customize) by means of a CSS file.</p> + <p> + Own Id: OTP-9706</p> + </item> + </list> + </section> + + + <section><title>Known Bugs and Problems</title> + <list> + <item> + <p> + Fix problems in CT/TS due to line numbers in exceptions.</p> + <p> + Own Id: OTP-9203</p> + </item> + </list> + </section> + +</section> + <section><title>Test_Server 3.4.5</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/toolbar/doc/src/notes.xml b/lib/toolbar/doc/src/notes.xml index 306309db1d..ac6ad533fc 100644 --- a/lib/toolbar/doc/src/notes.xml +++ b/lib/toolbar/doc/src/notes.xml @@ -31,6 +31,21 @@ <p>This document describes the changes made to the Toolbar application.</p> +<section><title>Toolbar 1.4.2.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Miscellaneous documentation build updates</p> + <p> + Own Id: OTP-9813</p> + </item> + </list> + </section> + +</section> + <section><title>Toolbar 1.4.2</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/toolbar/doc/src/toolbar.xml b/lib/toolbar/doc/src/toolbar.xml index ad379438fe..3ad0b4eb78 100644 --- a/lib/toolbar/doc/src/toolbar.xml +++ b/lib/toolbar/doc/src/toolbar.xml @@ -33,6 +33,11 @@ <module>toolbar</module> <modulesummary>GUI for Starting Tools and User Contributions</modulesummary> <description> + <warning> + <p> + The Toolbar application is deprecated and will be removed in R16. + </p> + </warning> <p>Toolbar makes it easier to use the different Erlang tools - and the user contributions - which are provided. It has a graphical user interface with an icon for each tool. diff --git a/lib/toolbar/doc/src/toolbar_chapter.xml b/lib/toolbar/doc/src/toolbar_chapter.xml index a80dc5bd3e..4ea2101218 100644 --- a/lib/toolbar/doc/src/toolbar_chapter.xml +++ b/lib/toolbar/doc/src/toolbar_chapter.xml @@ -28,6 +28,11 @@ <rev>A</rev> <file>toolbar_chapter.xml</file> </header> + <warning> + <p> + The Toolbar application is deprecated and will be removed in R16. + </p> + </warning> <p>Toolbar provides an interface to the various Erlang tools which are available. Toolbar can also provide access to user supplied tools which are included with the Erlang software release. These tools are called GS Contributions.</p> <p>All tools included in Toolbar must have a configuration file which contains information about the tool, such as its start function and the location of help information. The name of a configuration file must include the suffix <c>.tool</c>. </p> diff --git a/lib/toolbar/src/canvasbutton.erl b/lib/toolbar/src/canvasbutton.erl index 38fce537bb..7613253efe 100644 --- a/lib/toolbar/src/canvasbutton.erl +++ b/lib/toolbar/src/canvasbutton.erl @@ -17,6 +17,9 @@ %% %CopyrightEnd% %% -module(canvasbutton). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,read,2}}]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % diff --git a/lib/toolbar/src/toolbar.erl b/lib/toolbar/src/toolbar.erl index 67967172fe..b78df15700 100644 --- a/lib/toolbar/src/toolbar.erl +++ b/lib/toolbar/src/toolbar.erl @@ -17,6 +17,7 @@ %% %CopyrightEnd% %% -module(toolbar). +-compile([{nowarn_deprecated_function,{gs,start,1}}]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % diff --git a/lib/toolbar/src/toolbar_graphics.erl b/lib/toolbar/src/toolbar_graphics.erl index ad390440e3..b442d7ff06 100644 --- a/lib/toolbar/src/toolbar_graphics.erl +++ b/lib/toolbar/src/toolbar_graphics.erl @@ -17,6 +17,9 @@ %% %CopyrightEnd% %% -module(toolbar_graphics). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,read,2}}]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % diff --git a/lib/toolbar/src/toolbar_toolconfig.erl b/lib/toolbar/src/toolbar_toolconfig.erl index 6dccb7ba72..6fb56cb1bd 100644 --- a/lib/toolbar/src/toolbar_toolconfig.erl +++ b/lib/toolbar/src/toolbar_toolconfig.erl @@ -17,6 +17,11 @@ %% %CopyrightEnd% %% -module(toolbar_toolconfig). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % diff --git a/lib/toolbar/vsn.mk b/lib/toolbar/vsn.mk index 105303d785..b2b0764877 100644 --- a/lib/toolbar/vsn.mk +++ b/lib/toolbar/vsn.mk @@ -1,4 +1,4 @@ -TOOLBAR_VSN = 1.4.2 +TOOLBAR_VSN = 1.4.2.1 diff --git a/lib/tools/c_src/Makefile.in b/lib/tools/c_src/Makefile.in index 604332a91e..b8c4aed6e2 100644 --- a/lib/tools/c_src/Makefile.in +++ b/lib/tools/c_src/Makefile.in @@ -1,19 +1,20 @@ -# ``The contents of this file are subject to the Erlang Public License, +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009-2012. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # compliance with the License. You should have received a copy of the # Erlang Public License along with this software. If not, it can be -# retrieved via the world wide web at http://www.erlang.org/. -# +# retrieved online at http://www.erlang.org/. +# # Software distributed under the License is distributed on an "AS IS" # basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See # the License for the specific language governing rights and limitations # under the License. -# -# The Initial Developer of the Original Code is Ericsson Utvecklings AB. -# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -# AB. All Rights Reserved.'' -# -# $Id$ +# +# %CopyrightEnd% # include $(ERL_TOP)/make/target.mk @@ -138,15 +139,17 @@ EMEM_LIBS = $(LIBS) \ EMEM_OBJS = $(addprefix $(EMEM_OBJ_DIR)/,$(notdir $(EMEM_SRCS:.c=.o))) +ERTS_LIB = $(ERL_TOP/erts/lib_src/obj/$(TARGET)/$(TYPE)/MADE + # # Misc targets # _create_dirs := $(shell mkdir -p $(CREATE_DIRS)) -all: erts_lib $(PROGS) $(DRIVERS) +all: $(PROGS) $(DRIVERS) -erts_lib: +$(ERTS_LIB): cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE) @@ -174,7 +177,7 @@ $(EMEM_OBJ_DIR)/%.o: %.c # Program targets # -$(BIN_DIR)/emem$(TYPEMARKER)@EXEEXT@: $(EMEM_OBJS) +$(BIN_DIR)/emem$(TYPEMARKER)@EXEEXT@: $(EMEM_OBJS) $(ERTS_LIB) $(PRE_LD) $(LD) $(EMEM_LDFLAGS) -o $@ $(EMEM_OBJS) $(EMEM_LIBS) # diff --git a/lib/tools/c_src/erl_memory.c b/lib/tools/c_src/erl_memory.c index 872d55e789..5239176d03 100644 --- a/lib/tools/c_src/erl_memory.c +++ b/lib/tools/c_src/erl_memory.c @@ -1224,7 +1224,7 @@ print_main_footer(em_state *state) switch (state->info.stop_reason) { case EMTP_STOP: - p += sprintf(p, stop_str); + p += sprintf(p, "%s", stop_str); break; case EMTP_EXIT: p += sprintf(p, exit_str, state->info.exit_status); @@ -2339,7 +2339,7 @@ usage(char *sw, char *error) if (error) exit(1); else { - char *help_str = + fprintf(filep, "\n" " [] - switch is allowed any number of times\n" " {} - switch is allowed at most one time\n" @@ -2370,8 +2370,7 @@ usage(char *sw, char *error) " " SW_CHAR "o - display operation count values\n" " " SW_CHAR "p <P> - set listen port to <P>\n" " " SW_CHAR "t - display info about total values\n" - " " SW_CHAR "v - verbose output\n"; - fprintf(filep, help_str); + " " SW_CHAR "v - verbose output\n"); exit(0); } diff --git a/lib/tools/doc/src/notes.xml b/lib/tools/doc/src/notes.xml index 17506fb6e2..e24e1c5977 100644 --- a/lib/tools/doc/src/notes.xml +++ b/lib/tools/doc/src/notes.xml @@ -30,6 +30,85 @@ </header> <p>This document describes the changes made to the Tools application.</p> +<section><title>Tools 2.6.6.6</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p>Update system profiling principles to reflect eprof + performance improvements.</p> + <p> + Own Id: OTP-9656</p> + </item> + <item> + <p> + [cover] fix leftover {'DOWN', ..} msg in callers queue</p> + <p> + After stopping cover with cover:stop() there could still + be a {'DOWN',...} leftover message in the calling + process's message queue. This unexpected leftover could + be eliminated if erlang:demonitor/2 with option flush + would be used in certain points</p> + <p> + Own Id: OTP-9694</p> + </item> + <item> + <p> + Add deps as erlang-flymake include directory.</p> + <p> + Update erlang-flymake to recognize the "deps" folder as + an include directory. This makes erlang-flymake + compatible with the rebar dependency management tool's + default folder structure, which puts included + dependencies in "deps".(Thanks to Kevin Albrecht)</p> + <p> + Own Id: OTP-9791</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Variables are now now allowed in '<c>fun M:F/A</c>' as + suggested by Richard O'Keefe in EEP-23.</p> + <p>The representation of '<c>fun M:F/A</c>' in the + abstract format has been changed in an incompatible way. + Tools that directly read or manipulate the abstract + format (such as parse transforms) may need to be updated. + The compiler can handle both the new and the old format + (i.e. extracting the abstract format from a pre-R15 BEAM + file and compiling it using compile:forms/1,2 will work). + The <c>syntax_tools</c> application can also handle both + formats.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9643</p> + </item> + <item> + <p> + Tuple funs (a two-element tuple with a module name and a + function) are now officially deprecated and will be + removed in R16. Use '<c>fun M:F/A</c>' instead. To make + you aware that your system uses tuple funs, the very + first time a tuple fun is applied, a warning will be sent + to the error logger.</p> + <p> + Own Id: OTP-9649</p> + </item> + <item> + <p> + Eliminate use of deprecated regexp module</p> + <p> + Own Id: OTP-9810</p> + </item> + </list> + </section> + +</section> + <section><title>Tools 2.6.6.5</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/tools/test/fprof_SUITE.erl b/lib/tools/test/fprof_SUITE.erl index 0da6d4a9ea..f491c1e227 100644 --- a/lib/tools/test/fprof_SUITE.erl +++ b/lib/tools/test/fprof_SUITE.erl @@ -191,11 +191,17 @@ tail_seq(Config) when is_list(Config) -> %%%--------------------------------------------------------------------- -create_file_slow(doc) -> - ["Tests the create_file_slow benchmark"]; -create_file_slow(suite) -> - []; -create_file_slow(Config) when is_list(Config) -> +%% Tests the create_file_slow benchmark. +create_file_slow(Config) -> + case test_server:is_native(lists) orelse + test_server:is_native(file) of + true -> + {skip,"Native libs -- tracing does not work"}; + false -> + do_create_file_slow(Config) + end. + +do_create_file_slow(Config) -> ?line Timetrap = ?t:timetrap(?t:seconds(40)), ?line PrivDir = ?config(priv_dir, Config), ?line TraceFile = diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk index 2d63a33554..269d3d7773 100644 --- a/lib/tools/vsn.mk +++ b/lib/tools/vsn.mk @@ -1 +1 @@ -TOOLS_VSN = 2.6.6.5 +TOOLS_VSN = 2.6.6.6 diff --git a/lib/tv/doc/src/notes.xml b/lib/tv/doc/src/notes.xml index 77a6a43d51..97c99e6202 100644 --- a/lib/tv/doc/src/notes.xml +++ b/lib/tv/doc/src/notes.xml @@ -30,6 +30,21 @@ </header> <p>This document describes the changes made to the TV application.</p> +<section><title>TV 2.1.4.8</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Eliminate use of deprecated regexp module</p> + <p> + Own Id: OTP-9810</p> + </item> + </list> + </section> + +</section> + <section><title>TV 2.1.4.7</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/tv/doc/src/table_visualizer_chapter.xml b/lib/tv/doc/src/table_visualizer_chapter.xml index 12efbe643c..dbfd322945 100644 --- a/lib/tv/doc/src/table_visualizer_chapter.xml +++ b/lib/tv/doc/src/table_visualizer_chapter.xml @@ -31,6 +31,12 @@ <rev>C</rev> <file>table_visualizer.xml</file> </header> + <warning> + <p> + The TV application has been superseded by the Observer application. + TV will be removed in R16. + </p> + </warning> <p>The TV, TV, is a tool that enables the user to examine ETS and Mnesia tables on any (connected) node in the currently running Erlang system. Once a certain table has been opened in the tool, the content may be diff --git a/lib/tv/doc/src/tv.xml b/lib/tv/doc/src/tv.xml index 84b9f8c33d..83bbdfc052 100644 --- a/lib/tv/doc/src/tv.xml +++ b/lib/tv/doc/src/tv.xml @@ -36,6 +36,12 @@ <module>tv</module> <modulesummary>TV graphically examines ETS and Mnesia tables. </modulesummary> <description> + <warning> + <p> + The TV application has been superseded by the Observer application. + TV will be removed in R16. + </p> + </warning> <p>TV enables the user to examine ETS and Mnesia tables. Once a certain table has been opened in the tool, the content may be viewed at various levels of detail. The content viewed may also be sorted, using any diff --git a/lib/tv/src/tv_db.erl b/lib/tv/src/tv_db.erl index 201b4c0e6b..179b75c2e6 100644 --- a/lib/tv/src/tv_db.erl +++ b/lib/tv/src/tv_db.erl @@ -22,6 +22,10 @@ %%%********************************************************************* -module(tv_db). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). diff --git a/lib/tv/src/tv_db_search.erl b/lib/tv/src/tv_db_search.erl index 7bf5c4c048..6ae999253a 100644 --- a/lib/tv/src/tv_db_search.erl +++ b/lib/tv/src/tv_db_search.erl @@ -21,6 +21,18 @@ %%% %%%********************************************************************* -module(tv_db_search). +-compile([{nowarn_deprecated_function,{gs,button,3}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,entry,3}}, + {nowarn_deprecated_function,{gs,frame,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,label,3}}, + {nowarn_deprecated_function,{gs,listbox,3}}, + {nowarn_deprecated_function,{gs,radiobutton,3}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). diff --git a/lib/tv/src/tv_etsread.erl b/lib/tv/src/tv_etsread.erl index d3240ef513..b3e38f9d45 100644 --- a/lib/tv/src/tv_etsread.erl +++ b/lib/tv/src/tv_etsread.erl @@ -25,6 +25,9 @@ -module(tv_etsread). +-compile([{nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). diff --git a/lib/tv/src/tv_info.erl b/lib/tv/src/tv_info.erl index 7bc31e35cd..941286362c 100644 --- a/lib/tv/src/tv_info.erl +++ b/lib/tv/src/tv_info.erl @@ -16,6 +16,14 @@ %% %% %CopyrightEnd% -module(tv_info). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,frame,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,listbox,2}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). diff --git a/lib/tv/src/tv_ip.erl b/lib/tv/src/tv_ip.erl index aeec4e8f6d..2d3ada878a 100644 --- a/lib/tv/src/tv_ip.erl +++ b/lib/tv/src/tv_ip.erl @@ -16,6 +16,12 @@ %% %% %CopyrightEnd% -module(tv_ip). +-compile([{nowarn_deprecated_function,{gs,canvas,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). diff --git a/lib/tv/src/tv_main.erl b/lib/tv/src/tv_main.erl index 36cf92bee3..fbf56971f9 100644 --- a/lib/tv/src/tv_main.erl +++ b/lib/tv/src/tv_main.erl @@ -16,6 +16,20 @@ %% %% %CopyrightEnd% -module(tv_main). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,frame,3}}, + {nowarn_deprecated_function,{gs,grid,3}}, + {nowarn_deprecated_function,{gs,gridline,2}}, + {nowarn_deprecated_function,{gs,label,3}}, + {nowarn_deprecated_function,{gs,menu,2}}, + {nowarn_deprecated_function,{gs,menubar,3}}, + {nowarn_deprecated_function,{gs,menubutton,2}}, + {nowarn_deprecated_function,{gs,menuitem,2}}, + {nowarn_deprecated_function,{gs,menuitem,3}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). diff --git a/lib/tv/src/tv_new_table.erl b/lib/tv/src/tv_new_table.erl index 3d62b0548b..d31b9a4ee2 100644 --- a/lib/tv/src/tv_new_table.erl +++ b/lib/tv/src/tv_new_table.erl @@ -16,6 +16,16 @@ %% %% %CopyrightEnd%k -module(tv_new_table). +-compile([{nowarn_deprecated_function,{gs,button,3}}, + {nowarn_deprecated_function,{gs,checkbutton,3}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,entry,3}}, + {nowarn_deprecated_function,{gs,frame,3}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,radiobutton,3}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). diff --git a/lib/tv/src/tv_nodewin.erl b/lib/tv/src/tv_nodewin.erl index 3999d201d8..9030ed930f 100644 --- a/lib/tv/src/tv_nodewin.erl +++ b/lib/tv/src/tv_nodewin.erl @@ -16,6 +16,15 @@ %% %% %CopyrightEnd% -module(tv_nodewin). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,listbox,3}}, + {nowarn_deprecated_function,{gs,menu,3}}, + {nowarn_deprecated_function,{gs,menubar,3}}, + {nowarn_deprecated_function,{gs,menubutton,3}}, + {nowarn_deprecated_function,{gs,menuitem,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). diff --git a/lib/tv/src/tv_pb.erl b/lib/tv/src/tv_pb.erl index 78a27185dc..fa3dcde919 100644 --- a/lib/tv/src/tv_pb.erl +++ b/lib/tv/src/tv_pb.erl @@ -16,6 +16,9 @@ %% %% %CopyrightEnd% -module(tv_pb). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,frame,2}}]). diff --git a/lib/tv/src/tv_pb_funcs.erl b/lib/tv/src/tv_pb_funcs.erl index 87a4719bbd..0670d2795f 100644 --- a/lib/tv/src/tv_pb_funcs.erl +++ b/lib/tv/src/tv_pb_funcs.erl @@ -16,6 +16,12 @@ %% %% %CopyrightEnd% -module(tv_pb_funcs). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,canvas,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,read,2}}]). diff --git a/lib/tv/src/tv_pc.erl b/lib/tv/src/tv_pc.erl index 50214fe06a..fcb7aba3a7 100644 --- a/lib/tv/src/tv_pc.erl +++ b/lib/tv/src/tv_pc.erl @@ -25,6 +25,7 @@ -module(tv_pc). +-compile([{nowarn_deprecated_function,{gs,config,2}}]). diff --git a/lib/tv/src/tv_pc_menu_handling.erl b/lib/tv/src/tv_pc_menu_handling.erl index 16195bf91f..5d411b106e 100644 --- a/lib/tv/src/tv_pc_menu_handling.erl +++ b/lib/tv/src/tv_pc_menu_handling.erl @@ -25,6 +25,10 @@ -module(tv_pc_menu_handling). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). diff --git a/lib/tv/src/tv_pd.erl b/lib/tv/src/tv_pd.erl index ea14bf67b1..6694ea22a3 100644 --- a/lib/tv/src/tv_pd.erl +++ b/lib/tv/src/tv_pd.erl @@ -24,6 +24,11 @@ -module(tv_pd). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,destroy,1}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). diff --git a/lib/tv/src/tv_pd_display.erl b/lib/tv/src/tv_pd_display.erl index f5a30cb640..dab442e28e 100644 --- a/lib/tv/src/tv_pd_display.erl +++ b/lib/tv/src/tv_pd_display.erl @@ -22,6 +22,13 @@ %%%********************************************************************* -module(tv_pd_display). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,editor,2}}, + {nowarn_deprecated_function,{gs,entry,3}}, + {nowarn_deprecated_function,{gs,frame,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,read,2}}]). diff --git a/lib/tv/src/tv_pd_frames.erl b/lib/tv/src/tv_pd_frames.erl index 4e091ac9f0..d18dcaf70d 100644 --- a/lib/tv/src/tv_pd_frames.erl +++ b/lib/tv/src/tv_pd_frames.erl @@ -16,6 +16,8 @@ %% %% %CopyrightEnd% -module(tv_pd_frames). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,frame,2}}]). diff --git a/lib/tv/src/tv_pd_scale.erl b/lib/tv/src/tv_pd_scale.erl index c94e57f468..2f98c3183f 100644 --- a/lib/tv/src/tv_pd_scale.erl +++ b/lib/tv/src/tv_pd_scale.erl @@ -24,6 +24,8 @@ -module(tv_pd_scale). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,scale,2}}]). diff --git a/lib/tv/src/tv_pg.erl b/lib/tv/src/tv_pg.erl index ba8782392b..0b36b18212 100644 --- a/lib/tv/src/tv_pg.erl +++ b/lib/tv/src/tv_pg.erl @@ -16,6 +16,7 @@ %% %% %CopyrightEnd% -module(tv_pg). +-compile([{nowarn_deprecated_function,{gs,config,2}}]). diff --git a/lib/tv/src/tv_pg_gridfcns.erl b/lib/tv/src/tv_pg_gridfcns.erl index 3d23c8a69f..e47dac28a8 100644 --- a/lib/tv/src/tv_pg_gridfcns.erl +++ b/lib/tv/src/tv_pg_gridfcns.erl @@ -16,6 +16,10 @@ %% %% %CopyrightEnd% -module(tv_pg_gridfcns). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,frame,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,read,2}}]). diff --git a/lib/tv/src/tv_poll_dialog.erl b/lib/tv/src/tv_poll_dialog.erl index 8d41251266..4bf49f44f1 100644 --- a/lib/tv/src/tv_poll_dialog.erl +++ b/lib/tv/src/tv_poll_dialog.erl @@ -22,7 +22,13 @@ %%%********************************************************************* -module(tv_poll_dialog). - +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,radiobutton,2}}, + {nowarn_deprecated_function,{gs,scale,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,2}}]). -export([start/1, init/2]). diff --git a/lib/tv/src/tv_pw.erl b/lib/tv/src/tv_pw.erl index 8b3186e090..bd6d06e241 100644 --- a/lib/tv/src/tv_pw.erl +++ b/lib/tv/src/tv_pw.erl @@ -23,6 +23,7 @@ -module(tv_pw). +-compile([{nowarn_deprecated_function,{gs,config,2}}]). diff --git a/lib/tv/src/tv_pw_window.erl b/lib/tv/src/tv_pw_window.erl index 9cb5c879c0..0cd241a031 100644 --- a/lib/tv/src/tv_pw_window.erl +++ b/lib/tv/src/tv_pw_window.erl @@ -23,6 +23,10 @@ -module(tv_pw_window). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,menuitem,3}}, + {nowarn_deprecated_function,{gs,start,0}}]). diff --git a/lib/tv/src/tv_rec_edit.erl b/lib/tv/src/tv_rec_edit.erl index e8f663073e..f6c09ebc67 100644 --- a/lib/tv/src/tv_rec_edit.erl +++ b/lib/tv/src/tv_rec_edit.erl @@ -16,6 +16,16 @@ %% %% %CopyrightEnd% -module(tv_rec_edit). +-compile([{nowarn_deprecated_function,{gs,button,2}}, + {nowarn_deprecated_function,{gs,button,3}}, + {nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,entry,3}}, + {nowarn_deprecated_function,{gs,frame,2}}, + {nowarn_deprecated_function,{gs,frame,3}}, + {nowarn_deprecated_function,{gs,label,2}}, + {nowarn_deprecated_function,{gs,read,2}}, + {nowarn_deprecated_function,{gs,start,0}}, + {nowarn_deprecated_function,{gs,window,3}}]). diff --git a/lib/tv/src/tv_utils.erl b/lib/tv/src/tv_utils.erl index fd232bde69..9c7458d302 100644 --- a/lib/tv/src/tv_utils.erl +++ b/lib/tv/src/tv_utils.erl @@ -16,6 +16,9 @@ %% %% %CopyrightEnd% -module(tv_utils). +-compile([{nowarn_deprecated_function,{gs,config,2}}, + {nowarn_deprecated_function,{gs,create,3}}, + {nowarn_deprecated_function,{gs,destroy,1}}]). diff --git a/lib/tv/vsn.mk b/lib/tv/vsn.mk index 43e3d2ebce..756aae2096 100644 --- a/lib/tv/vsn.mk +++ b/lib/tv/vsn.mk @@ -1 +1 @@ -TV_VSN = 2.1.4.7 +TV_VSN = 2.1.4.8 diff --git a/lib/typer/vsn.mk b/lib/typer/vsn.mk index 9e73aed286..85a7c01424 100644 --- a/lib/typer/vsn.mk +++ b/lib/typer/vsn.mk @@ -1 +1 @@ -TYPER_VSN = 0.9.2 +TYPER_VSN = 0.9.3 diff --git a/lib/webtool/doc/src/notes.xml b/lib/webtool/doc/src/notes.xml index c58a440937..a56fdd7b6f 100644 --- a/lib/webtool/doc/src/notes.xml +++ b/lib/webtool/doc/src/notes.xml @@ -31,6 +31,21 @@ <p>This document describes the changes made to the Webtool application.</p> +<section><title>WebTool 0.8.9.1</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Miscellaneous documentation build updates</p> + <p> + Own Id: OTP-9813</p> + </item> + </list> + </section> + +</section> + <section><title>WebTool 0.8.9</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/webtool/vsn.mk b/lib/webtool/vsn.mk index 2643be866e..690f9a22cf 100644 --- a/lib/webtool/vsn.mk +++ b/lib/webtool/vsn.mk @@ -1 +1 @@ -WEBTOOL_VSN=0.8.9 +WEBTOOL_VSN=0.8.9.1 diff --git a/lib/wx/Makefile b/lib/wx/Makefile index 0bc89e08ad..9a75b2e36e 100644 --- a/lib/wx/Makefile +++ b/lib/wx/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2010. All Rights Reserved. +# Copyright Ericsson AB 2008-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -18,12 +18,19 @@ # include ./vsn.mk -include ./config.mk -SUBDIRS = src -ifeq ($(CAN_BUILD_DRIVER), true) -SUBDIRS += c_src -endif -SUBDIRS += examples doc/src + +ifdef TERTIARY_BOOTSTRAP + INSIDE_ERLSRC = true + SUBDIRS = src +else # Normal build + include ./config.mk + SUBDIRS = src + ifeq ($(CAN_BUILD_DRIVER), true) + SUBDIRS += c_src + endif + SUBDIRS += examples doc/src +endif #TERTIARY_BOOTSTRAP + CLEANDIRS = $(SUBDIRS) api_gen ifeq ($(INSIDE_ERLSRC),true) @@ -32,6 +39,7 @@ ifeq ($(INSIDE_ERLSRC),true) # Default Subdir Targets # ---------------------------------------------------- SUB_DIRECTORIES=$(SUBDIRS) + include $(ERL_TOP)/make/otp_subdir.mk else # we are building standalone wxErlang diff --git a/lib/wx/api_gen/gl_gen_c.erl b/lib/wx/api_gen/gl_gen_c.erl index 0f5cb0e1f4..be2c5cf2bf 100644 --- a/lib/wx/api_gen/gl_gen_c.erl +++ b/lib/wx/api_gen/gl_gen_c.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -238,7 +238,7 @@ decode_arg(P=#arg{name=Name,type=#type{size=BSz,name=Type,single={list,TSz}}},A0 {P, A}; decode_arg(P=#arg{name=Name,type=#type{name=Type,base=guard_int}},A0) -> A = align(4,A0), - w(" ~s *~s = (~s *) * (int *) bp; bp += 4;~n", [Type,Name,Type]), + w(" ~s *~s = (~s *) (ErlDrvSInt) * (int *) bp; bp += 4;~n", [Type,Name,Type]), {P, A}; decode_arg(P=#arg{name=Name,type=#type{name=Type,base=string,single=true}},A0) -> w(" ~s *~s = (~s *) bp;~n", [Type,Name,Type]), diff --git a/lib/wx/c_src/gen/gl_funcs.cpp b/lib/wx/c_src/gen/gl_funcs.cpp index 30542a0f02..fa1476dba5 100644 --- a/lib/wx/c_src/gen/gl_funcs.cpp +++ b/lib/wx/c_src/gen/gl_funcs.cpp @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2010. All Rights Reserved. + * Copyright Ericsson AB 2008-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -395,7 +395,7 @@ case 5043: { // glBitmap GLfloat *yorig = (GLfloat *) bp; bp += 4; GLfloat *xmove = (GLfloat *) bp; bp += 4; GLfloat *ymove = (GLfloat *) bp; bp += 4; - GLubyte *bitmap = (GLubyte *) * (int *) bp; bp += 4; + GLubyte *bitmap = (GLubyte *) (ErlDrvSInt) * (int *) bp; bp += 4; weglBitmap(*width,*height,*xorig,*yorig,*xmove,*ymove,bitmap); }; break; case 5044: { // glBitmap @@ -538,7 +538,7 @@ case 5073: { // glColorPointer GLint *size = (GLint *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; GLsizei *stride = (GLsizei *) bp; bp += 4; - GLvoid *pointer = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglColorPointer(*size,*type,*stride,pointer); }; break; case 5074: { // glColorPointer @@ -646,7 +646,7 @@ case 5090: { // glDrawElements GLenum *mode = (GLenum *) bp; bp += 4; GLsizei *count = (GLsizei *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *indices = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *indices = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglDrawElements(*mode,*count,*type,indices); }; break; case 5091: { // glDrawElements @@ -661,7 +661,7 @@ case 5092: { // glDrawPixels GLsizei *height = (GLsizei *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *pixels = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pixels = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglDrawPixels(*width,*height,*format,*type,pixels); }; break; case 5093: { // glDrawPixels @@ -678,7 +678,7 @@ case 5094: { // glEdgeFlagv }; break; case 5095: { // glEdgeFlagPointer GLsizei *stride = (GLsizei *) bp; bp += 4; - GLvoid *pointer = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglEdgeFlagPointer(*stride,pointer); }; break; case 5096: { // glEdgeFlagPointer @@ -1265,7 +1265,7 @@ case 5149: { // glIndexMask case 5150: { // glIndexPointer GLenum *type = (GLenum *) bp; bp += 4; GLsizei *stride = (GLsizei *) bp; bp += 4; - GLvoid *pointer = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglIndexPointer(*type,*stride,pointer); }; break; case 5151: { // glIndexPointer @@ -1300,7 +1300,7 @@ case 5157: { // glInitNames case 5158: { // glInterleavedArrays GLenum *format = (GLenum *) bp; bp += 4; GLsizei *stride = (GLsizei *) bp; bp += 4; - GLvoid *pointer = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglInterleavedArrays(*format,*stride,pointer); }; break; case 5159: { // glInterleavedArrays @@ -1561,7 +1561,7 @@ case 5199: { // glNormal3sv case 5200: { // glNormalPointer GLenum *type = (GLenum *) bp; bp += 4; GLsizei *stride = (GLsizei *) bp; bp += 4; - GLvoid *pointer = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglNormalPointer(*type,*stride,pointer); }; break; case 5201: { // glNormalPointer @@ -1933,7 +1933,7 @@ case 5274: { // glTexCoordPointer GLint *size = (GLint *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; GLsizei *stride = (GLsizei *) bp; bp += 4; - GLvoid *pointer = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglTexCoordPointer(*size,*type,*stride,pointer); }; break; case 5275: { // glTexCoordPointer @@ -2016,7 +2016,7 @@ case 5286: { // glTexImage1D GLint *border = (GLint *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *pixels = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pixels = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglTexImage1D(*target,*level,*internalformat,*width,*border,*format,*type,pixels); }; break; case 5287: { // glTexImage1D @@ -2039,7 +2039,7 @@ case 5288: { // glTexImage2D GLint *border = (GLint *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *pixels = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pixels = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglTexImage2D(*target,*level,*internalformat,*width,*height,*border,*format,*type,pixels); }; break; case 5289: { // glTexImage2D @@ -2087,7 +2087,7 @@ case 5294: { // glTexSubImage1D GLsizei *width = (GLsizei *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *pixels = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pixels = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglTexSubImage1D(*target,*level,*xoffset,*width,*format,*type,pixels); }; break; case 5295: { // glTexSubImage1D @@ -2109,7 +2109,7 @@ case 5296: { // glTexSubImage2D GLsizei *height = (GLsizei *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *pixels = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pixels = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglTexSubImage2D(*target,*level,*xoffset,*yoffset,*width,*height,*format,*type,pixels); }; break; case 5297: { // glTexSubImage2D @@ -2188,7 +2188,7 @@ case 5312: { // glVertexPointer GLint *size = (GLint *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; GLsizei *stride = (GLsizei *) bp; bp += 4; - GLvoid *pointer = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglVertexPointer(*size,*type,*stride,pointer); }; break; case 5313: { // glVertexPointer @@ -2222,7 +2222,7 @@ case 5317: { // glDrawRangeElements GLuint *end = (GLuint *) bp; bp += 4; GLsizei *count = (GLsizei *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *indices = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *indices = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglDrawRangeElements(*mode,*start,*end,*count,*type,indices); }; break; case 5318: { // glDrawRangeElements @@ -2244,7 +2244,7 @@ case 5319: { // glTexImage3D GLint *border = (GLint *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *pixels = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pixels = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglTexImage3D(*target,*level,*internalformat,*width,*height,*depth,*border,*format,*type,pixels); }; break; case 5320: { // glTexImage3D @@ -2271,7 +2271,7 @@ case 5321: { // glTexSubImage3D GLsizei *depth = (GLsizei *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *pixels = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pixels = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglTexSubImage3D(*target,*level,*xoffset,*yoffset,*zoffset,*width,*height,*depth,*format,*type,pixels); }; break; case 5322: { // glTexSubImage3D @@ -2306,7 +2306,7 @@ case 5324: { // glColorTable GLsizei *width = (GLsizei *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *table = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *table = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglColorTable(*target,*internalformat,*width,*format,*type,table); }; break; case 5325: { // glColorTable @@ -2389,7 +2389,7 @@ case 5332: { // glColorSubTable GLsizei *count = (GLsizei *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *data = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *data = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglColorSubTable(*target,*start,*count,*format,*type,data); }; break; case 5333: { // glColorSubTable @@ -2415,7 +2415,7 @@ case 5335: { // glConvolutionFilter1D GLsizei *width = (GLsizei *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *image = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *image = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglConvolutionFilter1D(*target,*internalformat,*width,*format,*type,image); }; break; case 5336: { // glConvolutionFilter1D @@ -2434,7 +2434,7 @@ case 5337: { // glConvolutionFilter2D GLsizei *height = (GLsizei *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *image = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *image = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglConvolutionFilter2D(*target,*internalformat,*width,*height,*format,*type,image); }; break; case 5338: { // glConvolutionFilter2D @@ -2530,8 +2530,8 @@ case 5346: { // glSeparableFilter2D GLsizei *height = (GLsizei *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *row = (GLvoid *) * (int *) bp; bp += 4; - GLvoid *column = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *row = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; + GLvoid *column = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglSeparableFilter2D(*target,*internalformat,*width,*height,*format,*type,row,column); }; break; case 5347: { // glSeparableFilter2D @@ -2666,7 +2666,7 @@ case 5360: { // glCompressedTexImage3D GLsizei *depth = (GLsizei *) bp; bp += 4; GLint *border = (GLint *) bp; bp += 4; GLsizei *imageSize = (GLsizei *) bp; bp += 4; - GLvoid *data = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *data = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglCompressedTexImage3D(*target,*level,*internalformat,*width,*height,*depth,*border,*imageSize,data); }; break; case 5361: { // glCompressedTexImage3D @@ -2689,7 +2689,7 @@ case 5362: { // glCompressedTexImage2D GLsizei *height = (GLsizei *) bp; bp += 4; GLint *border = (GLint *) bp; bp += 4; GLsizei *imageSize = (GLsizei *) bp; bp += 4; - GLvoid *data = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *data = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglCompressedTexImage2D(*target,*level,*internalformat,*width,*height,*border,*imageSize,data); }; break; case 5363: { // glCompressedTexImage2D @@ -2710,7 +2710,7 @@ case 5364: { // glCompressedTexImage1D GLsizei *width = (GLsizei *) bp; bp += 4; GLint *border = (GLint *) bp; bp += 4; GLsizei *imageSize = (GLsizei *) bp; bp += 4; - GLvoid *data = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *data = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglCompressedTexImage1D(*target,*level,*internalformat,*width,*border,*imageSize,data); }; break; case 5365: { // glCompressedTexImage1D @@ -2734,7 +2734,7 @@ case 5366: { // glCompressedTexSubImage3D GLsizei *depth = (GLsizei *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLsizei *imageSize = (GLsizei *) bp; bp += 4; - GLvoid *data = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *data = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglCompressedTexSubImage3D(*target,*level,*xoffset,*yoffset,*zoffset,*width,*height,*depth,*format,*imageSize,data); }; break; case 5367: { // glCompressedTexSubImage3D @@ -2760,7 +2760,7 @@ case 5368: { // glCompressedTexSubImage2D GLsizei *height = (GLsizei *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLsizei *imageSize = (GLsizei *) bp; bp += 4; - GLvoid *data = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *data = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglCompressedTexSubImage2D(*target,*level,*xoffset,*yoffset,*width,*height,*format,*imageSize,data); }; break; case 5369: { // glCompressedTexSubImage2D @@ -2782,7 +2782,7 @@ case 5370: { // glCompressedTexSubImage1D GLsizei *width = (GLsizei *) bp; bp += 4; GLenum *format = (GLenum *) bp; bp += 4; GLsizei *imageSize = (GLsizei *) bp; bp += 4; - GLvoid *data = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *data = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglCompressedTexSubImage1D(*target,*level,*xoffset,*width,*format,*imageSize,data); }; break; case 5371: { // glCompressedTexSubImage1D @@ -2958,7 +2958,7 @@ case 5401: { // glFogCoorddv case 5402: { // glFogCoordPointer GLenum *type = (GLenum *) bp; bp += 4; GLsizei *stride = (GLsizei *) bp; bp += 4; - GLvoid *pointer = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglFogCoordPointer(*type,*stride,pointer); }; break; case 5403: { // glFogCoordPointer @@ -3003,7 +3003,7 @@ case 5412: { // glSecondaryColorPointer GLint *size = (GLint *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; GLsizei *stride = (GLsizei *) bp; bp += 4; - GLvoid *pointer = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglSecondaryColorPointer(*size,*type,*stride,pointer); }; break; case 5413: { // glSecondaryColorPointer @@ -3156,7 +3156,7 @@ case 5434: { // glBufferData GLenum *target = (GLenum *) bp; bp += 4; bp += 4; GLsizeiptr size = (GLsizeiptr) * (GLuint64EXT *) bp; bp += 8; - GLvoid *data = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *data = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; GLenum *usage = (GLenum *) bp; bp += 4; weglBufferData(*target,size,data,*usage); }; break; @@ -3173,7 +3173,7 @@ case 5436: { // glBufferSubData bp += 4; GLintptr offset = (GLintptr) * (GLuint64EXT *) bp; bp += 8; GLsizeiptr size = (GLsizeiptr) * (GLuint64EXT *) bp; bp += 8; - GLvoid *data = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *data = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglBufferSubData(*target,offset,size,data); }; break; case 5437: { // glBufferSubData @@ -3833,7 +3833,7 @@ case 5518: { // glVertexAttribPointer GLboolean *normalized = (GLboolean *) bp; bp += 1; bp += 3; GLsizei *stride = (GLsizei *) bp; bp += 4; - GLvoid *pointer = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglVertexAttribPointer(*index,*size,*type,*normalized,*stride,pointer); }; break; case 5519: { // glVertexAttribPointer @@ -4051,7 +4051,7 @@ case 5541: { // glVertexAttribIPointer GLint *size = (GLint *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; GLsizei *stride = (GLsizei *) bp; bp += 4; - GLvoid *pointer = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglVertexAttribIPointer(*index,*size,*type,*stride,pointer); }; break; case 5542: { // glVertexAttribIPointer @@ -4345,7 +4345,7 @@ case 5578: { // glDrawElementsInstanced GLenum *mode = (GLenum *) bp; bp += 4; GLsizei *count = (GLsizei *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *indices = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *indices = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; GLsizei *primcount = (GLsizei *) bp; bp += 4; weglDrawElementsInstanced(*mode,*count,*type,indices,*primcount); }; break; @@ -5341,7 +5341,7 @@ case 5683: { // glDrawElementsBaseVertex GLenum *mode = (GLenum *) bp; bp += 4; GLsizei *count = (GLsizei *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *indices = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *indices = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; GLint *basevertex = (GLint *) bp; bp += 4; weglDrawElementsBaseVertex(*mode,*count,*type,indices,*basevertex); }; break; @@ -5359,7 +5359,7 @@ case 5685: { // glDrawRangeElementsBaseVertex GLuint *end = (GLuint *) bp; bp += 4; GLsizei *count = (GLsizei *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *indices = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *indices = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; GLint *basevertex = (GLint *) bp; bp += 4; weglDrawRangeElementsBaseVertex(*mode,*start,*end,*count,*type,indices,*basevertex); }; break; @@ -5377,7 +5377,7 @@ case 5687: { // glDrawElementsInstancedBaseVertex GLenum *mode = (GLenum *) bp; bp += 4; GLsizei *count = (GLsizei *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *indices = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *indices = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; GLsizei *primcount = (GLsizei *) bp; bp += 4; GLint *basevertex = (GLint *) bp; bp += 4; weglDrawElementsInstancedBaseVertex(*mode,*count,*type,indices,*primcount,*basevertex); @@ -5772,7 +5772,7 @@ case 5725: { // glGetQueryObjectui64v }; break; case 5726: { // glDrawArraysIndirect GLenum *mode = (GLenum *) bp; bp += 4; - GLvoid *indirect = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *indirect = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglDrawArraysIndirect(*mode,indirect); }; break; case 5727: { // glDrawArraysIndirect @@ -5783,7 +5783,7 @@ case 5727: { // glDrawArraysIndirect case 5728: { // glDrawElementsIndirect GLenum *mode = (GLenum *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; - GLvoid *indirect = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *indirect = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglDrawElementsIndirect(*mode,*type,indirect); }; break; case 5729: { // glDrawElementsIndirect @@ -6718,7 +6718,7 @@ case 5840: { // glVertexAttribLPointer GLint *size = (GLint *) bp; bp += 4; GLenum *type = (GLenum *) bp; bp += 4; GLsizei *stride = (GLsizei *) bp; bp += 4; - GLvoid *pointer = (GLvoid *) * (int *) bp; bp += 4; + GLvoid *pointer = (GLvoid *) (ErlDrvSInt) * (int *) bp; bp += 4; weglVertexAttribLPointer(*index,*size,*type,*stride,pointer); }; break; case 5841: { // glVertexAttribLPointer diff --git a/lib/wx/doc/src/Makefile b/lib/wx/doc/src/Makefile index c8eb6174c4..03e9f1e1bb 100644 --- a/lib/wx/doc/src/Makefile +++ b/lib/wx/doc/src/Makefile @@ -22,7 +22,7 @@ # ---------------------------------------------------- include ../../vsn.mk include ../../config.mk -APPLICATION=wxErlang +APPLICATION=wx ErlMods = wx.erl wx_object.erl diff --git a/lib/wx/doc/src/notes.xml b/lib/wx/doc/src/notes.xml index 7bd8d18592..4a94227a55 100644 --- a/lib/wx/doc/src/notes.xml +++ b/lib/wx/doc/src/notes.xml @@ -31,6 +31,37 @@ <p>This document describes the changes made to the wxErlang application.</p> +<section><title>Wx 0.99.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed a deadlock in the driver, which could happen if a + callback caused another callback to be invoked.</p> + <p> + Own Id: OTP-9725</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Implemented wxSystemOptions.</p> + <p> + Load Opengl from libGL.so.1 instead libGL.so to work + around linux problems.</p> + <p> + Own Id: OTP-9702</p> + </item> + </list> + </section> + +</section> + <section><title>Wx 0.99</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/wx/examples/demo/demo.erl b/lib/wx/examples/demo/demo.erl index 59c20e09fb..61e71af021 100644 --- a/lib/wx/examples/demo/demo.erl +++ b/lib/wx/examples/demo/demo.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -27,7 +27,7 @@ -behaviour(wx_object). -export([start/0, start/1, start_link/0, start_link/1, format/3, init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -record(state, {win, demo, example, selector, log, code}). @@ -189,6 +189,10 @@ handle_call(Msg, _From, State) -> io:format("Got Call ~p~n",[Msg]), {reply,ok,State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + %% Async Events are handled in handle_event as in handle_info handle_event(#wx{event=#wxCommand{type=command_listbox_selected, cmdString=Ex}}, State = #state{demo={_,DemoSz}, example=Example, code=Code}) -> diff --git a/lib/wx/examples/demo/ex_aui.erl b/lib/wx/examples/demo/ex_aui.erl index 6adfd970fc..50f077638d 100644 --- a/lib/wx/examples/demo/ex_aui.erl +++ b/lib/wx/examples/demo/ex_aui.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include("../../include/wx.hrl"). @@ -92,6 +92,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + %% Async Events are handled in handle_event as in handle_info handle_event(#wx{obj = Notebook, event = #wxCommand{type = command_button_clicked}}, diff --git a/lib/wx/examples/demo/ex_button.erl b/lib/wx/examples/demo/ex_button.erl index 28c8273cb9..0dd0363933 100644 --- a/lib/wx/examples/demo/ex_button.erl +++ b/lib/wx/examples/demo/ex_button.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,7 +26,7 @@ -behaviour(wx_object). -export([start/1, init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -record(state, { @@ -153,6 +153,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config,"Got Call ~p~n",[Msg]), {reply,ok,State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_canvas.erl b/lib/wx/examples/demo/ex_canvas.erl index 844c7eddf3..1ec4760f40 100644 --- a/lib/wx/examples/demo/ex_canvas.erl +++ b/lib/wx/examples/demo/ex_canvas.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2, handle_sync_event/3]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2, handle_sync_event/3]). -include_lib("wx/include/wx.hrl"). @@ -144,6 +144,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_canvas_paint.erl b/lib/wx/examples/demo/ex_canvas_paint.erl index 38d6b62f1d..9bc083766a 100644 --- a/lib/wx/examples/demo/ex_canvas_paint.erl +++ b/lib/wx/examples/demo/ex_canvas_paint.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2, handle_sync_event/3]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2, handle_sync_event/3]). -include_lib("wx/include/wx.hrl"). @@ -211,6 +211,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_choices.erl b/lib/wx/examples/demo/ex_choices.erl index 75f8d22493..2e456ae249 100644 --- a/lib/wx/examples/demo/ex_choices.erl +++ b/lib/wx/examples/demo/ex_choices.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -21,7 +21,7 @@ -behaviour(wx_object). -export([start/1, init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -147,6 +147,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config,"Got Call ~p\n",[Msg]), {reply, {error,nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_cursor.erl b/lib/wx/examples/demo/ex_cursor.erl index 322bdcbb6c..c1a558541b 100644 --- a/lib/wx/examples/demo/ex_cursor.erl +++ b/lib/wx/examples/demo/ex_cursor.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -135,6 +135,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_dialogs.erl b/lib/wx/examples/demo/ex_dialogs.erl index 020e9eeb14..b39344f8b1 100644 --- a/lib/wx/examples/demo/ex_dialogs.erl +++ b/lib/wx/examples/demo/ex_dialogs.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -153,6 +153,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_frame_utils.erl b/lib/wx/examples/demo/ex_frame_utils.erl index 3064c9f3b7..a90642b355 100644 --- a/lib/wx/examples/demo/ex_frame_utils.erl +++ b/lib/wx/examples/demo/ex_frame_utils.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -102,6 +102,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_gauge.erl b/lib/wx/examples/demo/ex_gauge.erl index d30c3fea58..ffc667ff05 100644 --- a/lib/wx/examples/demo/ex_gauge.erl +++ b/lib/wx/examples/demo/ex_gauge.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -23,7 +23,7 @@ -include_lib("wx/include/wx.hrl"). -export([start/1, init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -record(gauge, {obj, value, @@ -118,6 +118,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config,"Got Call ~p\n",[Msg]), {reply,ok, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + %% Async Events are handled in handle_event as in handle_info handle_event(#wx{id = ?ID_START_STOP, event = #wxCommand{type = command_togglebutton_clicked, diff --git a/lib/wx/examples/demo/ex_gl.erl b/lib/wx/examples/demo/ex_gl.erl index 53f1eda847..72dad2cf9d 100644 --- a/lib/wx/examples/demo/ex_gl.erl +++ b/lib/wx/examples/demo/ex_gl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -21,7 +21,7 @@ -behaviour(wx_object). -export([init/1, code_change/3, handle_info/2, handle_event/2, - handle_call/3, terminate/2, + handle_call/3, handle_cast/2, terminate/2, start/1]). -include_lib("wx/include/wx.hrl"). @@ -118,6 +118,10 @@ handle_call(Msg, _From, State) -> io:format("Got Call ~p~n",[Msg]), {reply,ok,State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, not_yet_implemented, State}. diff --git a/lib/wx/examples/demo/ex_graphicsContext.erl b/lib/wx/examples/demo/ex_graphicsContext.erl index bcd7a75be0..c356500d99 100644 --- a/lib/wx/examples/demo/ex_graphicsContext.erl +++ b/lib/wx/examples/demo/ex_graphicsContext.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,7 +26,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, handle_info/2, handle_call/3, - handle_event/2, handle_sync_event/3]). +handle_cast/2, handle_event/2, handle_sync_event/3]). -include_lib("wx/include/wx.hrl"). @@ -98,6 +98,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_grid.erl b/lib/wx/examples/demo/ex_grid.erl index 2169c818ff..d1a9952ab2 100644 --- a/lib/wx/examples/demo/ex_grid.erl +++ b/lib/wx/examples/demo/ex_grid.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -81,6 +81,10 @@ handle_info(_Msg, State) -> handle_call(_Msg, _From, State) -> {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_htmlWindow.erl b/lib/wx/examples/demo/ex_htmlWindow.erl index b864cd10b2..564c790e48 100644 --- a/lib/wx/examples/demo/ex_htmlWindow.erl +++ b/lib/wx/examples/demo/ex_htmlWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include("../../include/wx.hrl"). @@ -81,6 +81,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_listCtrl.erl b/lib/wx/examples/demo/ex_listCtrl.erl index 3faec4e229..13096dfa52 100644 --- a/lib/wx/examples/demo/ex_listCtrl.erl +++ b/lib/wx/examples/demo/ex_listCtrl.erl @@ -23,7 +23,7 @@ -behaviour(wx_object). -export([start/1, init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -record(state, { @@ -147,6 +147,11 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config,"Got Call ~p\n",[Msg]), {reply,ok,State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_notebook.erl b/lib/wx/examples/demo/ex_notebook.erl index 2e16ccfffa..fc38fdae08 100644 --- a/lib/wx/examples/demo/ex_notebook.erl +++ b/lib/wx/examples/demo/ex_notebook.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -23,7 +23,7 @@ -behaviour(wx_object). -export([start/1, init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -record(state, { @@ -133,6 +133,11 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config,"Got Call ~p\n",[Msg]), {reply,ok,State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_pickers.erl b/lib/wx/examples/demo/ex_pickers.erl index 892c5b449d..8013a5ba32 100644 --- a/lib/wx/examples/demo/ex_pickers.erl +++ b/lib/wx/examples/demo/ex_pickers.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -124,6 +124,11 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_popupMenu.erl b/lib/wx/examples/demo/ex_popupMenu.erl index 8774dbef7b..d6778c5dc5 100644 --- a/lib/wx/examples/demo/ex_popupMenu.erl +++ b/lib/wx/examples/demo/ex_popupMenu.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -90,6 +90,11 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_radioBox.erl b/lib/wx/examples/demo/ex_radioBox.erl index 8211aec4a2..ab7685f41f 100644 --- a/lib/wx/examples/demo/ex_radioBox.erl +++ b/lib/wx/examples/demo/ex_radioBox.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -21,7 +21,7 @@ -behaviour(wx_object). -export([start/1, init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -107,6 +107,9 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config,"Got Call ~p\n",[Msg]), {reply, {error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_sashWindow.erl b/lib/wx/examples/demo/ex_sashWindow.erl index dd05f4e45f..d8a8958f28 100644 --- a/lib/wx/examples/demo/ex_sashWindow.erl +++ b/lib/wx/examples/demo/ex_sashWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -116,6 +116,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_sizers.erl b/lib/wx/examples/demo/ex_sizers.erl index 2cc6efd503..7b9e8eb37f 100644 --- a/lib/wx/examples/demo/ex_sizers.erl +++ b/lib/wx/examples/demo/ex_sizers.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -101,6 +101,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_slider.erl b/lib/wx/examples/demo/ex_slider.erl index 7b669d96f6..612543ff26 100644 --- a/lib/wx/examples/demo/ex_slider.erl +++ b/lib/wx/examples/demo/ex_slider.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -21,7 +21,7 @@ -behaviour(wx_object). -export([start/1, init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -101,6 +101,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config,"Got Call ~p\n",[Msg]), {reply, {error, nyi},State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_splitterWindow.erl b/lib/wx/examples/demo/ex_splitterWindow.erl index c135f298fa..4f25b73293 100644 --- a/lib/wx/examples/demo/ex_splitterWindow.erl +++ b/lib/wx/examples/demo/ex_splitterWindow.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -90,6 +90,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_static.erl b/lib/wx/examples/demo/ex_static.erl index 67061520c4..013bd5ac35 100644 --- a/lib/wx/examples/demo/ex_static.erl +++ b/lib/wx/examples/demo/ex_static.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -105,6 +105,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_textCtrl.erl b/lib/wx/examples/demo/ex_textCtrl.erl index 95837c7c4c..d82884f30b 100644 --- a/lib/wx/examples/demo/ex_textCtrl.erl +++ b/lib/wx/examples/demo/ex_textCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -21,7 +21,7 @@ -behaviour(wx_object). -export([start/1, init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -92,6 +92,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config,"Got Call ~p\n",[Msg]), {reply, {error,nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/demo/ex_treeCtrl.erl b/lib/wx/examples/demo/ex_treeCtrl.erl index fa40795393..611904500a 100644 --- a/lib/wx/examples/demo/ex_treeCtrl.erl +++ b/lib/wx/examples/demo/ex_treeCtrl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,7 +25,7 @@ %% wx_object callbacks -export([init/1, terminate/2, code_change/3, - handle_info/2, handle_call/3, handle_event/2]). + handle_info/2, handle_call/3, handle_cast/2, handle_event/2]). -include_lib("wx/include/wx.hrl"). @@ -109,6 +109,10 @@ handle_call(Msg, _From, State) -> demo:format(State#state.config, "Got Call ~p\n", [Msg]), {reply,{error, nyi}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, ignore, State}. diff --git a/lib/wx/examples/sudoku/sudoku_board.erl b/lib/wx/examples/sudoku/sudoku_board.erl index 14e32f4782..4b26ff97da 100644 --- a/lib/wx/examples/sudoku/sudoku_board.erl +++ b/lib/wx/examples/sudoku/sudoku_board.erl @@ -30,7 +30,7 @@ draw/3, %% Callbacks init/1, handle_sync_event/3, - handle_event/2, handle_info/2, handle_call/3, + handle_event/2, handle_info/2, handle_call/3, handle_cast/2, code_change/3, terminate/2]). -include("sudoku.hrl"). @@ -209,6 +209,10 @@ handle_call({draw, DC, Size},_From, S) -> redraw(DC,Size,S), {reply, ok, S}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, not_yet_implemented, State}. diff --git a/lib/wx/examples/sudoku/sudoku_gui.erl b/lib/wx/examples/sudoku/sudoku_gui.erl index bbcfe8c466..3d0c95ffa7 100644 --- a/lib/wx/examples/sudoku/sudoku_gui.erl +++ b/lib/wx/examples/sudoku/sudoku_gui.erl @@ -24,7 +24,7 @@ %%%------------------------------------------------------------------- -module(sudoku_gui). --export([init/1, handle_info/2, handle_call/3, handle_event/2, +-export([init/1, handle_info/2, handle_call/3, handle_cast/2, handle_event/2, terminate/2, code_change/3]). -compile(export_all). @@ -230,6 +230,10 @@ handle_event(Msg,S) -> handle_call(What, _From, State) -> {stop, {call, What}, State}. +handle_cast(Msg, State) -> + io:format("Got cast ~p~n",[Msg]), + {noreply,State}. + code_change(_, _, State) -> {stop, not_yet_implemented, State}. diff --git a/lib/wx/src/Makefile b/lib/wx/src/Makefile index 46bc06271c..4e5971de03 100644 --- a/lib/wx/src/Makefile +++ b/lib/wx/src/Makefile @@ -18,7 +18,15 @@ # include ../vsn.mk -include ../config.mk +ifdef TERTIARY_BOOTSTRAP + VSN = $(WX_VSN) + INSIDE_ERLSRC = true + include $(ERL_TOP)/make/target.mk + include $(ERL_TOP)/make/$(TARGET)/otp.mk + RELSYSDIR = $(RELEASE_PATH)/lib/wx-$(VSN) +else # Normal build + include ../config.mk +endif ESRC = . EGEN = gen @@ -65,7 +73,11 @@ APPUP_SRC = $(APPUP_FILE).src APPUP_TARGET = $(EBIN)/$(APPUP_FILE) # Targets -debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) +ifdef TERTIARY_BOOTSTRAP + opt: $(EBIN)/wx_object.beam +else + debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) +endif clean: rm -f $(TARGET_FILES) diff --git a/lib/wx/src/wx_object.erl b/lib/wx/src/wx_object.erl index bc85cd93d4..80f8937656 100644 --- a/lib/wx/src/wx_object.erl +++ b/lib/wx/src/wx_object.erl @@ -108,7 +108,38 @@ get_pid/1 ]). --export([behaviour_info/1]). +%% -export([behaviour_info/1]). +-callback init(Args :: term()) -> + {#wx_ref{}, State :: term()} | {#wx_ref{}, State :: term(), timeout() | hibernate} | + {stop, Reason :: term()} | ignore. +-callback handle_event(Request :: #wx{}, State :: term()) -> + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate} | + {stop, Reason :: term(), NewState :: term()}. +-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()}, + State :: term()) -> + {reply, Reply :: term(), NewState :: term()} | + {reply, Reply :: term(), NewState :: term(), timeout() | hibernate} | + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate} | + {stop, Reason :: term(), Reply :: term(), NewState :: term()} | + {stop, Reason :: term(), NewState :: term()}. +-callback handle_cast(Request :: term(), State :: term()) -> + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate} | + {stop, Reason :: term(), NewState :: term()}. +-callback handle_info(Info :: timeout() | term(), State :: term()) -> + {noreply, NewState :: term()} | + {noreply, NewState :: term(), timeout() | hibernate} | + {stop, Reason :: term(), NewState :: term()}. +-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} | + term()), + State :: term()) -> + term(). +-callback code_change(OldVsn :: (term() | {down, term()}), State :: term(), + Extra :: term()) -> + {ok, NewState :: term()} | {error, Reason :: term()}. + %% System exports -export([system_continue/3, @@ -125,15 +156,15 @@ %%% API %%%========================================================================= %% @hidden -behaviour_info(callbacks) -> - [{init,1}, - {handle_call,3}, - {handle_info,2}, - {handle_event,2}, - {terminate,2}, - {code_change,3}]; -behaviour_info(_Other) -> - undefined. +%% behaviour_info(callbacks) -> +%% [{init,1}, +%% {handle_call,3}, +%% {handle_info,2}, +%% {handle_event,2}, +%% {terminate,2}, +%% {code_change,3}]; +%% behaviour_info(_Other) -> +%% undefined. %% ----------------------------------------------------------------- diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk index 8685c633d4..3f3e9422a8 100644 --- a/lib/wx/vsn.mk +++ b/lib/wx/vsn.mk @@ -1 +1 @@ -WX_VSN = 0.99 +WX_VSN = 0.99.1 diff --git a/lib/xmerl/doc/src/notes.xml b/lib/xmerl/doc/src/notes.xml index 15c42d6f6a..8734bd8771 100644 --- a/lib/xmerl/doc/src/notes.xml +++ b/lib/xmerl/doc/src/notes.xml @@ -31,6 +31,117 @@ <p>This document describes the changes made to the Xmerl application.</p> +<section><title>Xmerl 1.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> Fix character check of non-characters due to change + in unicode module. </p> + <p> + Own Id: OTP-9670</p> + </item> + <item> + <p> + Treat , as special in xmerl_xpath_scan. (Thanks to Anneli + Cuss)</p> + <p> + Own Id: OTP-9753</p> + </item> + <item> + <p> + Fix bug in namespace handling for attributes when the + <c>namespace_conformant</c> flag is set to true. </p> + <p> + Own Id: OTP-9821</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> Updates to the xml scanner </p> <list> <item> + <p>xmerl_scan is now returning xmlComment records in the + output.<br/><br/> Functions <c>xmerl_scan:file/2</c> and + <c>xmerl_scan:string/2</c> now accepts a new option + <c>{comments, Flag}</c> for filtering of comments.<br/> + Default (<c>true</c>) is that <c>#xmlComment</c> records + are returned from the scanner and this flag should be set + to false if one don't want comments in the output. </p> + </item> <item> <p>Add <i>default_attrs</i> + option<br/><br/> When <i>default_attrs</i> is <c>true</c> + any attribute with a default value defined in the doctype + but not in the attribute axis of the currently scanned + element is added to it. </p> </item> <item> <p>Allow + whole documents to be returned<br/><br/> Functions + <c>xmerl_scan:file/2</c> and <c>xmerl_scan:string/2</c> + now accepts a new option <c>{document, true}</c> to + produce a whole document as a <c>xmlDocument</c> record + instead of just the root element node.<br/> This option + is the only way to get to the top-level comments and + processing instructions without hooking through the + customization functions. Those nodes are needed to + implement [Canonical XML][c14n-xml] support.<br/> + [c14n-xml]: + http://www.w3.org/TR/2008/PR-xml-c14n11-20080129/ + <i>Canonical XML</i> </p> </item> <item><p>Parents and + namespace are tracked in <c>#xmlAttribute</c> + nodes</p></item> <item><p>Parents are tracked in + <c>#xmlPI</c> nodes</p></item> <item><p>Set <c>vsn</c> + field in <c>#xmlDecl</c> record</p></item> <item><p>Fix + namespace-conformance constraints<br/><br/> See + [Namespaces in XML 1.0 (Third Edition)][1]: The prefix + xml is by definition bound to the namespace name + http://www.w3.org/XML/1998/namespace. It MAY, but need + not, be declared, and MUST NOT be bound to any other + namespace name. Other prefixes MUST NOT be bound to this + namespace name, and it MUST NOT be declared as the + default namespace.<br/> The prefix xmlns is used only to + declare namespace bindings and is by definition bound to + the namespace name http://www.w3.org/2000/xmlns/. It MUST + NOT be declared . Other prefixes MUST NOT be bound to + this namespace name, and it MUST NOT be declared as the + default namespace. Element names MUST NOT have the prefix + xmlns.<br/> In XML documents conforming to this + specification, no tag may contain two attributes which + have identical names, or have qualified names with the + same local part and with prefixes which have been bound + to namespace names that are identical.<br/> [1] + http://www.w3.org/TR/REC-xml-names/ </p></item> </list> + <p> Updates of xmerl's Xpath functionality. </p> <list> + <item><p>Add <c>#xmlPI</c> support to + xmerl_xpath:write_node/1</p></item> <item><p>Fix + processing-instruction(name?)</p></item> <item><p>Fix + path filters, support more top-level primary + expressions</p></item> <item><p>Accumulate comments in + element nodes</p></item> <item><p>Implement namespace + axis<br/><br/> Namespace nodes are represented as + <c>#xmlNsNode</c> records. Now that the namespace axis is + correctly implemented, attributes nodes corresponding to + attributes that declare namespaces are ignored.<br/> See + [5.3 Attribute Nodes][xpath-5.3]:<br/> There are no + attribute nodes corresponding to attributes that declare + namespaces.<br/> [xpath-5.3]: + http://www.w3.org/TR/xpath/#attribute-nodes </p></item> + </list> <p> (Thanks to Anthony Ramine) </p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9664</p> + </item> + <item> + <p> + Eliminate use of deprecated regexp module</p> + <p> + Own Id: OTP-9810</p> + </item> + </list> + </section> + +</section> + <section><title>Xmerl 1.2.10</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/xmerl/doc/src/xmerl_ug.xmlsrc b/lib/xmerl/doc/src/xmerl_ug.xmlsrc index 6ee6707e53..9ef8fbb0b9 100644 --- a/lib/xmerl/doc/src/xmerl_ug.xmlsrc +++ b/lib/xmerl/doc/src/xmerl_ug.xmlsrc @@ -36,9 +36,9 @@ <title>Features</title> <p>The <em>xmerl</em> XML parser is able to parse XML documents according to the XML 1.0 standard. As default it performs - well-formed parsing,(syntax checks and checks of well-formed + well-formed parsing, (syntax checks and checks of well-formed constraints). Optionally one can also use xmerl as a validating - parser,(validate according to referenced DTD and validating + parser, (validate according to referenced DTD and validating constraints). By means of for example the xmerl_xs module it is possible to transform the parsed result to other formats, e.g. text, HTML, XML etc.</p> diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl index ec7ea534d6..05431a5fd2 100644 --- a/lib/xmerl/src/xmerl_scan.erl +++ b/lib/xmerl/src/xmerl_scan.erl @@ -20,8 +20,8 @@ %% Description : Simgle-pass XML scanner. See xmerl.hrl for data defs. %% @doc This module is the interface to the XML parser, it handles XML 1.0. -%% The XML parser is activated through -%% <tt>xmerl_scan:string/[1,2]</tt> or +%% The XML parser is activated through +%% <tt>xmerl_scan:string/[1,2]</tt> or %% <tt>xmerl_scan:file/[1,2]</tt>. %% It returns records of the type defined in xmerl.hrl. %% See also <a href="xmerl_examples.html">tutorial</a> on customization @@ -79,15 +79,15 @@ %% <dt><code>{validation, Flag}</code></dt> %% <dd>Controls whether to process as a validating XML parser: %% 'off' (default) no validation, or validation 'dtd' by DTD or 'schema' -%% by XML Schema. 'false' and 'true' options are obsolete -%% (i.e. they may be removed in a future release), if used 'false' +%% by XML Schema. 'false' and 'true' options are obsolete +%% (i.e. they may be removed in a future release), if used 'false' %% equals 'off' and 'true' equals 'dtd'.</dd> %% <dt><code>{schemaLocation, [{Namespace,Link}|...]}</code></dt> -%% <dd>Tells explicitly which XML Schema documents to use to validate -%% the XML document. Used together with the +%% <dd>Tells explicitly which XML Schema documents to use to validate +%% the XML document. Used together with the %% <code>{validation,schema}</code> option.</dd> %% <dt><code>{quiet, Flag}</code></dt> -%% <dd>Set to 'true' if xmerl should behave quietly and not output any +%% <dd>Set to 'true' if xmerl should behave quietly and not output any %% information to standard output (default 'false').</dd> %% <dt><code>{doctype_DTD, DTD}</code></dt> %% <dd>Allows to specify DTD name when it isn't available in the XML @@ -275,7 +275,7 @@ int_file_decl(F, Options,_ExtCharset) -> %% @spec string(Text::list()) -> {xmlElement(),Rest} %% Rest = list() %% @equiv string(Test, []) -string(Str) -> +string(Str) -> string(Str, []). %% @spec string(Text::list(),Options::option_list()) -> {document(),Rest} @@ -306,7 +306,7 @@ int_string(Str, Options, XMLBase, FileName) -> scan_document(Str2, S#xmerl_scanner{encoding="iso-10646-utf-1"}); {undefined,undefined,Str2} -> %% no auto detection scan_document(Str2, S); - {external,ExtCharset,Str2} -> + {external,ExtCharset,Str2} -> %% no auto detection, ExtCharset is an explicitly provided %% 7 bit,8 bit or utf-8 encoding scan_document(Str2, S#xmerl_scanner{encoding=atom_to_list(ExtCharset)}) @@ -325,7 +325,7 @@ int_string_decl(Str, Options, XMLBase, FileName) -> {external,ExtCharset,Str2} -> scan_decl(Str2, S#xmerl_scanner{encoding=atom_to_list(ExtCharset)}) end. - + initial_state0(Options,XMLBase) -> @@ -386,7 +386,7 @@ initial_state([{line, L}|T], S) -> initial_state(T, S#xmerl_scanner{line = L}); initial_state([{namespace_conformant, F}|T], S) when F==true; F==false -> initial_state(T, S#xmerl_scanner{namespace_conformant = F}); -initial_state([{validation, F}|T], S) +initial_state([{validation, F}|T], S) when F==off; F==dtd; F==schema; F==true; F==false -> initial_state(T, S#xmerl_scanner{validation = validation_value(F)}); initial_state([{schemaLocation, SL}|T], S) when is_list(SL) -> @@ -422,7 +422,7 @@ validation_value(false) -> validation_value(F) -> F. -%% Used for compacting (some) indentations. +%% Used for compacting (some) indentations. %% See also fast_accumulate_whitespace(). common_data() -> {comdata(lists:duplicate(60, $\s), []), @@ -465,7 +465,7 @@ event(_X, S) -> %% where Pos' can be derived from X#xmlElement.pos, X#xmlText.pos, or %% X#xmlAttribute.pos (whichever is the current object type.) %% The acc/3 function is not allowed to redefine the type of object -%% being defined, but _is_ allowed to either ignore it or split it +%% being defined, but _is_ allowed to either ignore it or split it %% into multiple objects (in which case {Acc',Pos',S'} should be returned.) %% If {Acc',S'} is returned, Pos will be incremented by 1 by default. %% Below is an example of an acceptable operation @@ -488,10 +488,10 @@ fetch_URI(URI, S) -> %% assume URI is a filename Split = filename:split(URI), Filename = fun([])->[];(X)->lists:last(X) end (Split), - Fullname = + Fullname = case Split of %% how about Windows systems? ["file:"|Name]-> %% absolute path, see RFC2396 sect 3 - %% file:/dtd_name + %% file:/dtd_name filename:join(["/"|Name]); ["/"|Rest] when Rest /= [] -> %% absolute path name @@ -544,9 +544,9 @@ scan_document(Str0, S=#xmerl_scanner{event_fun = Event, line = L, col = C, data = document}, S), - + %% Transform to given character set. - %% Note that if another character set is given in the encoding + %% Note that if another character set is given in the encoding %% attribute in a XML declaration that one will be used later Str=if Charset == "utf-8" -> @@ -573,7 +573,7 @@ scan_document(Str0, S=#xmerl_scanner{event_fun = Event, {Misc, _Pos1, Tail, S4}=scan_misc(T3, S3, Pos + 1), %% M5 = erlang:memory(), %% io:format("Memory status after misc: ~p~n",[M5]), - + S5 = #xmerl_scanner{} = Event(#xmerl_event{event = ended, line = S4#xmerl_scanner.line, col = S4#xmerl_scanner.col, @@ -636,7 +636,7 @@ scan_decl(Str, S=#xmerl_scanner{event_fun = Event, line = L, col = C, data = document}, S), - + case scan_prolog(Str, S1, _StartPos = 1) of {_,_,T2="<"++_, S2} -> {{S2#xmerl_scanner.user_state,T2},[],S2}; @@ -665,14 +665,14 @@ scan_prolog("<?xml"++T, Pos,Acc) when ?whitespace(hd(T)) -> {Charset, T3, S3} = if - Col==1,L==1,S0#xmerl_scanner.text_decl==true -> + Col==1,L==1,S0#xmerl_scanner.text_decl==true -> ?dbg("prolog(\"<?xml\")~n", []), ?bump_col(5), {_,T1,S1} = mandatory_strip(T,S), {Decl,T2, S2}=scan_text_decl(T1,S1), Encoding=Decl#xmlDecl.encoding, {Encoding, T2, S2#xmerl_scanner{encoding=Encoding}}; - Col==1,L==1 -> + Col==1,L==1 -> ?dbg("prolog(\"<?xml\")~n", []), ?bump_col(5), {Decl,T2, S2}=scan_xml_decl(T, S), @@ -728,7 +728,7 @@ scan_prolog(Str="%"++_T,S=#xmerl_scanner{environment={external,_}}, scan_prolog(Str, S0 = #xmerl_scanner{user_state=_US,encoding=_Charset}, Pos,Acc) -> ?dbg("prolog(\"<\")~n", []), - + %% Check for Comments, PI before possible DOCTYPE declaration ?bump_col(1), %% If no known character set assume it is UTF-8 @@ -759,7 +759,7 @@ scan_prolog2(Str = "<!" ++ _, S, Pos, Acc) -> {Acc, Pos, T, S1}; scan_prolog2(Str, S0 = #xmerl_scanner{user_state=_US},Pos,Acc) -> ?dbg("prolog(\"<\")~n", []), - + %% Here we consider the DTD provided by doctype_DTD option, S1 = case S0 of @@ -793,7 +793,7 @@ scan_misc("<!--" ++ T, S0=#xmerl_scanner{acc_fun = F, comments=CF}, Pos, Acc) -> {C, T1, S1} = scan_comment(T, S, Pos, _Parents = [], _Lang = []), case CF of true -> - {Acc2, Pos2, S3} = + {Acc2, Pos2, S3} = case F(C, Acc, S1) of {Acc1, S2} -> {Acc1, Pos + 1, S2}; @@ -838,7 +838,7 @@ scan_xml_decl(T, S) -> {_,T1,S1} = mandatory_strip(T,S), {T2,S2} = case T1 of - "version" ++ _T2 -> + "version" ++ _T2 -> {_T2,S1#xmerl_scanner{col=S1#xmerl_scanner.col+7}}; _ -> ?fatal(expected_version_attribute,S1) end, @@ -879,8 +879,8 @@ scan_xml_decl2("encoding" ++ T, S0 = #xmerl_scanner{event_fun = Event}, value = LowEncName}, Decl = Decl0#xmlDecl{encoding = LowEncName, attributes = [Attr|Attrs]}, - S3 = #xmerl_scanner{} = Event(#xmerl_event{event = ended, - line = S0#xmerl_scanner.line, + S3 = #xmerl_scanner{} = Event(#xmerl_event{event = ended, + line = S0#xmerl_scanner.line, col = S0#xmerl_scanner.col, data = Attr}, S2), case T2 of @@ -902,7 +902,7 @@ scan_xml_decl3("?>" ++ T, S0,Decl) -> return_xml_decl(T,S,Decl); scan_xml_decl3("standalone" ++ T,S0 = #xmerl_scanner{event_fun = Event}, Decl0 = #xmlDecl{attributes = Attrs}) -> - %% [32] SDDecl + %% [32] SDDecl ?bump_col(10), {T1, S1} = scan_eq(T, S), {StValue,T2,S2}=scan_standalone_value(T1,S1), @@ -911,8 +911,8 @@ scan_xml_decl3("standalone" ++ T,S0 = #xmerl_scanner{event_fun = Event}, value = StValue}, Decl = Decl0#xmlDecl{standalone = StValue, attributes = [Attr|Attrs]}, - S3 = #xmerl_scanner{} = Event(#xmerl_event{event = ended, - line = S0#xmerl_scanner.line, + S3 = #xmerl_scanner{} = Event(#xmerl_event{event = ended, + line = S0#xmerl_scanner.line, col = S0#xmerl_scanner.col, data = Attr}, S2), {_,T3,S4} = strip(T2,S3), @@ -933,7 +933,7 @@ return_xml_decl(T,S=#xmerl_scanner{hook_fun = _Hook, %% {Ret, S3} = Hook(Decl, S2), %% {Ret, T1, S3}. {Decl, T1, S2}. - + scan_standalone_value("'yes'" ++T,S0)-> ?bump_col(5), @@ -976,7 +976,7 @@ scan_text_decl(T,S=#xmerl_scanner{event_fun = Event}) -> scan_text_decl(T5,S6,Decl). scan_text_decl("?>"++T,S0 = #xmerl_scanner{hook_fun = _Hook, - event_fun = Event}, + event_fun = Event}, Decl0 = #xmlDecl{attributes = Attrs}) -> ?bump_col(2), ?strip1, @@ -1001,7 +1001,7 @@ scan_optional_version("version"++T,S0) -> {#xmlDecl{attributes=[Attr]},T4,S4}; scan_optional_version(T,S) -> {#xmlDecl{attributes=[]},T,S}. - + %%%%%%% [81] EncName @@ -1010,7 +1010,7 @@ scan_enc_name([], S=#xmerl_scanner{continuation_fun = F}) -> F(fun(MoreBytes, S1) -> scan_enc_name(MoreBytes, S1) end, fun(S1) -> ?fatal(expected_encoding_name, S1) end, S); -scan_enc_name([H|T], S0) when H >= $"; H =< $' -> +scan_enc_name([H|T], S0) when H >= $"; H =< $' -> ?bump_col(1), scan_enc_name(T, S, H, []). @@ -1063,7 +1063,7 @@ scan_xml_vsn([H|T], S) when H==$"; H==$'-> xml_vsn([], S=#xmerl_scanner{continuation_fun = F}, Delim, Acc) -> ?dbg("cont()...~n", []), - F(fun(MoreBytes, S1) -> xml_vsn(MoreBytes, S1, Delim, Acc) end, + F(fun(MoreBytes, S1) -> xml_vsn(MoreBytes, S1, Delim, Acc) end, fun(S1) -> ?fatal(unexpected_end, S1) end, S); xml_vsn([H|T], S=#xmerl_scanner{col = C}, H, Acc) -> @@ -1093,7 +1093,7 @@ scan_pi(Str = [H1,H2,H3 | T],S0=#xmerl_scanner{line = L, col = C}, Pos, Ps) when H1==$x;H1==$X -> %% names beginning with [xX][mM][lL] are reserved for future use. ?bump_col(3), - if + if ((H2==$m) or (H2==$M)) and ((H3==$l) or (H3==$L)) -> scan_wellknown_pi(T,S,Pos,Ps); @@ -1126,7 +1126,7 @@ scan_pi([], S=#xmerl_scanner{continuation_fun = F}, Target, fun(S1) -> ?fatal(unexpected_end, S1) end, S); scan_pi("?>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook, - event_fun = Event}, + event_fun = Event}, Target, L, C, Pos, Ps, Acc) -> ?bump_col(2), PI = #xmlPI{name = Target, @@ -1153,7 +1153,7 @@ scan_pi2([], S=#xmerl_scanner{continuation_fun = F}, Target, fun(S1) -> ?fatal(unexpected_end, S1) end, S); scan_pi2("?>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook, - event_fun = Event}, + event_fun = Event}, Target, L, C, Pos, Ps, Acc) -> ?bump_col(2), PI = #xmlPI{name = Target, @@ -1173,7 +1173,7 @@ scan_pi2(Str, S0, Target, L, C, Pos, Ps, Acc) -> -%% [28] doctypedecl ::= +%% [28] doctypedecl ::= %% '<!DOCTYPE' S Name (S ExternalID)? S? ('[' intSubset ']' S?)? '>' scan_doctype([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), @@ -1279,7 +1279,7 @@ fetch_DTD(undefined, S) -> S; % fetch_DTD(_,S=#xmerl_scanner{validation=false}) -> % S; -fetch_DTD(DTDSpec, S)-> +fetch_DTD(DTDSpec, S)-> case fetch_and_parse(DTDSpec,S,[{text_decl,true}, {environment,{external,subset}}]) of NewS when is_record(NewS,xmerl_scanner) -> @@ -1294,7 +1294,7 @@ fetch_and_parse(ExtSpec,S=#xmerl_scanner{fetch_fun=Fetch, Options0) -> RetS = case Fetch(ExtSpec, S) of - {ok, NewS} -> + {ok, NewS} -> %% For backward compatibility only. This will be removed later!! NewS; {ok, not_fetched,NewS} -> @@ -1359,7 +1359,7 @@ fetch_not_parse(ExtSpec,S=#xmerl_scanner{fetch_fun=Fetch}) -> {ok, DataRet, NewS} -> {String,LocationName} = case DataRet of - {file,F} -> + {file,F} -> {get_file(F,S),F}; {string,Str} -> {binary_to_list(Str),file_name_unknown}; @@ -1375,7 +1375,7 @@ fetch_not_parse(ExtSpec,S=#xmerl_scanner{fetch_fun=Fetch}) -> get_file(F,S) -> % io:format("get_file F=~p~n",[F]), case file:read_file(F) of - {ok,Bin} -> + {ok,Bin} -> binary_to_list(Bin); Err -> ?fatal({error_reading_file,F,Err},S) @@ -1390,7 +1390,7 @@ check_decl(#xmerl_scanner{rules=Tab} = S) -> check_notations(Tab,S), check_elements(Tab,S), %% check also attribute defs for element check_entities(Tab,S). - + check_notations(Tab,S) -> case ets:match(Tab,{{notation,'$1'},undeclared}) of [[]] -> ok; @@ -1439,7 +1439,7 @@ check_attributes([{N1,'ID',_,_,_}=Attr|Rest],S) -> check_attributes([{_,{enumeration,_},_,_,_}=Attr|T],S) -> vc_Enumeration(Attr,S), check_attributes(T,S); -check_attributes([{_,Ent,_,_,_}=Attr|T],S) +check_attributes([{_,Ent,_,_,_}=Attr|T],S) when Ent=='ENTITY';Ent=='ENTITIES' -> vc_Entity_Name(Attr,S), check_attributes(T,S); @@ -1483,7 +1483,7 @@ scan_ext_subset([], S=#xmerl_scanner{continuation_fun = F}) -> F(fun(MoreBytes, S1) -> scan_ext_subset(MoreBytes, S1) end, fun(S1) -> {[], S1} end, S); -scan_ext_subset("%" ++ T, S0) -> +scan_ext_subset("%" ++ T, S0) -> %% DeclSep [28a]: WFC: PE Between Declarations. %% The replacement text of a parameter entity reference in a %% DeclSep must match the production extSubsetDecl. @@ -1537,7 +1537,7 @@ scan_decl_sep(T,S) -> % {" " ++ EntV2 ++ " ",_S3}; % ExpRef -> % {ExpRef,S1} -% end, +% end, % {_, T3, S3} = strip(ExpandedRef,S2), % {_T4,S4} = scan_ext_subset(T3,S3), % strip(T1,S4). @@ -1623,7 +1623,7 @@ scan_include(T, S) -> scan_include(T1, S1). -%%%%%%% [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl | +%%%%%%% [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl | %%%%%%% NotationDecl | PI |Comment %%%%%%% [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>' @@ -1642,14 +1642,14 @@ scan_markup_decl("<?" ++ T, S0) -> ?bump_col(2), {_PI, T1, S1} = scan_pi(T, S,_Pos=markup,[]), strip(T1, S1); -scan_markup_decl("<!ELEMENT" ++ T, +scan_markup_decl("<!ELEMENT" ++ T, #xmerl_scanner{rules_read_fun = Read, rules_write_fun = Write, rules_delete_fun = Delete} = S0) -> ?bump_col(9), {_,T1,S1} = mandatory_strip(T,S), {Ename, _NamespaceInfo, T2, S2} = scan_name(T1, S1), - Element = + Element = case Read(elem_def, Ename, S2) of El = #xmlElement{elementdef=Decl} when Decl =/= undeclared -> case S2#xmerl_scanner.validation of @@ -1690,7 +1690,7 @@ scan_markup_decl("<!NOTATION" ++ T, S0) -> {_,T1,S1} = mandatory_strip(T,S), {T2, S2} = scan_notation_decl(T1, S1), strip(T2,S2); -scan_markup_decl("<!ATTLIST" ++ T, +scan_markup_decl("<!ATTLIST" ++ T, #xmerl_scanner{rules_read_fun = Read, rules_write_fun = Write, rules_delete_fun= Delete} = S0) -> @@ -1707,7 +1707,7 @@ scan_markup_decl("<!ATTLIST" ++ T, %% internal DTD. {#xmlElement{},update_attributes(Attributes,[])}; Edef = #xmlElement{attributes = OldAttrs} -> - Delete(elem_def,Ename,S4), + Delete(elem_def,Ename,S4), %% the slot in rules table must be empty so that the %% later write has the assumed effect. Read maybe %% should empty the table slot. @@ -1726,7 +1726,7 @@ scan_element_completion(T,S) -> update_attributes(NewAttrs, OldAttrs) -> update_attributes1(NewAttrs,lists:reverse(OldAttrs)). -update_attributes1([A = {Name,_Type,_DefaultV,_DefaultD,_Env}|Attrs], +update_attributes1([A = {Name,_Type,_DefaultV,_DefaultD,_Env}|Attrs], OldAttrs) -> case lists:keymember(Name, 1, OldAttrs) of true -> @@ -1867,7 +1867,7 @@ scan_notation_type("|" ++ T, S0, Acc) -> ?strip3, scan_notation_type(T3, S3, [Name | Acc]). -%%% Validity constraint for NotationType: +%%% Validity constraint for NotationType: %%% The used notation names must be declared in the DTD, but they may %%% be declared later. notation_exists(Name, #xmerl_scanner{rules_read_fun = Read, @@ -1996,7 +1996,7 @@ scan_entity_def(Str, S, EName) -> {environment,{external,{entity,EName}}}]) of {{_USret,Entity},_Tail,_Sx} -> {Entity, external,T2, S2}; - {Entity,_Tail,Sx} -> + {Entity,_Tail,Sx} -> OldRef=S2#xmerl_scanner.entity_references, NewRef=Sx#xmerl_scanner.entity_references, {Entity,external,T2, @@ -2048,26 +2048,26 @@ scan_element(T, S=#xmerl_scanner{line=L,col=C}, {Name, NamespaceInfo, T1, S1} = scan_name(T, S), vc_Element_valid(Name,NamespaceInfo,S), ?strip2, - scan_element(T2, S2, Pos, Name, L, C, _Attrs = [], - Lang, Parents, NamespaceInfo, NS, + scan_element(T2, S2, Pos, Name, L, C, _Attrs = [], + Lang, Parents, NamespaceInfo, NS, SpaceDefault). scan_element("/", S=#xmerl_scanner{continuation_fun = F}, - Pos, Name, StartL, StartC, Attrs, Lang, Parents, + Pos, Name, StartL, StartC, Attrs, Lang, Parents, NSI, NS, SpaceDefault) -> ?dbg("trailing / detected~n", []), - F(fun(MoreBytes, S1) -> scan_element("/" ++ MoreBytes, S1, - Pos, Name, StartL, StartC, Attrs, + F(fun(MoreBytes, S1) -> scan_element("/" ++ MoreBytes, S1, + Pos, Name, StartL, StartC, Attrs, Lang,Parents,NSI,NS,SpaceDefault) end, fun(S1) -> ?fatal(unexpected_end, S1) end, S); -scan_element([], S=#xmerl_scanner{continuation_fun = F}, - Pos, Name, StartL, StartC, Attrs, Lang, Parents, +scan_element([], S=#xmerl_scanner{continuation_fun = F}, + Pos, Name, StartL, StartC, Attrs, Lang, Parents, NSI, NS, SpaceDefault) -> ?dbg("cont()...~n", []), - F(fun(MoreBytes, S1) -> scan_element(MoreBytes, S1, - Pos, Name, StartL, StartC, Attrs, + F(fun(MoreBytes, S1) -> scan_element(MoreBytes, S1, + Pos, Name, StartL, StartC, Attrs, Lang,Parents,NSI,NS,SpaceDefault) end, fun(S1) -> ?fatal(unexpected_end, S1) end, S); @@ -2075,12 +2075,12 @@ scan_element("/>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook, event_fun = Event, line = L, col = C, xmlbase_cache=XMLBase}, Pos, - Name, _StartL, _StartC, Attrs0, Lang, Parents, NSI, + Name, _StartL, _StartC, Attrs0, Lang, Parents, NSI, Namespace, _SpaceDefault) -> ?bump_col(2), Attrs = lists:reverse(Attrs0), E=processed_whole_element(S, Pos, Name, Attrs, Lang, Parents,NSI,Namespace), - + #xmlElement{attributes = Attrs1} = E, wfc_unique_att_spec(Attrs1,S), S1 = #xmerl_scanner{} = Event(#xmerl_event{event = ended, @@ -2091,11 +2091,11 @@ scan_element("/>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook, S2b=S2#xmerl_scanner{xmlbase=XMLBase}, {Ret, T, S2b}; scan_element(">", S=#xmerl_scanner{continuation_fun = F}, - Pos, Name, StartL, StartC, Attrs, Lang, Parents, + Pos, Name, StartL, StartC, Attrs, Lang, Parents, NSI, NS, SpaceDefault) -> ?dbg("trailing > detected~n", []), - F(fun(MoreBytes, S1) -> scan_element(">" ++ MoreBytes, S1, - Pos, Name, StartL, StartC, Attrs, + F(fun(MoreBytes, S1) -> scan_element(">" ++ MoreBytes, S1, + Pos, Name, StartL, StartC, Attrs, Lang,Parents,NSI,NS,SpaceDefault) end, fun(S1) -> ?fatal(unexpected_end, S1) end, S); @@ -2104,28 +2104,31 @@ scan_element(">" ++ T, S0 = #xmerl_scanner{event_fun = Event, line = L, col = C, xmlbase_cache=XMLBase, space = SpaceOption}, - Pos, Name, StartL, StartC, Attrs0, Lang, Parents, + Pos, Name, StartL, StartC, Attrs0, Lang, Parents, NSI, Namespace, SpaceDefault) -> ?bump_col(1), Attrs = lists:reverse(Attrs0), - wfc_unique_att_spec(Attrs,S), - XMLSpace = case lists:keysearch('xml:space', #xmlAttribute.name, Attrs) of + E0=processed_whole_element(S,Pos,Name,Attrs,Lang,Parents,NSI,Namespace), + + #xmlElement{attributes = Attrs1} = E0, + wfc_unique_att_spec(Attrs1,S), + XMLSpace = case lists:keysearch('xml:space', #xmlAttribute.name, Attrs1) of false -> SpaceDefault; {value, #xmlAttribute{value="default"}} -> SpaceOption; {value, #xmlAttribute{value="preserve"}} -> preserve; _ -> SpaceDefault end, - - E0=processed_whole_element(S,Pos,Name,Attrs,Lang,Parents,NSI,Namespace), + + E0=processed_whole_element(S,Pos,Name,Attrs1,Lang,Parents,NSI,Namespace), S1 = #xmerl_scanner{} = Event(#xmerl_event{event = started, line = StartL, col = StartC, data = E0}, S), - - {Content, T1, S2} = scan_content(T, S1, Name, Attrs, XMLSpace, + + {Content, T1, S2} = scan_content(T, S1, Name, Attrs1, XMLSpace, E0#xmlElement.language, [{Name, Pos}|Parents], Namespace), - + Element=E0#xmlElement{content=Content, xmlbase=E0#xmlElement.xmlbase}, S3 = #xmerl_scanner{} = Event(#xmerl_event{event = ended, @@ -2135,7 +2138,7 @@ scan_element(">" ++ T, S0 = #xmerl_scanner{event_fun = Event, {Ret, S4} = Hook(Element, S3), S4b=S4#xmerl_scanner{xmlbase=XMLBase}, {Ret, T1, S4b}; -scan_element(T, S, Pos, Name, StartL, StartC, Attrs, Lang, Parents, +scan_element(T, S, Pos, Name, StartL, StartC, Attrs, Lang, Parents, NSI, NS, SpaceDefault) -> {AttName, NamespaceInfo, T1, S1} = scan_name(T, S), {T2, S2} = scan_eq(T1, S1), @@ -2144,14 +2147,14 @@ scan_element(T, S, Pos, Name, StartL, StartC, Attrs, Lang, Parents, %% check_default_value(S3,DefaultDecl,AttValue), NewNS = check_namespace(AttName, NamespaceInfo, AttValue, NS), {T3,S3} = wfc_whitespace_betw_attrs(T3a,S3a), - ?strip4, + ?strip4, AttrPos = case Attrs of [] -> 1; [#xmlAttribute{pos = P}|_] -> P+1 end, - Attr = #xmlAttribute{name = AttName, + Attr = #xmlAttribute{name = AttName, parents = [{Name, Pos}|Parents], pos = AttrPos, language = Lang, @@ -2161,10 +2164,10 @@ scan_element(T, S, Pos, Name, StartL, StartC, Attrs, Lang, Parents, XMLBase=if AttName=='xml:base' -> resolve_relative_uri(AttValue,S4#xmerl_scanner.xmlbase); - true -> + true -> S4#xmerl_scanner.xmlbase end, - + #xmerl_scanner{event_fun = Event, line = Line, col = Col} = S4, @@ -2174,7 +2177,7 @@ scan_element(T, S, Pos, Name, StartL, StartC, Attrs, Lang, Parents, data = Attr}, S4#xmerl_scanner{xmlbase=XMLBase, xmlbase_cache=S#xmerl_scanner.xmlbase}), - scan_element(T4, S5, Pos, Name, StartL, StartC, [Attr|Attrs], + scan_element(T4, S5, Pos, Name, StartL, StartC, [Attr|Attrs], Lang, Parents, NSI, NewNS, SpaceDefault). get_default_attrs(S = #xmerl_scanner{rules_read_fun = Read}, ElemName) -> @@ -2210,7 +2213,7 @@ resolve_relative_uri(NewBase,CurrentBase) -> processed_whole_element(S=#xmerl_scanner{hook_fun = _Hook, xmlbase = XMLBase, line = _L, col = _C, - event_fun = _Event}, + event_fun = _Event}, Pos, Name, Attrs, Lang, Parents, NSI, Namespace) -> Language = check_language(Attrs, Lang), @@ -2231,7 +2234,7 @@ processed_whole_element(S=#xmerl_scanner{hook_fun = _Hook, Attrs end, - {ExpName, ExpAttrs} = + {ExpName, ExpAttrs} = case S#xmerl_scanner.namespace_conformant of true -> %% expand attribute names. We need to do this after having @@ -2243,11 +2246,11 @@ processed_whole_element(S=#xmerl_scanner{hook_fun = _Hook, %% should apply to those attributes as well. %% Note that the default URI does not apply to attrbute names. TempNamespace = Namespace#xmlNamespace{default = []}, - ExpAttrsX = + ExpAttrsX = [A#xmlAttribute{ namespace=Namespace, expanded_name=expanded_name( - A#xmlAttribute.name, + A#xmlAttribute.name, A#xmlAttribute.nsinfo, % NSI, TempNamespace, S)} || A <- AllAttrs], @@ -2277,7 +2280,7 @@ check_language([], Lang) -> check_namespace(xmlns, _, Value, NS) -> NS#xmlNamespace{default = list_to_atom(Value)}; -check_namespace(_, {"xmlns", Prefix}, Value, +check_namespace(_, {"xmlns", Prefix}, Value, NS = #xmlNamespace{nodes = Ns}) -> NS#xmlNamespace{nodes = keyreplaceadd( Prefix, 1, Ns, {Prefix, list_to_atom(Value)})}; @@ -2322,7 +2325,7 @@ expanded_name(_Name, {Prefix, Local}, #xmlNamespace{nodes = Ns}, S) -> %% must be declared ?fatal({namespace_prefix_not_declared, Prefix}, S) end. - + @@ -2348,7 +2351,7 @@ scan_att_value("%"++T,S0=#xmerl_scanner{rules_read_fun=Read, rules_delete_fun=Delete},AttType) -> ?bump_col(1), {Name,T1,S1} = scan_pe_reference(T,S), - {ExpandedRef,S2} = + {ExpandedRef,S2} = case expand_pe_reference(Name,S1,in_literal) of Tuple when is_tuple(Tuple) -> %% {system,URI} or {public,URI} @@ -2386,9 +2389,9 @@ scan_att_chars([H|T], S0, H, Acc, TmpAcc,AttType,IsNorm) -> % End quote ?bump_col(1), check_att_default_val(S#xmerl_scanner.validation,TmpAcc,AttType,S), {Acc2,S2,IsNorm2} = - if + if AttType == 'CDATA' -> {Acc,S,IsNorm}; - true -> + true -> normalize(Acc,S,IsNorm) end, {lists:flatten(lists:reverse(Acc2)), T, S2,IsNorm2}; @@ -2443,7 +2446,7 @@ check_att_default_val(dtd,RevName,Ent,S) -> check_att_default_val(_,_,_,_) -> ok. -check_att_default_val(Name,Ent,S=#xmerl_scanner{rules_write_fun=Write}) +check_att_default_val(Name,Ent,S=#xmerl_scanner{rules_write_fun=Write}) when Ent == 'ENTITY'; Ent == 'ENTITIES' -> case xmerl_lib:is_letter(hd(Name)) of true -> ok; @@ -2504,28 +2507,28 @@ valid_Char(_,_,C,S) -> %%%%%%% [43] content scan_content(T, S, Name, Attrs, Space, Lang, Parents, NS) -> - scan_content(T, S, _Pos = 1, Name, Attrs, Space, + scan_content(T, S, _Pos = 1, Name, Attrs, Space, Lang, Parents, NS, _Acc = [],_MarkupDel=[]). scan_content("<", S= #xmerl_scanner{continuation_fun = F}, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,_) -> ?dbg("trailing < detected~n", []), - F(fun(MoreBytes, S1) -> scan_content("<" ++ MoreBytes, S1, - Pos, Name, Attrs, + F(fun(MoreBytes, S1) -> scan_content("<" ++ MoreBytes, S1, + Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) end, fun(S1) -> ?fatal(unexpected_end, S1) end, S); -scan_content([], S=#xmerl_scanner{environment={external,{entity,_}}}, +scan_content([], S=#xmerl_scanner{environment={external,{entity,_}}}, _Pos, _Name, _Attrs, _Space, _Lang, _Parents, _NS, Acc,_) -> {lists:reverse(Acc),[],S}; -scan_content([], S=#xmerl_scanner{environment=internal_parsed_entity}, +scan_content([], S=#xmerl_scanner{environment=internal_parsed_entity}, _Pos, _Name, _Attrs, _Space, _Lang, _Parents, _NS, Acc,_) -> {lists:reverse(Acc),[],S}; -scan_content([], S=#xmerl_scanner{continuation_fun = F}, +scan_content([], S=#xmerl_scanner{continuation_fun = F}, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,_) -> ?dbg("cont()...~n", []), - F(fun(MoreBytes, S1) -> scan_content(MoreBytes, S1, - Pos, Name, Attrs, + F(fun(MoreBytes, S1) -> scan_content(MoreBytes, S1, + Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) end, fun(S1) -> ?fatal(unexpected_end, S1) end, S); @@ -2542,10 +2545,10 @@ scan_content("</" ++ T, S0, _Pos, Name, _Attrs, _Space, _Lang, case T2 of ">" ++ T3 -> {lists:reverse(Acc), T3, S2}; - _ -> + _ -> ?fatal({error,{unexpected_end_of_STag}},S) end; -scan_content([$&|_T]=Str, +scan_content([$&|_T]=Str, #xmerl_scanner{environment={external,{entity,EName}}} = S0, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,_) -> {_EntV,T1,S1}=scan_entity_value(Str,S0 ,[],EName,general), @@ -2564,13 +2567,13 @@ scan_content("&" ++ T, S0, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) - _ -> scan_content(string_to_char_set(S1#xmerl_scanner.encoding,ExpRef)++T1,S1,Pos,Name,Attrs,Space,Lang,Parents,NS,Acc,[]) end; -scan_content("<!--" ++ T, S0=#xmerl_scanner{acc_fun = F, comments=CF}, Pos, Name, Attrs, Space, +scan_content("<!--" ++ T, S0=#xmerl_scanner{acc_fun = F, comments=CF}, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) -> ?bump_col(4), {C, T1, S1} = scan_comment(T, S, Pos, Parents, Lang), case CF of true -> - {Acc2, Pos2, S3} = + {Acc2, Pos2, S3} = case F(C, Acc, S1) of {Acc1, S2} -> {Acc1, Pos + 1, S2}; @@ -2580,10 +2583,10 @@ scan_content("<!--" ++ T, S0=#xmerl_scanner{acc_fun = F, comments=CF}, Pos, Name scan_content(T1, S3, Pos2, Name, Attrs, Space, Lang, Parents, NS, Acc2,[]); false -> scan_content(T1, S1, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) - end; + end; scan_content("<" ++ T, S0, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) -> ?bump_col(1), - {Markup, T1, S1} = + {Markup, T1, S1} = scan_content_markup(T, S, Pos, Name, Attrs, Space, Lang, Parents, NS), AccF = S1#xmerl_scanner.acc_fun, {NewAcc, NewPos, NewS} = case AccF(Markup, Acc, S1) of @@ -2599,10 +2602,10 @@ scan_content([_H|T], S= #xmerl_scanner{environment={external,{entity,_}}}, %% Guess we have to scan the content to find any internal entity %% references. scan_content(T,S,Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]); -scan_content(T, S=#xmerl_scanner{acc_fun = F, +scan_content(T, S=#xmerl_scanner{acc_fun = F, event_fun = Event, hook_fun=Hook, - line = _L}, + line = _L}, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,MarkupDel) -> Text0 = #xmlText{pos = Pos, parents = Parents}, @@ -2625,7 +2628,7 @@ scan_content(T, S=#xmerl_scanner{acc_fun = F, Parents, NS, NewAcc,[]). -scan_content_markup([], S=#xmerl_scanner{continuation_fun = F}, +scan_content_markup([], S=#xmerl_scanner{continuation_fun = F}, Pos, Name, Attrs, Space, Lang, Parents, NS) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_content_markup( @@ -2650,21 +2653,21 @@ scan_char_data(T, S, Space,MUD) -> scan_char_data([], S=#xmerl_scanner{environment={external,{entity,_}}}, _Space,_MUD, Acc) -> - + {lists:reverse(Acc), [], S}; scan_char_data([], S=#xmerl_scanner{environment=internal_parsed_entity}, _Space, _MUD,Acc) -> - + {lists:reverse(Acc), [], S}; scan_char_data([], S=#xmerl_scanner{continuation_fun = F}, Space, _MUD,Acc) -> ?dbg("cont()...~n", []), - F(fun(MoreBytes, S1) -> scan_char_data(MoreBytes,S1,Space,_MUD,Acc) end, + F(fun(MoreBytes, S1) -> scan_char_data(MoreBytes,S1,Space,_MUD,Acc) end, fun(S1) -> ?fatal(unexpected_end, S1) end, S); scan_char_data([$&|T], S,Space,"&",Acc) -> scan_char_data(T, S, Space,[], [$&|Acc]); scan_char_data(T=[$&|_], S,_Space,_MUD,Acc) -> - + {lists:reverse(Acc), T, S}; scan_char_data("]]>" ++ _T, S, _Space,_MUD, _Acc) -> %% See Section 2.4: Especially: @@ -2676,7 +2679,7 @@ scan_char_data("]]>" ++ _T, S, _Space,_MUD, _Acc) -> scan_char_data([$<|T],S,Space,"<", Acc) -> scan_char_data(T, S, Space,[], [$<|Acc]); scan_char_data(T = [$<|_], S, _Space,_MUD,Acc) -> - + {lists:reverse(Acc), T, S}; scan_char_data(T = [H|R], S, Space,MUD, Acc) when ?whitespace(H) -> if @@ -2769,7 +2772,7 @@ scan_reference(T, S) -> %% ampersand is not recognized as an entity-reference delimiter.)" %% %% How to achieve this? My current approach is to insert the *strings* "&", -%% "<", ">", "'", and "\"" instead of the characters. The processor will +%% "<", ">", "'", and "\"" instead of the characters. The processor will %% ignore them when performing multiple expansions. This means, for now, that %% the character data output by the processor is (1-2 levels) deep. %% At some suitable point, we should flatten these, so that application-level @@ -2798,7 +2801,7 @@ scan_entity_ref("quot;" ++ T, S0) -> scan_entity_ref(T, S) -> {Name, _NamespaceInfo, T1, S1} = scan_name(T, S), T2 = scan_mandatory(";",T1,1,S1,expected_entity_reference_semicolon), -% ";" ++ T2 = T1, +% ";" ++ T2 = T1, S2 = S1, Entity = expand_reference(Name, S2), {Entity, T2, S2}. @@ -2809,7 +2812,7 @@ scan_entity_ref(T, S) -> scan_pe_reference(T, S) -> {Name, _NamespaceInfo, T1, S1} = scan_name(T, S), T2 = scan_mandatory(";",T1,1,S1,expected_parsed_entity_reference_semicolon), -% ";" ++ T2 = T1, +% ";" ++ T2 = T1, {Name, T2, S1#xmerl_scanner{col = S1#xmerl_scanner.col+1}}. expand_pe_reference(Name, #xmerl_scanner{rules_read_fun = Read} = S,WS) -> @@ -2836,7 +2839,7 @@ expand_pe_reference(Name, #xmerl_scanner{rules_read_fun = Read} = S,WS) -> % Result -> % fetch_DTD(Result,S) % end. - + %%%%%%% [68] EntityReference @@ -2915,15 +2918,15 @@ scan_eq(T, S) -> %% scan_name/2 %% -%% We perform some checks here to make sure that the names conform to +%% We perform some checks here to make sure that the names conform to %% the "Namespaces in XML" specification. This is an option. -%% +%% %% Qualified Name: %% [6] QName ::= (Prefix ':')? LocalPart %% [7] Prefix ::= NCName %% [8] LocalPart ::= NCName %% [4] NCName ::= (Letter | '_') (NCNameChar)* -%% [5] NCNameChar ::= Letter | Digit | '.' | '-' | '_' +%% [5] NCNameChar ::= Letter | Digit | '.' | '-' | '_' %% | CombiningChar | Extender @@ -2937,9 +2940,9 @@ scan_eq(T, S) -> %% scan_name_no_colons(Str, S) -> NSC = S#xmerl_scanner.namespace_conformant, - case NSC of + case NSC of true -> - {Target, NSI, T1, S1} = + {Target, NSI, T1, S1} = scan_name(Str,S#xmerl_scanner{namespace_conformant=no_colons}), {Target,NSI,T1,S1#xmerl_scanner{namespace_conformant=NSC}}; false -> @@ -2951,7 +2954,7 @@ scan_name_no_colons(Str, S) -> %% [5] Name ::= (Letter | '_' | ':') (NameChar)* scan_name([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), - F(fun(MoreBytes, S1) -> scan_name(MoreBytes, S1) end, + F(fun(MoreBytes, S1) -> scan_name(MoreBytes, S1) end, fun(S1) -> ?fatal(unexpected_end, S1) end, S); scan_name(Str = [$:|T], S0 = #xmerl_scanner{namespace_conformant = NSC}) -> @@ -3014,15 +3017,15 @@ scan_nmtoken(Str, S) -> {Ch,T} = to_ucs(S#xmerl_scanner.encoding,Str), case xmerl_lib:is_namechar(Ch) of true -> - scan_nmtoken(T, S#xmerl_scanner{col = S#xmerl_scanner.col+1}, - _Acc = [Ch], _Prefix = [], _Local = [Ch], + scan_nmtoken(T, S#xmerl_scanner{col = S#xmerl_scanner.col+1}, + _Acc = [Ch], _Prefix = [], _Local = [Ch], _NamespaceConformant = false,isLatin1(Ch,true)); false -> ?fatal({invalid_nmtoken, lists:sublist(Str, 1, 6)}, S) end. -scan_nmtoken([], S=#xmerl_scanner{continuation_fun = F}, +scan_nmtoken([], S=#xmerl_scanner{continuation_fun = F}, Acc, Prefix, Local, NSC,IsLatin1) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_nmtoken(MoreBytes,S1,Acc,Prefix,Local,NSC,IsLatin1) end, @@ -3036,16 +3039,16 @@ scan_nmtoken(Str = [H|_], S, Acc, Prefix, Local, _NSC,true) when ?whitespace(H) NmString = lists:reverse(Acc), {list_to_atom(NmString), namespace_info(Prefix, Local), Str, S}; scan_nmtoken(Str = [$:|_], S, Acc, [], _Local, no_colons,_IsLatin1) -> - ?fatal({invalid_NCName, + ?fatal({invalid_NCName, lists:sublist(lists:reverse(Acc) ++ Str, 1, 6)}, S); scan_nmtoken([$:|T], S0, Acc, [], Local, NSC, IsLatin1) -> ?bump_col(1), scan_nmtoken(T, S, [$:|Acc], lists:reverse(Local), [], NSC,IsLatin1); scan_nmtoken(Str = [$:|_T], S, Acc, _Prefix, _Local, _NSC = true,_IsLatin1) -> %% non-empty Prefix means that we've encountered a ":" already. - %% Conformity with "Namespaces in XML" requires + %% Conformity with "Namespaces in XML" requires %% at most one colon in a name - ?fatal({invalid_NCName, + ?fatal({invalid_NCName, lists:sublist(lists:reverse(Acc) ++ Str, 1, 6)}, S); %% non-namechar also marks the end of a name @@ -3078,7 +3081,7 @@ isLatin1(_,_) -> scan_system_literal([], S=#xmerl_scanner{continuation_fun = F}) -> ?dbg("cont()...~n", []), - F(fun(MoreBytes, S1) -> scan_system_literal(MoreBytes, S1) end, + F(fun(MoreBytes, S1) -> scan_system_literal(MoreBytes, S1) end, fun(S1) -> ?fatal(unexpected_end, S1) end, S); scan_system_literal("\"" ++ T, S) -> @@ -3087,7 +3090,7 @@ scan_system_literal("'" ++ T, S) -> scan_system_literal(T, S, $', []). -scan_system_literal([], S=#xmerl_scanner{continuation_fun = F}, +scan_system_literal([], S=#xmerl_scanner{continuation_fun = F}, Delimiter, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_system_literal(MoreBytes,S1,Delimiter,Acc) end, @@ -3100,7 +3103,7 @@ scan_system_literal("#"++_R, S, _H, _Acc) -> ?fatal(fragment_identifier_in_system_literal,S); scan_system_literal(Str, S, Delimiter, Acc) -> {Ch,T} = to_ucs(S#xmerl_scanner.encoding,Str), - scan_system_literal(T, S#xmerl_scanner{col = S#xmerl_scanner.col+1}, + scan_system_literal(T, S#xmerl_scanner{col = S#xmerl_scanner.col+1}, Delimiter, [Ch|Acc]). @@ -3117,7 +3120,7 @@ scan_pubid_literal([H|_T], S) -> ?fatal({invalid_pubid_char, H}, S). -scan_pubid_literal([], S=#xmerl_scanner{continuation_fun = F}, +scan_pubid_literal([], S=#xmerl_scanner{continuation_fun = F}, Delimiter, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_pubid_literal(MoreBytes,S1,Delimiter,Acc) end, @@ -3134,7 +3137,7 @@ scan_pubid_literal([H|T], S, Delimiter, Acc) -> case is_pubid_char(H) of true -> scan_pubid_literal( - T, S#xmerl_scanner{col = S#xmerl_scanner.col+1}, + T, S#xmerl_scanner{col = S#xmerl_scanner.col+1}, Delimiter, [H|Acc]); false -> ?fatal({invalid_pubid_char, H}, S) @@ -3186,7 +3189,7 @@ scan_contentspec(_Str,S) -> scan_elem_content(T, S) -> scan_elem_content(T, S, _Context = children, _Mode = unknown, _Acc = []). -scan_elem_content([], S=#xmerl_scanner{continuation_fun = F}, +scan_elem_content([], S=#xmerl_scanner{continuation_fun = F}, Context, Mode, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes,S1) -> scan_elem_content(MoreBytes,S1,Context,Mode,Acc) end, @@ -3207,7 +3210,7 @@ scan_elem_content(")" ++ T, S0, Context, Mode0, Acc0) -> % more names than '#PCDATA' % and no '*'. {'*', mixed,_} -> ok; - {Other, mixed,_} -> + {Other, mixed,_} -> ?fatal({illegal_for_mixed_content, Other}, S1); _ -> ok @@ -3216,7 +3219,7 @@ scan_elem_content(")" ++ T, S0, Context, Mode0, Acc0) -> {format_elem_content({Occurrence, {Mode, Acc}}), T2, S2}; scan_elem_content("#PCDATA" ++ _T, S, not_mixed, _Mode, _Acc) -> ?fatal({error,{extra_set_of_parenthesis}},S); -scan_elem_content("#PCDATA" ++ _T, S, _Cont, Mode, Acc) +scan_elem_content("#PCDATA" ++ _T, S, _Cont, Mode, Acc) when Mode==choice;Mode==seq;Acc/=[] -> ?fatal({error,{invalid_format_of_mixed_content}},S); scan_elem_content("#PCDATA" ++ T, S0, _Context, Mode, Acc) -> @@ -3259,7 +3262,7 @@ scan_elem_content2(T, S, Context, Mode, Acc) -> {Occurrence, T2, S2} = scan_occurrence(T1, S1), case {Occurrence, Context} of {once, mixed} -> ok; - {Other, mixed} -> + {Other, mixed} -> ?fatal({illegal_for_mixed_content, Other}, S1); _ -> ok @@ -3305,17 +3308,17 @@ vc_Valid_Char(_AT,C,S) -> -vc_ID_Attribute_Default(_,#xmerl_scanner{validation=Valid}) +vc_ID_Attribute_Default(_,#xmerl_scanner{validation=Valid}) when Valid /= dtd -> - ok; -vc_ID_Attribute_Default({_,'ID',_,Def,_},_S) + ok; +vc_ID_Attribute_Default({_,'ID',_,Def,_},_S) when Def=='#IMPLIED';Def=='#REQUIRED' -> ok; vc_ID_Attribute_Default({_,'ID',_,Def,_},S) -> ?fatal({error,{validity_constraint_error_ID_Attribute_Default,Def}},S). -vc_Enumeration({_Name,{_,NameList},DefaultVal,_,_},S) - when is_list(DefaultVal) -> +vc_Enumeration({_Name,{_,NameList},DefaultVal,_,_},S) + when is_list(DefaultVal) -> case lists:member(list_to_atom(DefaultVal),NameList) of true -> ok; @@ -3338,12 +3341,12 @@ vc_Entity_Name({_,'ENTITIES',DefaultVal,_,_},S) when is_list(DefaultVal) -> Read = S#xmerl_scanner.rules_read_fun, NameListFun = fun([],Acc,_St,_Fun) -> lists:reverse(Acc); - (Str,Acc,St,Fun) -> + (Str,Acc,St,Fun) -> {N,_,St2,Str2} = scan_name(Str,St), Fun(Str2,[N|Acc],St2,Fun) end, NameList = NameListFun(DefaultVal,[],S,NameListFun), - VcFun = + VcFun = fun(X) -> case Read(entity,X,S) of {_,external,{_,{ndata,_}}} -> @@ -3356,7 +3359,7 @@ vc_Entity_Name({_,'ENTITIES',_,_,_},_S) -> ok. vc_No_Duplicate_Types(#xmerl_scanner{validation=dtd} = S,mixed,Acc) -> - CheckDupl = + CheckDupl = fun([H|T],F) -> case lists:member(H,T) of true -> @@ -3519,7 +3522,7 @@ scan_notation_decl1("PUBLIC" ++ T, S0) -> ?strip3, case T3 of ">" ++ _ -> - {{public, PIDL}, T3, + {{public, PIDL}, T3, S3#xmerl_scanner{col = S3#xmerl_scanner.col+1}}; _ -> {SL, T4, S4} = scan_system_literal(T3, S3), @@ -3570,7 +3573,7 @@ scan_entity_value([],S, scan_entity_value([],S=#xmerl_scanner{validation=dtd}, no_delim,_Acc,PEName,_,_PENesting) -> {{error,{failed_VC_Proper_Declaration_PE_Nesting,2,PEName}},[],S}; -scan_entity_value([], S=#xmerl_scanner{continuation_fun = F}, +scan_entity_value([], S=#xmerl_scanner{continuation_fun = F}, Delim, Acc, PEName,Namespace,PENesting) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> @@ -3589,7 +3592,7 @@ scan_entity_value([Delim|T], S0, scan_entity_value("%" ++ _T,S=#xmerl_scanner{environment=prolog},_,_,_,_,_) -> ?fatal({error,{wfc_PEs_In_Internal_Subset}},S); % %% This is a PEdecl in an external entity -% scan_entity_value([$%,WS|T], S0, Delim, Acc, PEName,Namespace,PENesting) +% scan_entity_value([$%,WS|T], S0, Delim, Acc, PEName,Namespace,PENesting) % when ?whitespace(WS) -> % ?bump_col(2), % scan_entity_value(T, S, Delim, [WS,$%|Acc], PEName,Namespace,PENesting); @@ -3599,7 +3602,7 @@ scan_entity_value("%" ++ T, S0, Delim, Acc, PEName,Namespace,PENesting) -> if PERefName == PEName,Namespace==parameter -> ?fatal({illegal_recursion_in_PE, PEName}, S1); true -> - {ExpandedRef,S2} = + {ExpandedRef,S2} = case expand_pe_reference(PERefName, S1, in_literal) of %% actually should pe ref be expanded as_PE but %% handle whitespace explicitly in this case. @@ -3607,7 +3610,7 @@ scan_entity_value("%" ++ T, S0, Delim, Acc, PEName,Namespace,PENesting) -> %% {system,URI} or {public,URI} %% Included in literal. {ExpRef,Sx}=fetch_not_parse(Tuple,S1), - {EntV, _, S5} = + {EntV, _, S5} = scan_entity_value(ExpRef, Sx, no_delim,[], PERefName,parameter,[]), %% should do an update Write(parameter_entity) @@ -3727,7 +3730,7 @@ scan_entity_value(")"++ T,S0,Delim,Acc,PEName, parameter=NS,PENesting) -> scan_entity_value(T,S,Delim,[")"|Acc],PEName,NS, pe_pop(")",PENesting,S)); scan_entity_value("\n"++T, S, Delim, Acc, PEName,Namespace,PENesting) -> - scan_entity_value(T, S#xmerl_scanner{line=S#xmerl_scanner.line+1}, + scan_entity_value(T, S#xmerl_scanner{line=S#xmerl_scanner.line+1}, Delim, ["\n"|Acc], PEName,Namespace,PENesting); scan_entity_value(Str, S0, Delim, Acc, PEName,Namespace,PENesting) -> {Ch,T} = to_ucs(S0#xmerl_scanner.encoding,Str), @@ -3770,7 +3773,7 @@ save_refed_entity_name1(Name,PEName, pe_push(Tok,Stack,_S) when Tok=="<!";Tok=="<?";Tok=="<!--";Tok=="<!["; Tok=="[";Tok=="<";Tok=="</";Tok=="(" -> [Tok|Stack]; -pe_push(Tok,Stack,#xmerl_scanner{validation=dtd}) +pe_push(Tok,Stack,#xmerl_scanner{validation=dtd}) when Tok==")";Tok==">";Tok=="?>";Tok=="]]>";Tok=="-->";Tok=="/>"-> [Tok|Stack]; pe_push(_,Stack,_S) -> @@ -3838,10 +3841,10 @@ scan_comment(Str,S=#xmerl_scanner{col=C,event_fun=Event}, Pos, Parents, Lang) -> col = C, pos = Pos, data = Comment}, S), - + scan_comment1(Str, S1, Pos, Comment, _Acc = []). -scan_comment1([], S=#xmerl_scanner{continuation_fun = F}, +scan_comment1([], S=#xmerl_scanner{continuation_fun = F}, Pos, Comment, Acc) -> ?dbg("cont()...~n", []), F(fun(MoreBytes, S1) -> scan_comment1(MoreBytes, S1, Pos, Comment, Acc) end, @@ -3849,7 +3852,7 @@ scan_comment1([], S=#xmerl_scanner{continuation_fun = F}, S); scan_comment1("-->" ++ T, S0 = #xmerl_scanner{col = C, event_fun = Event, - hook_fun = Hook}, + hook_fun = Hook}, _Pos, Comment, Acc) -> ?bump_col(3), Comment1 = Comment#xmlComment{value = lists:reverse(Acc)}, @@ -3957,9 +3960,9 @@ normalize(T,S,IsNorm) -> end. -%% Optimization: +%% Optimization: %% - avoid building list of spaces or tabs; -%% - avoid reverse; +%% - avoid reverse; %% - compact two common indentation patterns. %% Note: only to be called when a \n was found. fast_accumulate_whitespace(" " ++ T, S, _) -> @@ -3971,7 +3974,7 @@ fast_accumulate_whitespace("<"++_=R, S, _T) -> {done, {element(3, CD), R, S#xmerl_scanner{col = 1, line = Line + 1}}}; fast_accumulate_whitespace(_, S, T) -> accumulate_whitespace(T, S, []). - + fast_acc_spaces(" " ++ T, S, N) -> fast_acc_spaces(T, S, N + 1); fast_acc_spaces(T, S, N) -> @@ -3985,18 +3988,18 @@ fast_acc_tabs(T, S, N) -> fast_acc_end(T, S, N, Col, C, CD_I) -> #xmerl_scanner{common_data = CD, line = Line0} = S, Line = Line0 + 1, - try + try $< = hd(T), - {done,{element(N, element(CD_I, CD)), T, + {done,{element(N, element(CD_I, CD)), T, S#xmerl_scanner{col = Col, line = Line}}} - catch _:_ -> + catch _:_ -> accumulate_whitespace(T, S, Line, Col, lists:duplicate(N, C)++"\n") end. - + %%% @spec accumulate_whitespace(T::string(),S::global_state(), %%% atom(),Acc::string()) -> {Acc, T1, S1} -%%% +%%% %%% @doc Function to accumulate and normalize whitespace. accumulate_whitespace(T, S, preserve, Acc) -> accumulate_whitespace(T, S, Acc); @@ -4055,19 +4058,19 @@ schemaLocations(El,#xmerl_scanner{schemaLocation=SL}) -> schemaLocations(El) end. -schemaLocations(#xmlElement{attributes=Atts,xmlbase=_Base}) -> +schemaLocations(#xmlElement{attributes=Atts,xmlbase=_Base}) -> Pred = fun(#xmlAttribute{name=schemaLocation}) -> false; (#xmlAttribute{nsinfo={_,"schemaLocation"}}) -> false; (_) -> true end, case lists:dropwhile(Pred,Atts) of [#xmlAttribute{value=Paths}|_] -> - + case string:tokens(Paths," \n\t\r") of L when length(L) > 0 -> case length(L) rem 2 of 0 -> - PairList = + PairList = fun([],_Fun) -> []; ([SLNS,SLLoc|Rest],Fun) -> @@ -4137,7 +4140,7 @@ to_ucs(Encoding, Chars) when Encoding=="utf-8"; Encoding == undefined -> utf8_2_ucs(Chars); to_ucs(_,[C|Rest]) -> {C,Rest}. - + utf8_2_ucs([A,B,C,D|Rest]) when A band 16#f8 =:= 16#f0, B band 16#c0 =:= 16#80, C band 16#c0 =:= 16#80, @@ -4226,7 +4229,7 @@ string_to_char_set(_,Str) -> %% {{_,{_,Tot}},Tot110} when Tot > Tot110 -> %% io:format("From ~p to ~p, total memory: ~p (~p)~n",[OldLine,Line,Tot,OldTot]), %% Tot; -%% {{_,{_,Tot}},_} -> +%% {{_,{_,Tot}},_} -> %% Tot %% end, %% put_total({NewTot,Line}). diff --git a/lib/xmerl/src/xmerl_uri.erl b/lib/xmerl/src/xmerl_uri.erl index a0c6f1c2a7..1864651491 100644 --- a/lib/xmerl/src/xmerl_uri.erl +++ b/lib/xmerl/src/xmerl_uri.erl @@ -358,7 +358,7 @@ scan_host(C0) -> %% Hex3=<?HEX; %% Hex4=<?HEX -> %% {C1,lists:reverse(lists:append(IPv6address))}; - {C1,Hostname,[A|_HostF]} -> + {C1,Hostname,[_A|_HostF]} -> {C1,lists:reverse(lists:append(Hostname))} %% _ -> %% {error,no_host} diff --git a/make/run_make.mk b/make/run_make.mk index b2be384aa3..39c3668e50 100644 --- a/make/run_make.mk +++ b/make/run_make.mk @@ -27,6 +27,8 @@ include $(ERL_TOP)/make/target.mk +.PHONY: valgrind + opt debug purify quantify purecov valgrind gcov gprof lcnt: $(MAKE) -f $(TARGET)/Makefile TYPE=$@ diff --git a/make/target.mk b/make/target.mk index a6493e09a5..4e13779461 100644 --- a/make/target.mk +++ b/make/target.mk @@ -54,7 +54,7 @@ endif ifneq ($(TARGET),) ifneq ($(TARGET),win32) -ifneq ($(TARGET),vxworks) +ifneq ($(findstring vxworks,$(TARGET)),vxworks) override TARGET := $(shell $(ERL_TOP)/erts/autoconf/config.sub $(TARGET)) else endif diff --git a/system/doc/design_principles/sup_princ.xml b/system/doc/design_principles/sup_princ.xml index 5b8fd604c8..c473e257fa 100644 --- a/system/doc/design_principles/sup_princ.xml +++ b/system/doc/design_principles/sup_princ.xml @@ -136,7 +136,7 @@ init(...) -> M = F = atom() A = [term()] Restart = permanent | transient | temporary - Shutdown = brutal_kill | integer() >=0 | infinity + Shutdown = brutal_kill | integer()>=0 | infinity Type = worker | supervisor Modules = [Module] | dynamic Module = atom()]]></code> diff --git a/xcomp/erl-xcomp-avr32-atmel-linux-gnu.conf b/xcomp/erl-xcomp-avr32-atmel-linux-gnu.conf index f691c6cfd1..31f5306c1a 100644 --- a/xcomp/erl-xcomp-avr32-atmel-linux-gnu.conf +++ b/xcomp/erl-xcomp-avr32-atmel-linux-gnu.conf @@ -59,7 +59,7 @@ erl_xcomp_host=avr32-atmel-linux-gnu # * `erl_xcomp_configure_flags' - Extra configure flags to pass to the # `configure' script. -#erl_xcomp_configure_flags= +erl_xcomp_configure_flags="--disable-hipe --disable-threads --disable-smp" ## -- Cross Compiler and Other Tools ------------------------------------------- @@ -73,7 +73,7 @@ erl_xcomp_host=avr32-atmel-linux-gnu CC=avr32-linux-gcc # * `CFLAGS' - C compiler flags. -#CFLAGS= +CFLAGS="-O -Dfinite=__finite" # * `STATIC_CFLAGS' - Static C compiler flags. #STATIC_CFLAGS= |