From 4c6eed5c0a033ce353160d43aef9c60716411c6e Mon Sep 17 00:00:00 2001 From: Daniel Larimer Date: Fri, 21 Dec 2012 12:58:01 -0500 Subject: [PATCH] adding vendor deps --- vendor/CMakeLists.txt | 2 + vendor/libssh2-1.4.2/AUTHORS | 48 + .../CMakeDirectoryInformation.cmake | 16 + .../libssh2-1.4.2/CMakeFiles/progress.marks | 1 + .../CMakeFiles/ssh2.dir/C.includecache | 8 + .../CMakeFiles/ssh2.dir/DependInfo.cmake | 48 + .../CMakeFiles/ssh2.dir/build.make | 649 +++ .../CMakeFiles/ssh2.dir/cmake_clean.cmake | 31 + .../ssh2.dir/cmake_clean_target.cmake | 3 + .../CMakeFiles/ssh2.dir/depend.internal | 1098 +++++ .../CMakeFiles/ssh2.dir/depend.make | 1098 +++++ .../CMakeFiles/ssh2.dir/flags.make | 8 + .../CMakeFiles/ssh2.dir/link.txt | 2 + .../CMakeFiles/ssh2.dir/progress.make | 23 + vendor/libssh2-1.4.2/CMakeLists.txt | 28 + vendor/libssh2-1.4.2/COPYING | 42 + vendor/libssh2-1.4.2/ChangeLog | 1 + vendor/libssh2-1.4.2/HACKING | 13 + vendor/libssh2-1.4.2/Makefile | 776 ++++ vendor/libssh2-1.4.2/README | 102 + vendor/libssh2-1.4.2/RELEASE-NOTES | 21 + vendor/libssh2-1.4.2/cmake_install.cmake | 37 + vendor/libssh2-1.4.2/include/libssh2.h | 1188 +++++ .../libssh2-1.4.2/include/libssh2_publickey.h | 118 + vendor/libssh2-1.4.2/include/libssh2_sftp.h | 345 ++ vendor/libssh2-1.4.2/libssh2_debug.a | Bin 0 -> 1108128 bytes vendor/libssh2-1.4.2/src/agent.c | 793 ++++ vendor/libssh2-1.4.2/src/channel.c | 2570 +++++++++++ vendor/libssh2-1.4.2/src/channel.h | 141 + vendor/libssh2-1.4.2/src/comp.c | 390 ++ vendor/libssh2-1.4.2/src/comp.h | 45 + vendor/libssh2-1.4.2/src/crypt.c | 334 ++ vendor/libssh2-1.4.2/src/crypto.h | 118 + vendor/libssh2-1.4.2/src/global.c | 78 + vendor/libssh2-1.4.2/src/hostkey.c | 485 ++ vendor/libssh2-1.4.2/src/keepalive.c | 98 + vendor/libssh2-1.4.2/src/kex.c | 2008 +++++++++ vendor/libssh2-1.4.2/src/knownhost.c | 1146 +++++ vendor/libssh2-1.4.2/src/libgcrypt.c | 593 +++ vendor/libssh2-1.4.2/src/libgcrypt.h | 150 + vendor/libssh2-1.4.2/src/libssh2_config.h | 5 + vendor/libssh2-1.4.2/src/libssh2_config_osx.h | 224 + vendor/libssh2-1.4.2/src/libssh2_config_win.h | 41 + vendor/libssh2-1.4.2/src/libssh2_priv.h | 1038 +++++ vendor/libssh2-1.4.2/src/mac.c | 314 ++ vendor/libssh2-1.4.2/src/mac.h | 67 + vendor/libssh2-1.4.2/src/misc.c | 612 +++ vendor/libssh2-1.4.2/src/misc.h | 94 + vendor/libssh2-1.4.2/src/openssl.c | 804 ++++ vendor/libssh2-1.4.2/src/openssl.h | 178 + vendor/libssh2-1.4.2/src/packet.c | 1243 +++++ vendor/libssh2-1.4.2/src/packet.h | 76 + vendor/libssh2-1.4.2/src/pem.c | 213 + vendor/libssh2-1.4.2/src/publickey.c | 1058 +++++ vendor/libssh2-1.4.2/src/scp.c | 1085 +++++ vendor/libssh2-1.4.2/src/session.c | 1751 ++++++++ vendor/libssh2-1.4.2/src/session.h | 93 + vendor/libssh2-1.4.2/src/sftp.c | 3278 ++++++++++++++ vendor/libssh2-1.4.2/src/sftp.h | 230 + vendor/libssh2-1.4.2/src/transport.c | 873 ++++ vendor/libssh2-1.4.2/src/transport.h | 87 + vendor/libssh2-1.4.2/src/userauth.c | 1687 +++++++ vendor/libssh2-1.4.2/src/userauth.h | 50 + vendor/libssh2-1.4.2/src/version.c | 54 + .../CMakeDirectoryInformation.cmake | 16 + vendor/sigar/CMakeFiles/progress.marks | 1 + .../sigar/CMakeFiles/sigar.dir/C.includecache | 8 + .../CMakeFiles/sigar.dir/DependInfo.cmake | 43 + vendor/sigar/CMakeFiles/sigar.dir/build.make | 337 ++ .../CMakeFiles/sigar.dir/cmake_clean.cmake | 19 + .../sigar.dir/cmake_clean_target.cmake | 3 + .../CMakeFiles/sigar.dir/depend.internal | 98 + vendor/sigar/CMakeFiles/sigar.dir/depend.make | 98 + vendor/sigar/CMakeFiles/sigar.dir/flags.make | 8 + vendor/sigar/CMakeFiles/sigar.dir/link.txt | 2 + .../sigar/CMakeFiles/sigar.dir/progress.make | 11 + vendor/sigar/CMakeLists.txt | 33 + vendor/sigar/Makefile | 452 ++ vendor/sigar/cmake_install.cmake | 37 + vendor/sigar/include/sigar.h | 943 ++++ vendor/sigar/include/sigar_fileinfo.h | 157 + vendor/sigar/include/sigar_format.h | 65 + vendor/sigar/include/sigar_getline.h | 18 + vendor/sigar/include/sigar_log.h | 80 + vendor/sigar/include/sigar_private.h | 422 ++ vendor/sigar/include/sigar_ptql.h | 53 + vendor/sigar/include/sigar_util.h | 191 + vendor/sigar/libsigar_debug.a | Bin 0 -> 621472 bytes vendor/sigar/src/os/aix/aix_sigar.c | 2151 +++++++++ vendor/sigar/src/os/aix/sigar_os.h | 73 + vendor/sigar/src/os/darwin/darwin_sigar.c | 3711 +++++++++++++++ vendor/sigar/src/os/darwin/sigar_os.h | 89 + vendor/sigar/src/os/hpux/hpux_sigar.c | 1342 ++++++ vendor/sigar/src/os/hpux/sigar_os.h | 49 + vendor/sigar/src/os/linux/linux_sigar.c | 2782 ++++++++++++ vendor/sigar/src/os/linux/sigar_os.h | 82 + vendor/sigar/src/os/solaris/get_mib2.c | 321 ++ vendor/sigar/src/os/solaris/get_mib2.h | 127 + vendor/sigar/src/os/solaris/kstats.c | 181 + vendor/sigar/src/os/solaris/procfs.c | 97 + vendor/sigar/src/os/solaris/sigar_os.h | 224 + vendor/sigar/src/os/solaris/solaris_sigar.c | 2717 +++++++++++ vendor/sigar/src/os/win32/peb.c | 212 + vendor/sigar/src/os/win32/sigar_os.h | 676 +++ vendor/sigar/src/os/win32/sigar_pdh.h | 47 + vendor/sigar/src/os/win32/win32_sigar.c | 3992 +++++++++++++++++ vendor/sigar/src/os/win32/wmi.cpp | 243 + vendor/sigar/src/sigar.c | 2428 ++++++++++ vendor/sigar/src/sigar_cache.c | 179 + vendor/sigar/src/sigar_fileinfo.c | 815 ++++ vendor/sigar/src/sigar_format.c | 696 +++ vendor/sigar/src/sigar_getline.c | 1849 ++++++++ vendor/sigar/src/sigar_ptql.c | 1967 ++++++++ vendor/sigar/src/sigar_signal.c | 216 + vendor/sigar/src/sigar_util.c | 1060 +++++ vendor/sigar/src/sigar_version_autoconf.c | 22 + 116 files changed, 61253 insertions(+) create mode 100644 vendor/CMakeLists.txt create mode 100644 vendor/libssh2-1.4.2/AUTHORS create mode 100644 vendor/libssh2-1.4.2/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 vendor/libssh2-1.4.2/CMakeFiles/progress.marks create mode 100644 vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/C.includecache create mode 100644 vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/DependInfo.cmake create mode 100644 vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make create mode 100644 vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/cmake_clean.cmake create mode 100644 vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/cmake_clean_target.cmake create mode 100644 vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/depend.internal create mode 100644 vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/depend.make create mode 100644 vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make create mode 100644 vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/link.txt create mode 100644 vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/progress.make create mode 100644 vendor/libssh2-1.4.2/CMakeLists.txt create mode 100644 vendor/libssh2-1.4.2/COPYING create mode 100644 vendor/libssh2-1.4.2/ChangeLog create mode 100644 vendor/libssh2-1.4.2/HACKING create mode 100644 vendor/libssh2-1.4.2/Makefile create mode 100644 vendor/libssh2-1.4.2/README create mode 100644 vendor/libssh2-1.4.2/RELEASE-NOTES create mode 100644 vendor/libssh2-1.4.2/cmake_install.cmake create mode 100644 vendor/libssh2-1.4.2/include/libssh2.h create mode 100644 vendor/libssh2-1.4.2/include/libssh2_publickey.h create mode 100644 vendor/libssh2-1.4.2/include/libssh2_sftp.h create mode 100644 vendor/libssh2-1.4.2/libssh2_debug.a create mode 100644 vendor/libssh2-1.4.2/src/agent.c create mode 100644 vendor/libssh2-1.4.2/src/channel.c create mode 100644 vendor/libssh2-1.4.2/src/channel.h create mode 100644 vendor/libssh2-1.4.2/src/comp.c create mode 100644 vendor/libssh2-1.4.2/src/comp.h create mode 100644 vendor/libssh2-1.4.2/src/crypt.c create mode 100644 vendor/libssh2-1.4.2/src/crypto.h create mode 100644 vendor/libssh2-1.4.2/src/global.c create mode 100644 vendor/libssh2-1.4.2/src/hostkey.c create mode 100644 vendor/libssh2-1.4.2/src/keepalive.c create mode 100644 vendor/libssh2-1.4.2/src/kex.c create mode 100644 vendor/libssh2-1.4.2/src/knownhost.c create mode 100644 vendor/libssh2-1.4.2/src/libgcrypt.c create mode 100644 vendor/libssh2-1.4.2/src/libgcrypt.h create mode 100644 vendor/libssh2-1.4.2/src/libssh2_config.h create mode 100644 vendor/libssh2-1.4.2/src/libssh2_config_osx.h create mode 100644 vendor/libssh2-1.4.2/src/libssh2_config_win.h create mode 100644 vendor/libssh2-1.4.2/src/libssh2_priv.h create mode 100644 vendor/libssh2-1.4.2/src/mac.c create mode 100644 vendor/libssh2-1.4.2/src/mac.h create mode 100644 vendor/libssh2-1.4.2/src/misc.c create mode 100644 vendor/libssh2-1.4.2/src/misc.h create mode 100644 vendor/libssh2-1.4.2/src/openssl.c create mode 100644 vendor/libssh2-1.4.2/src/openssl.h create mode 100644 vendor/libssh2-1.4.2/src/packet.c create mode 100644 vendor/libssh2-1.4.2/src/packet.h create mode 100644 vendor/libssh2-1.4.2/src/pem.c create mode 100644 vendor/libssh2-1.4.2/src/publickey.c create mode 100644 vendor/libssh2-1.4.2/src/scp.c create mode 100644 vendor/libssh2-1.4.2/src/session.c create mode 100644 vendor/libssh2-1.4.2/src/session.h create mode 100644 vendor/libssh2-1.4.2/src/sftp.c create mode 100644 vendor/libssh2-1.4.2/src/sftp.h create mode 100644 vendor/libssh2-1.4.2/src/transport.c create mode 100644 vendor/libssh2-1.4.2/src/transport.h create mode 100644 vendor/libssh2-1.4.2/src/userauth.c create mode 100644 vendor/libssh2-1.4.2/src/userauth.h create mode 100644 vendor/libssh2-1.4.2/src/version.c create mode 100644 vendor/sigar/CMakeFiles/CMakeDirectoryInformation.cmake create mode 100644 vendor/sigar/CMakeFiles/progress.marks create mode 100644 vendor/sigar/CMakeFiles/sigar.dir/C.includecache create mode 100644 vendor/sigar/CMakeFiles/sigar.dir/DependInfo.cmake create mode 100644 vendor/sigar/CMakeFiles/sigar.dir/build.make create mode 100644 vendor/sigar/CMakeFiles/sigar.dir/cmake_clean.cmake create mode 100644 vendor/sigar/CMakeFiles/sigar.dir/cmake_clean_target.cmake create mode 100644 vendor/sigar/CMakeFiles/sigar.dir/depend.internal create mode 100644 vendor/sigar/CMakeFiles/sigar.dir/depend.make create mode 100644 vendor/sigar/CMakeFiles/sigar.dir/flags.make create mode 100644 vendor/sigar/CMakeFiles/sigar.dir/link.txt create mode 100644 vendor/sigar/CMakeFiles/sigar.dir/progress.make create mode 100644 vendor/sigar/CMakeLists.txt create mode 100644 vendor/sigar/Makefile create mode 100644 vendor/sigar/cmake_install.cmake create mode 100644 vendor/sigar/include/sigar.h create mode 100644 vendor/sigar/include/sigar_fileinfo.h create mode 100644 vendor/sigar/include/sigar_format.h create mode 100644 vendor/sigar/include/sigar_getline.h create mode 100644 vendor/sigar/include/sigar_log.h create mode 100644 vendor/sigar/include/sigar_private.h create mode 100644 vendor/sigar/include/sigar_ptql.h create mode 100644 vendor/sigar/include/sigar_util.h create mode 100644 vendor/sigar/libsigar_debug.a create mode 100644 vendor/sigar/src/os/aix/aix_sigar.c create mode 100644 vendor/sigar/src/os/aix/sigar_os.h create mode 100644 vendor/sigar/src/os/darwin/darwin_sigar.c create mode 100644 vendor/sigar/src/os/darwin/sigar_os.h create mode 100644 vendor/sigar/src/os/hpux/hpux_sigar.c create mode 100644 vendor/sigar/src/os/hpux/sigar_os.h create mode 100644 vendor/sigar/src/os/linux/linux_sigar.c create mode 100644 vendor/sigar/src/os/linux/sigar_os.h create mode 100644 vendor/sigar/src/os/solaris/get_mib2.c create mode 100644 vendor/sigar/src/os/solaris/get_mib2.h create mode 100644 vendor/sigar/src/os/solaris/kstats.c create mode 100644 vendor/sigar/src/os/solaris/procfs.c create mode 100644 vendor/sigar/src/os/solaris/sigar_os.h create mode 100644 vendor/sigar/src/os/solaris/solaris_sigar.c create mode 100644 vendor/sigar/src/os/win32/peb.c create mode 100755 vendor/sigar/src/os/win32/sigar_os.h create mode 100644 vendor/sigar/src/os/win32/sigar_pdh.h create mode 100755 vendor/sigar/src/os/win32/win32_sigar.c create mode 100644 vendor/sigar/src/os/win32/wmi.cpp create mode 100644 vendor/sigar/src/sigar.c create mode 100644 vendor/sigar/src/sigar_cache.c create mode 100644 vendor/sigar/src/sigar_fileinfo.c create mode 100644 vendor/sigar/src/sigar_format.c create mode 100644 vendor/sigar/src/sigar_getline.c create mode 100644 vendor/sigar/src/sigar_ptql.c create mode 100644 vendor/sigar/src/sigar_signal.c create mode 100644 vendor/sigar/src/sigar_util.c create mode 100644 vendor/sigar/src/sigar_version_autoconf.c diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt new file mode 100644 index 0000000..919e5c8 --- /dev/null +++ b/vendor/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory( libssh2-1.4.2 ) +add_subdirectory( sigar ) diff --git a/vendor/libssh2-1.4.2/AUTHORS b/vendor/libssh2-1.4.2/AUTHORS new file mode 100644 index 0000000..214fca9 --- /dev/null +++ b/vendor/libssh2-1.4.2/AUTHORS @@ -0,0 +1,48 @@ + libssh2 is the result of many friendly people. This list is an attempt to + mention all contributors. If we've missed anyone, tell us! + + This list of names is a-z sorted. + +Adam Gobiowski +Alexander Holyapin +Alexander Lamaison +Ben Kibbey +Bjorn Stenborg +Carlo Bramini +Dan Casey +Dan Fandrich +Daniel Stenberg +David J Sullivan +David Robins +Edink Kadribasic +Erik Brossler +Francois Dupoux +Guenter Knauf +Heiner Steven +James Housleys +Jean-Louis Charton +Jussi Mononen +Mark McPherson +Markus Moeller +Mike Protts +Mikhail Gusarov +Neil Gierman +Olivier Hervieu +Paul Veldkamp +Peter Krempa +Peter O'Gorman +Peter Stuge +Romain Bondue +Sara Golemon +Satish Mittal +Sean Peterson +Selcuk Gueney +Simon Hart +Simon Josefsson +Steven Ayre +Steven Van Ingelgem +Tor Arntsen +Vincent Jaulin +Vlad Grachov +Wez Furlong +Yang Tse diff --git a/vendor/libssh2-1.4.2/CMakeFiles/CMakeDirectoryInformation.cmake b/vendor/libssh2-1.4.2/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000..040550b --- /dev/null +++ b/vendor/libssh2-1.4.2/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Relative path conversion top directories. +SET(CMAKE_RELATIVE_PATH_TOP_SOURCE "/Users/dlarimer/projects/AthenaRuntime") +SET(CMAKE_RELATIVE_PATH_TOP_BINARY "/Users/dlarimer/projects/AthenaRuntime") + +# Force unix paths in dependencies. +SET(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +SET(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +SET(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +SET(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +SET(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/vendor/libssh2-1.4.2/CMakeFiles/progress.marks b/vendor/libssh2-1.4.2/CMakeFiles/progress.marks new file mode 100644 index 0000000..f599e28 --- /dev/null +++ b/vendor/libssh2-1.4.2/CMakeFiles/progress.marks @@ -0,0 +1 @@ +10 diff --git a/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/C.includecache b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/C.includecache new file mode 100644 index 0000000..b84d7a1 --- /dev/null +++ b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/C.includecache @@ -0,0 +1,8 @@ +#IncludeRegexLine: ^[ ]*#[ ]*(include|import)[ ]*[<"]([^">]+)([">]) + +#IncludeRegexScan: ^.*$ + +#IncludeRegexComplain: ^$ + +#IncludeRegexTransform: + diff --git a/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/DependInfo.cmake b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/DependInfo.cmake new file mode 100644 index 0000000..e39632b --- /dev/null +++ b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/DependInfo.cmake @@ -0,0 +1,48 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "C" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_C + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/agent.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/channel.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/comp.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypt.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/global.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/hostkey.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/keepalive.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/kex.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/knownhost.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/mac.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/packet.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/pem.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/publickey.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/scp.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/session.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/sftp.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/transport.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/userauth.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/version.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o" + ) +SET(CMAKE_C_COMPILER_ID "GNU") + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "." + "/usr/local/include" + "vendor/fc/include" + "libs/cpparchive/include" + "/opt/local/include" + "libs/fa/include" + "vendor/fc/vendor/libssh2-1.4.2/include" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make new file mode 100644 index 0000000..32ee942 --- /dev/null +++ b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make @@ -0,0 +1,649 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/dlarimer/projects/AthenaRuntime + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/dlarimer/projects/AthenaRuntime + +# Include any dependencies generated for this target. +include vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/depend.make + +# Include the progress variables for this target. +include vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/progress.make + +# Include the compile flags for this target's objects. +include vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: vendor/fc/vendor/libssh2-1.4.2/src/agent.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/agent.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/agent.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/agent.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/agent.c > CMakeFiles/ssh2.dir/src/agent.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/agent.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/agent.c -o CMakeFiles/ssh2.dir/src/agent.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/channel.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_2) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/channel.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/channel.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/channel.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/channel.c > CMakeFiles/ssh2.dir/src/channel.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/channel.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/channel.c -o CMakeFiles/ssh2.dir/src/channel.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/comp.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_3) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/comp.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/comp.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/comp.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/comp.c > CMakeFiles/ssh2.dir/src/comp.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/comp.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/comp.c -o CMakeFiles/ssh2.dir/src/comp.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypt.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_4) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/crypt.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypt.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/crypt.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypt.c > CMakeFiles/ssh2.dir/src/crypt.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/crypt.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypt.c -o CMakeFiles/ssh2.dir/src/crypt.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: vendor/fc/vendor/libssh2-1.4.2/src/global.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_5) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/global.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/global.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/global.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/global.c > CMakeFiles/ssh2.dir/src/global.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/global.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/global.c -o CMakeFiles/ssh2.dir/src/global.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/hostkey.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_6) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/hostkey.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/hostkey.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/hostkey.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/hostkey.c > CMakeFiles/ssh2.dir/src/hostkey.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/hostkey.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/hostkey.c -o CMakeFiles/ssh2.dir/src/hostkey.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: vendor/fc/vendor/libssh2-1.4.2/src/keepalive.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_7) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/keepalive.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/keepalive.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/keepalive.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/keepalive.c > CMakeFiles/ssh2.dir/src/keepalive.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/keepalive.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/keepalive.c -o CMakeFiles/ssh2.dir/src/keepalive.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/kex.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_8) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/kex.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/kex.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/kex.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/kex.c > CMakeFiles/ssh2.dir/src/kex.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/kex.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/kex.c -o CMakeFiles/ssh2.dir/src/kex.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: vendor/fc/vendor/libssh2-1.4.2/src/knownhost.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_9) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/knownhost.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/knownhost.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/knownhost.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/knownhost.c > CMakeFiles/ssh2.dir/src/knownhost.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/knownhost.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/knownhost.c -o CMakeFiles/ssh2.dir/src/knownhost.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_10) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/libgcrypt.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/libgcrypt.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.c > CMakeFiles/ssh2.dir/src/libgcrypt.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/libgcrypt.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.c -o CMakeFiles/ssh2.dir/src/libgcrypt.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: vendor/fc/vendor/libssh2-1.4.2/src/mac.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_11) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/mac.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/mac.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/mac.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/mac.c > CMakeFiles/ssh2.dir/src/mac.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/mac.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/mac.c -o CMakeFiles/ssh2.dir/src/mac.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_12) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/misc.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/misc.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.c > CMakeFiles/ssh2.dir/src/misc.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/misc.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.c -o CMakeFiles/ssh2.dir/src/misc.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_13) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/openssl.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/openssl.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.c > CMakeFiles/ssh2.dir/src/openssl.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/openssl.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.c -o CMakeFiles/ssh2.dir/src/openssl.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/src/packet.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_14) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/packet.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/packet.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/packet.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/packet.c > CMakeFiles/ssh2.dir/src/packet.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/packet.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/packet.c -o CMakeFiles/ssh2.dir/src/packet.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: vendor/fc/vendor/libssh2-1.4.2/src/pem.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_15) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/pem.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/pem.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/pem.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/pem.c > CMakeFiles/ssh2.dir/src/pem.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/pem.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/pem.c -o CMakeFiles/ssh2.dir/src/pem.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/publickey.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_16) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/publickey.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/publickey.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/publickey.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/publickey.c > CMakeFiles/ssh2.dir/src/publickey.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/publickey.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/publickey.c -o CMakeFiles/ssh2.dir/src/publickey.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/scp.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_17) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/scp.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/scp.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/scp.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/scp.c > CMakeFiles/ssh2.dir/src/scp.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/scp.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/scp.c -o CMakeFiles/ssh2.dir/src/scp.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/session.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_18) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/session.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/session.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/session.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/session.c > CMakeFiles/ssh2.dir/src/session.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/session.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/session.c -o CMakeFiles/ssh2.dir/src/session.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/sftp.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_19) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/sftp.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/sftp.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/sftp.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/sftp.c > CMakeFiles/ssh2.dir/src/sftp.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/sftp.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/sftp.c -o CMakeFiles/ssh2.dir/src/sftp.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/src/transport.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_20) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/transport.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/transport.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/transport.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/transport.c > CMakeFiles/ssh2.dir/src/transport.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/transport.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/transport.c -o CMakeFiles/ssh2.dir/src/transport.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/userauth.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_21) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/userauth.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/userauth.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/userauth.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/userauth.c > CMakeFiles/ssh2.dir/src/userauth.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/userauth.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/userauth.c -o CMakeFiles/ssh2.dir/src/userauth.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: vendor/fc/vendor/libssh2-1.4.2/src/version.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_22) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/ssh2.dir/src/version.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/version.c + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/ssh2.dir/src/version.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/version.c > CMakeFiles/ssh2.dir/src/version.c.i + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/ssh2.dir/src/version.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/version.c -o CMakeFiles/ssh2.dir/src/version.c.s + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o.requires: +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o.requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o.provides: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o.requires + $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o.provides.build +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o.provides + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o.provides.build: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o + +# Object files for target ssh2 +ssh2_OBJECTS = \ +"CMakeFiles/ssh2.dir/src/agent.c.o" \ +"CMakeFiles/ssh2.dir/src/channel.c.o" \ +"CMakeFiles/ssh2.dir/src/comp.c.o" \ +"CMakeFiles/ssh2.dir/src/crypt.c.o" \ +"CMakeFiles/ssh2.dir/src/global.c.o" \ +"CMakeFiles/ssh2.dir/src/hostkey.c.o" \ +"CMakeFiles/ssh2.dir/src/keepalive.c.o" \ +"CMakeFiles/ssh2.dir/src/kex.c.o" \ +"CMakeFiles/ssh2.dir/src/knownhost.c.o" \ +"CMakeFiles/ssh2.dir/src/libgcrypt.c.o" \ +"CMakeFiles/ssh2.dir/src/mac.c.o" \ +"CMakeFiles/ssh2.dir/src/misc.c.o" \ +"CMakeFiles/ssh2.dir/src/openssl.c.o" \ +"CMakeFiles/ssh2.dir/src/packet.c.o" \ +"CMakeFiles/ssh2.dir/src/pem.c.o" \ +"CMakeFiles/ssh2.dir/src/publickey.c.o" \ +"CMakeFiles/ssh2.dir/src/scp.c.o" \ +"CMakeFiles/ssh2.dir/src/session.c.o" \ +"CMakeFiles/ssh2.dir/src/sftp.c.o" \ +"CMakeFiles/ssh2.dir/src/transport.c.o" \ +"CMakeFiles/ssh2.dir/src/userauth.c.o" \ +"CMakeFiles/ssh2.dir/src/version.c.o" + +# External object files for target ssh2 +ssh2_EXTERNAL_OBJECTS = + +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make +vendor/fc/vendor/libssh2-1.4.2/libssh2.a: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking C static library libssh2.a" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && $(CMAKE_COMMAND) -P CMakeFiles/ssh2.dir/cmake_clean_target.cmake + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/ssh2.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build: vendor/fc/vendor/libssh2-1.4.2/libssh2.a +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o.requires +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o.requires +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/requires + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/clean: + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 && $(CMAKE_COMMAND) -P CMakeFiles/ssh2.dir/cmake_clean.cmake +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/clean + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/depend: + cd /Users/dlarimer/projects/AthenaRuntime && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /Users/dlarimer/projects/AthenaRuntime /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 /Users/dlarimer/projects/AthenaRuntime /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/depend + diff --git a/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/cmake_clean.cmake b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/cmake_clean.cmake new file mode 100644 index 0000000..63d2db6 --- /dev/null +++ b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/cmake_clean.cmake @@ -0,0 +1,31 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/ssh2.dir/src/agent.c.o" + "CMakeFiles/ssh2.dir/src/channel.c.o" + "CMakeFiles/ssh2.dir/src/comp.c.o" + "CMakeFiles/ssh2.dir/src/crypt.c.o" + "CMakeFiles/ssh2.dir/src/global.c.o" + "CMakeFiles/ssh2.dir/src/hostkey.c.o" + "CMakeFiles/ssh2.dir/src/keepalive.c.o" + "CMakeFiles/ssh2.dir/src/kex.c.o" + "CMakeFiles/ssh2.dir/src/knownhost.c.o" + "CMakeFiles/ssh2.dir/src/libgcrypt.c.o" + "CMakeFiles/ssh2.dir/src/mac.c.o" + "CMakeFiles/ssh2.dir/src/misc.c.o" + "CMakeFiles/ssh2.dir/src/openssl.c.o" + "CMakeFiles/ssh2.dir/src/packet.c.o" + "CMakeFiles/ssh2.dir/src/pem.c.o" + "CMakeFiles/ssh2.dir/src/publickey.c.o" + "CMakeFiles/ssh2.dir/src/scp.c.o" + "CMakeFiles/ssh2.dir/src/session.c.o" + "CMakeFiles/ssh2.dir/src/sftp.c.o" + "CMakeFiles/ssh2.dir/src/transport.c.o" + "CMakeFiles/ssh2.dir/src/userauth.c.o" + "CMakeFiles/ssh2.dir/src/version.c.o" + "libssh2.pdb" + "libssh2.a" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang C) + INCLUDE(CMakeFiles/ssh2.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/cmake_clean_target.cmake b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/cmake_clean_target.cmake new file mode 100644 index 0000000..a016209 --- /dev/null +++ b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/cmake_clean_target.cmake @@ -0,0 +1,3 @@ +FILE(REMOVE_RECURSE + "libssh2.a" +) diff --git a/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/depend.internal b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/depend.internal new file mode 100644 index 0000000..6d3a9ee --- /dev/null +++ b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/depend.internal @@ -0,0 +1,1098 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/agent.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/session.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/userauth.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/channel.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/channel.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/packet.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/session.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/transport.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/comp.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/comp.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /opt/local/include/zconf.h + /opt/local/include/zlib.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypt.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/global.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/hostkey.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/keepalive.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/packet.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/transport.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/comp.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/kex.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/mac.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/packet.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/transport.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/knownhost.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/mac.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/mac.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/aes.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/channel.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/packet.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/packet.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/transport.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/pem.c + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/channel.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/publickey.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/session.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/channel.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/scp.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/session.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/channel.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/mac.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/packet.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/session.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/session.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/transport.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/channel.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/session.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/sftp.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/sftp.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/mac.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/packet.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/transport.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/transport.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/packet.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/session.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/transport.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/userauth.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/userauth.h + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/crypto.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/misc.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/openssl.h + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/src/version.c + /opt/local/include/gcrypt-module.h + /opt/local/include/gcrypt.h + /opt/local/include/gpg-error.h + /opt/local/include/openssl/asn1.h + /opt/local/include/openssl/bio.h + /opt/local/include/openssl/bn.h + /opt/local/include/openssl/buffer.h + /opt/local/include/openssl/crypto.h + /opt/local/include/openssl/dh.h + /opt/local/include/openssl/dsa.h + /opt/local/include/openssl/e_os2.h + /opt/local/include/openssl/ebcdic.h + /opt/local/include/openssl/ec.h + /opt/local/include/openssl/ecdh.h + /opt/local/include/openssl/ecdsa.h + /opt/local/include/openssl/evp.h + /opt/local/include/openssl/hmac.h + /opt/local/include/openssl/lhash.h + /opt/local/include/openssl/md5.h + /opt/local/include/openssl/obj_mac.h + /opt/local/include/openssl/objects.h + /opt/local/include/openssl/opensslconf.h + /opt/local/include/openssl/opensslv.h + /opt/local/include/openssl/ossl_typ.h + /opt/local/include/openssl/pem.h + /opt/local/include/openssl/pem2.h + /opt/local/include/openssl/pkcs7.h + /opt/local/include/openssl/rand.h + /opt/local/include/openssl/rsa.h + /opt/local/include/openssl/safestack.h + /opt/local/include/openssl/sha.h + /opt/local/include/openssl/stack.h + /opt/local/include/openssl/symhacks.h + /opt/local/include/openssl/x509.h + /opt/local/include/openssl/x509_vfy.h + /usr/local/include/libssh2.h + /usr/local/include/libssh2_publickey.h + /usr/local/include/libssh2_sftp.h diff --git a/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/depend.make b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/depend.make new file mode 100644 index 0000000..0f479f6 --- /dev/null +++ b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/depend.make @@ -0,0 +1,1098 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: vendor/fc/vendor/libssh2-1.4.2/src/agent.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: vendor/fc/vendor/libssh2-1.4.2/src/session.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: vendor/fc/vendor/libssh2-1.4.2/src/userauth.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/channel.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/channel.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/packet.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/session.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: vendor/fc/vendor/libssh2-1.4.2/src/transport.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/comp.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/comp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/zconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /opt/local/include/zlib.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypt.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: vendor/fc/vendor/libssh2-1.4.2/src/global.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/hostkey.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: vendor/fc/vendor/libssh2-1.4.2/src/keepalive.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: vendor/fc/vendor/libssh2-1.4.2/src/packet.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: vendor/fc/vendor/libssh2-1.4.2/src/transport.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/comp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/kex.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/packet.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: vendor/fc/vendor/libssh2-1.4.2/src/transport.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: vendor/fc/vendor/libssh2-1.4.2/src/knownhost.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: vendor/fc/vendor/libssh2-1.4.2/src/mac.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: vendor/fc/vendor/libssh2-1.4.2/src/mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/aes.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/src/channel.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/src/packet.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/src/packet.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: vendor/fc/vendor/libssh2-1.4.2/src/transport.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: vendor/fc/vendor/libssh2-1.4.2/src/pem.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/channel.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/publickey.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: vendor/fc/vendor/libssh2-1.4.2/src/session.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/channel.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/scp.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/session.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/channel.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/packet.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/session.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/session.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: vendor/fc/vendor/libssh2-1.4.2/src/transport.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/channel.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/session.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/sftp.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: vendor/fc/vendor/libssh2-1.4.2/src/sftp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/src/mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/src/packet.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/src/transport.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: vendor/fc/vendor/libssh2-1.4.2/src/transport.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/packet.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/session.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/transport.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/userauth.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: vendor/fc/vendor/libssh2-1.4.2/src/userauth.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o: /usr/local/include/libssh2_sftp.h + +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: vendor/fc/vendor/libssh2-1.4.2/src/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libgcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_osx.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_config_win.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: vendor/fc/vendor/libssh2-1.4.2/src/libssh2_priv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: vendor/fc/vendor/libssh2-1.4.2/src/misc.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: vendor/fc/vendor/libssh2-1.4.2/src/openssl.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: vendor/fc/vendor/libssh2-1.4.2/src/version.c +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/gcrypt-module.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/gcrypt.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/gpg-error.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/asn1.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/bio.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/bn.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/buffer.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/crypto.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/dh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/dsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/e_os2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/ebcdic.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/ec.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/ecdh.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/ecdsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/evp.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/hmac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/lhash.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/md5.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/obj_mac.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/objects.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/opensslconf.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/opensslv.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/ossl_typ.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/pem.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/pem2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/pkcs7.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/rand.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/rsa.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/safestack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/sha.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/stack.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/symhacks.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/x509.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /opt/local/include/openssl/x509_vfy.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /usr/local/include/libssh2.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /usr/local/include/libssh2_publickey.h +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o: /usr/local/include/libssh2_sftp.h + diff --git a/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make new file mode 100644 index 0000000..07d723b --- /dev/null +++ b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile C with /opt/local/bin/gcc +C_FLAGS = -O3 -DNDEBUG -I/Users/dlarimer/projects/AthenaRuntime -I/usr/local/include -I/Users/dlarimer/projects/AthenaRuntime/vendor/fc/include -I/Users/dlarimer/projects/AthenaRuntime/libs/cpparchive/include -I/opt/local/include -I/Users/dlarimer/projects/AthenaRuntime/libs/fa/include -I/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/include + +C_DEFINES = + diff --git a/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/link.txt b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/link.txt new file mode 100644 index 0000000..f524545 --- /dev/null +++ b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/link.txt @@ -0,0 +1,2 @@ +/opt/local/bin/ar cr libssh2.a CMakeFiles/ssh2.dir/src/agent.c.o CMakeFiles/ssh2.dir/src/channel.c.o CMakeFiles/ssh2.dir/src/comp.c.o CMakeFiles/ssh2.dir/src/crypt.c.o CMakeFiles/ssh2.dir/src/global.c.o CMakeFiles/ssh2.dir/src/hostkey.c.o CMakeFiles/ssh2.dir/src/keepalive.c.o CMakeFiles/ssh2.dir/src/kex.c.o CMakeFiles/ssh2.dir/src/knownhost.c.o CMakeFiles/ssh2.dir/src/libgcrypt.c.o CMakeFiles/ssh2.dir/src/mac.c.o CMakeFiles/ssh2.dir/src/misc.c.o CMakeFiles/ssh2.dir/src/openssl.c.o CMakeFiles/ssh2.dir/src/packet.c.o CMakeFiles/ssh2.dir/src/pem.c.o CMakeFiles/ssh2.dir/src/publickey.c.o CMakeFiles/ssh2.dir/src/scp.c.o CMakeFiles/ssh2.dir/src/session.c.o CMakeFiles/ssh2.dir/src/sftp.c.o CMakeFiles/ssh2.dir/src/transport.c.o CMakeFiles/ssh2.dir/src/userauth.c.o CMakeFiles/ssh2.dir/src/version.c.o +/opt/local/bin/ranlib libssh2.a diff --git a/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/progress.make b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/progress.make new file mode 100644 index 0000000..a75bb90 --- /dev/null +++ b/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/progress.make @@ -0,0 +1,23 @@ +CMAKE_PROGRESS_1 = +CMAKE_PROGRESS_2 = 75 +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = 76 +CMAKE_PROGRESS_5 = +CMAKE_PROGRESS_6 = 77 +CMAKE_PROGRESS_7 = +CMAKE_PROGRESS_8 = 78 +CMAKE_PROGRESS_9 = +CMAKE_PROGRESS_10 = 79 +CMAKE_PROGRESS_11 = +CMAKE_PROGRESS_12 = 80 +CMAKE_PROGRESS_13 = +CMAKE_PROGRESS_14 = +CMAKE_PROGRESS_15 = 81 +CMAKE_PROGRESS_16 = +CMAKE_PROGRESS_17 = 82 +CMAKE_PROGRESS_18 = +CMAKE_PROGRESS_19 = 83 +CMAKE_PROGRESS_20 = +CMAKE_PROGRESS_21 = 84 +CMAKE_PROGRESS_22 = + diff --git a/vendor/libssh2-1.4.2/CMakeLists.txt b/vendor/libssh2-1.4.2/CMakeLists.txt new file mode 100644 index 0000000..a982813 --- /dev/null +++ b/vendor/libssh2-1.4.2/CMakeLists.txt @@ -0,0 +1,28 @@ +include_directories(include) +include_directories( ${OPENSSL_INCLUDE_DIR} ) +SET( sources + src/agent.c + src/channel.c + src/comp.c + src/crypt.c + src/global.c + src/hostkey.c + src/keepalive.c + src/kex.c + src/knownhost.c + src/libgcrypt.c + src/mac.c + src/misc.c + src/openssl.c + src/packet.c + src/pem.c + src/publickey.c + src/scp.c + src/session.c + src/sftp.c + src/transport.c + src/userauth.c + src/version.c +) + +SETUP_LIBRARY( ssh2 SOURCES ${sources} LIBRARIES ${libraries} LIBRARY_TYPE STATIC ) diff --git a/vendor/libssh2-1.4.2/COPYING b/vendor/libssh2-1.4.2/COPYING new file mode 100644 index 0000000..1bd78c9 --- /dev/null +++ b/vendor/libssh2-1.4.2/COPYING @@ -0,0 +1,42 @@ +/* Copyright (c) 2004-2007 Sara Golemon + * Copyright (c) 2005,2006 Mikhail Gusarov + * Copyright (c) 2006-2007 The Written Word, Inc. + * Copyright (c) 2007 Eli Fant + * Copyright (c) 2009 Daniel Stenberg + * Copyright (C) 2008, 2009 Simon Josefsson + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + diff --git a/vendor/libssh2-1.4.2/ChangeLog b/vendor/libssh2-1.4.2/ChangeLog new file mode 100644 index 0000000..404c887 --- /dev/null +++ b/vendor/libssh2-1.4.2/ChangeLog @@ -0,0 +1 @@ +see NEWS diff --git a/vendor/libssh2-1.4.2/HACKING b/vendor/libssh2-1.4.2/HACKING new file mode 100644 index 0000000..5da8e66 --- /dev/null +++ b/vendor/libssh2-1.4.2/HACKING @@ -0,0 +1,13 @@ + +libssh2 source code style guide: + + - 4 level indent + - spaces-only (no tabs) + - open braces on the if/for line: + + if (banana) { + go_nuts(); + } + + - keep source lines shorter than 80 columns + - See libssh2-style.el for how to achieve this within Emacs diff --git a/vendor/libssh2-1.4.2/Makefile b/vendor/libssh2-1.4.2/Makefile new file mode 100644 index 0000000..7aecd2a --- /dev/null +++ b/vendor/libssh2-1.4.2/Makefile @@ -0,0 +1,776 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/dlarimer/projects/AthenaRuntime + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/dlarimer/projects/AthenaRuntime + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." + /opt/local/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /opt/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: install/local +.PHONY : install/local/fast + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /opt/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: install/strip +.PHONY : install/strip/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /opt/local/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + cd /Users/dlarimer/projects/AthenaRuntime && $(CMAKE_COMMAND) -E cmake_progress_start /Users/dlarimer/projects/AthenaRuntime/CMakeFiles /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/progress.marks + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f CMakeFiles/Makefile2 vendor/fc/vendor/libssh2-1.4.2/all + $(CMAKE_COMMAND) -E cmake_progress_start /Users/dlarimer/projects/AthenaRuntime/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f CMakeFiles/Makefile2 vendor/fc/vendor/libssh2-1.4.2/clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f CMakeFiles/Makefile2 vendor/fc/vendor/libssh2-1.4.2/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f CMakeFiles/Makefile2 vendor/fc/vendor/libssh2-1.4.2/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /Users/dlarimer/projects/AthenaRuntime && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Convenience name for target. +vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/rule: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f CMakeFiles/Makefile2 vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/rule +.PHONY : vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/rule + +# Convenience name for target. +ssh2: vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/rule +.PHONY : ssh2 + +# fast build rule for target. +ssh2/fast: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build +.PHONY : ssh2/fast + +src/agent.o: src/agent.c.o +.PHONY : src/agent.o + +# target to build an object file +src/agent.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.o +.PHONY : src/agent.c.o + +src/agent.i: src/agent.c.i +.PHONY : src/agent.i + +# target to preprocess a source file +src/agent.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.i +.PHONY : src/agent.c.i + +src/agent.s: src/agent.c.s +.PHONY : src/agent.s + +# target to generate assembly for a file +src/agent.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/agent.c.s +.PHONY : src/agent.c.s + +src/channel.o: src/channel.c.o +.PHONY : src/channel.o + +# target to build an object file +src/channel.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.o +.PHONY : src/channel.c.o + +src/channel.i: src/channel.c.i +.PHONY : src/channel.i + +# target to preprocess a source file +src/channel.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.i +.PHONY : src/channel.c.i + +src/channel.s: src/channel.c.s +.PHONY : src/channel.s + +# target to generate assembly for a file +src/channel.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/channel.c.s +.PHONY : src/channel.c.s + +src/comp.o: src/comp.c.o +.PHONY : src/comp.o + +# target to build an object file +src/comp.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.o +.PHONY : src/comp.c.o + +src/comp.i: src/comp.c.i +.PHONY : src/comp.i + +# target to preprocess a source file +src/comp.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.i +.PHONY : src/comp.c.i + +src/comp.s: src/comp.c.s +.PHONY : src/comp.s + +# target to generate assembly for a file +src/comp.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/comp.c.s +.PHONY : src/comp.c.s + +src/crypt.o: src/crypt.c.o +.PHONY : src/crypt.o + +# target to build an object file +src/crypt.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.o +.PHONY : src/crypt.c.o + +src/crypt.i: src/crypt.c.i +.PHONY : src/crypt.i + +# target to preprocess a source file +src/crypt.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.i +.PHONY : src/crypt.c.i + +src/crypt.s: src/crypt.c.s +.PHONY : src/crypt.s + +# target to generate assembly for a file +src/crypt.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/crypt.c.s +.PHONY : src/crypt.c.s + +src/global.o: src/global.c.o +.PHONY : src/global.o + +# target to build an object file +src/global.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.o +.PHONY : src/global.c.o + +src/global.i: src/global.c.i +.PHONY : src/global.i + +# target to preprocess a source file +src/global.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.i +.PHONY : src/global.c.i + +src/global.s: src/global.c.s +.PHONY : src/global.s + +# target to generate assembly for a file +src/global.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/global.c.s +.PHONY : src/global.c.s + +src/hostkey.o: src/hostkey.c.o +.PHONY : src/hostkey.o + +# target to build an object file +src/hostkey.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.o +.PHONY : src/hostkey.c.o + +src/hostkey.i: src/hostkey.c.i +.PHONY : src/hostkey.i + +# target to preprocess a source file +src/hostkey.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.i +.PHONY : src/hostkey.c.i + +src/hostkey.s: src/hostkey.c.s +.PHONY : src/hostkey.s + +# target to generate assembly for a file +src/hostkey.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/hostkey.c.s +.PHONY : src/hostkey.c.s + +src/keepalive.o: src/keepalive.c.o +.PHONY : src/keepalive.o + +# target to build an object file +src/keepalive.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.o +.PHONY : src/keepalive.c.o + +src/keepalive.i: src/keepalive.c.i +.PHONY : src/keepalive.i + +# target to preprocess a source file +src/keepalive.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.i +.PHONY : src/keepalive.c.i + +src/keepalive.s: src/keepalive.c.s +.PHONY : src/keepalive.s + +# target to generate assembly for a file +src/keepalive.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/keepalive.c.s +.PHONY : src/keepalive.c.s + +src/kex.o: src/kex.c.o +.PHONY : src/kex.o + +# target to build an object file +src/kex.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.o +.PHONY : src/kex.c.o + +src/kex.i: src/kex.c.i +.PHONY : src/kex.i + +# target to preprocess a source file +src/kex.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.i +.PHONY : src/kex.c.i + +src/kex.s: src/kex.c.s +.PHONY : src/kex.s + +# target to generate assembly for a file +src/kex.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/kex.c.s +.PHONY : src/kex.c.s + +src/knownhost.o: src/knownhost.c.o +.PHONY : src/knownhost.o + +# target to build an object file +src/knownhost.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.o +.PHONY : src/knownhost.c.o + +src/knownhost.i: src/knownhost.c.i +.PHONY : src/knownhost.i + +# target to preprocess a source file +src/knownhost.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.i +.PHONY : src/knownhost.c.i + +src/knownhost.s: src/knownhost.c.s +.PHONY : src/knownhost.s + +# target to generate assembly for a file +src/knownhost.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/knownhost.c.s +.PHONY : src/knownhost.c.s + +src/libgcrypt.o: src/libgcrypt.c.o +.PHONY : src/libgcrypt.o + +# target to build an object file +src/libgcrypt.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.o +.PHONY : src/libgcrypt.c.o + +src/libgcrypt.i: src/libgcrypt.c.i +.PHONY : src/libgcrypt.i + +# target to preprocess a source file +src/libgcrypt.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.i +.PHONY : src/libgcrypt.c.i + +src/libgcrypt.s: src/libgcrypt.c.s +.PHONY : src/libgcrypt.s + +# target to generate assembly for a file +src/libgcrypt.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/libgcrypt.c.s +.PHONY : src/libgcrypt.c.s + +src/mac.o: src/mac.c.o +.PHONY : src/mac.o + +# target to build an object file +src/mac.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.o +.PHONY : src/mac.c.o + +src/mac.i: src/mac.c.i +.PHONY : src/mac.i + +# target to preprocess a source file +src/mac.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.i +.PHONY : src/mac.c.i + +src/mac.s: src/mac.c.s +.PHONY : src/mac.s + +# target to generate assembly for a file +src/mac.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/mac.c.s +.PHONY : src/mac.c.s + +src/misc.o: src/misc.c.o +.PHONY : src/misc.o + +# target to build an object file +src/misc.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.o +.PHONY : src/misc.c.o + +src/misc.i: src/misc.c.i +.PHONY : src/misc.i + +# target to preprocess a source file +src/misc.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.i +.PHONY : src/misc.c.i + +src/misc.s: src/misc.c.s +.PHONY : src/misc.s + +# target to generate assembly for a file +src/misc.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/misc.c.s +.PHONY : src/misc.c.s + +src/openssl.o: src/openssl.c.o +.PHONY : src/openssl.o + +# target to build an object file +src/openssl.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.o +.PHONY : src/openssl.c.o + +src/openssl.i: src/openssl.c.i +.PHONY : src/openssl.i + +# target to preprocess a source file +src/openssl.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.i +.PHONY : src/openssl.c.i + +src/openssl.s: src/openssl.c.s +.PHONY : src/openssl.s + +# target to generate assembly for a file +src/openssl.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/openssl.c.s +.PHONY : src/openssl.c.s + +src/packet.o: src/packet.c.o +.PHONY : src/packet.o + +# target to build an object file +src/packet.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.o +.PHONY : src/packet.c.o + +src/packet.i: src/packet.c.i +.PHONY : src/packet.i + +# target to preprocess a source file +src/packet.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.i +.PHONY : src/packet.c.i + +src/packet.s: src/packet.c.s +.PHONY : src/packet.s + +# target to generate assembly for a file +src/packet.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/packet.c.s +.PHONY : src/packet.c.s + +src/pem.o: src/pem.c.o +.PHONY : src/pem.o + +# target to build an object file +src/pem.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.o +.PHONY : src/pem.c.o + +src/pem.i: src/pem.c.i +.PHONY : src/pem.i + +# target to preprocess a source file +src/pem.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.i +.PHONY : src/pem.c.i + +src/pem.s: src/pem.c.s +.PHONY : src/pem.s + +# target to generate assembly for a file +src/pem.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/pem.c.s +.PHONY : src/pem.c.s + +src/publickey.o: src/publickey.c.o +.PHONY : src/publickey.o + +# target to build an object file +src/publickey.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.o +.PHONY : src/publickey.c.o + +src/publickey.i: src/publickey.c.i +.PHONY : src/publickey.i + +# target to preprocess a source file +src/publickey.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.i +.PHONY : src/publickey.c.i + +src/publickey.s: src/publickey.c.s +.PHONY : src/publickey.s + +# target to generate assembly for a file +src/publickey.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/publickey.c.s +.PHONY : src/publickey.c.s + +src/scp.o: src/scp.c.o +.PHONY : src/scp.o + +# target to build an object file +src/scp.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.o +.PHONY : src/scp.c.o + +src/scp.i: src/scp.c.i +.PHONY : src/scp.i + +# target to preprocess a source file +src/scp.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.i +.PHONY : src/scp.c.i + +src/scp.s: src/scp.c.s +.PHONY : src/scp.s + +# target to generate assembly for a file +src/scp.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/scp.c.s +.PHONY : src/scp.c.s + +src/session.o: src/session.c.o +.PHONY : src/session.o + +# target to build an object file +src/session.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.o +.PHONY : src/session.c.o + +src/session.i: src/session.c.i +.PHONY : src/session.i + +# target to preprocess a source file +src/session.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.i +.PHONY : src/session.c.i + +src/session.s: src/session.c.s +.PHONY : src/session.s + +# target to generate assembly for a file +src/session.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/session.c.s +.PHONY : src/session.c.s + +src/sftp.o: src/sftp.c.o +.PHONY : src/sftp.o + +# target to build an object file +src/sftp.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.o +.PHONY : src/sftp.c.o + +src/sftp.i: src/sftp.c.i +.PHONY : src/sftp.i + +# target to preprocess a source file +src/sftp.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.i +.PHONY : src/sftp.c.i + +src/sftp.s: src/sftp.c.s +.PHONY : src/sftp.s + +# target to generate assembly for a file +src/sftp.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/sftp.c.s +.PHONY : src/sftp.c.s + +src/transport.o: src/transport.c.o +.PHONY : src/transport.o + +# target to build an object file +src/transport.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.o +.PHONY : src/transport.c.o + +src/transport.i: src/transport.c.i +.PHONY : src/transport.i + +# target to preprocess a source file +src/transport.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.i +.PHONY : src/transport.c.i + +src/transport.s: src/transport.c.s +.PHONY : src/transport.s + +# target to generate assembly for a file +src/transport.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/transport.c.s +.PHONY : src/transport.c.s + +src/userauth.o: src/userauth.c.o +.PHONY : src/userauth.o + +# target to build an object file +src/userauth.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.o +.PHONY : src/userauth.c.o + +src/userauth.i: src/userauth.c.i +.PHONY : src/userauth.i + +# target to preprocess a source file +src/userauth.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.i +.PHONY : src/userauth.c.i + +src/userauth.s: src/userauth.c.s +.PHONY : src/userauth.s + +# target to generate assembly for a file +src/userauth.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/userauth.c.s +.PHONY : src/userauth.c.s + +src/version.o: src/version.c.o +.PHONY : src/version.o + +# target to build an object file +src/version.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.o +.PHONY : src/version.c.o + +src/version.i: src/version.c.i +.PHONY : src/version.i + +# target to preprocess a source file +src/version.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.i +.PHONY : src/version.c.i + +src/version.s: src/version.c.s +.PHONY : src/version.s + +# target to generate assembly for a file +src/version.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/build.make vendor/fc/vendor/libssh2-1.4.2/CMakeFiles/ssh2.dir/src/version.c.s +.PHONY : src/version.c.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... rebuild_cache" + @echo "... ssh2" + @echo "... src/agent.o" + @echo "... src/agent.i" + @echo "... src/agent.s" + @echo "... src/channel.o" + @echo "... src/channel.i" + @echo "... src/channel.s" + @echo "... src/comp.o" + @echo "... src/comp.i" + @echo "... src/comp.s" + @echo "... src/crypt.o" + @echo "... src/crypt.i" + @echo "... src/crypt.s" + @echo "... src/global.o" + @echo "... src/global.i" + @echo "... src/global.s" + @echo "... src/hostkey.o" + @echo "... src/hostkey.i" + @echo "... src/hostkey.s" + @echo "... src/keepalive.o" + @echo "... src/keepalive.i" + @echo "... src/keepalive.s" + @echo "... src/kex.o" + @echo "... src/kex.i" + @echo "... src/kex.s" + @echo "... src/knownhost.o" + @echo "... src/knownhost.i" + @echo "... src/knownhost.s" + @echo "... src/libgcrypt.o" + @echo "... src/libgcrypt.i" + @echo "... src/libgcrypt.s" + @echo "... src/mac.o" + @echo "... src/mac.i" + @echo "... src/mac.s" + @echo "... src/misc.o" + @echo "... src/misc.i" + @echo "... src/misc.s" + @echo "... src/openssl.o" + @echo "... src/openssl.i" + @echo "... src/openssl.s" + @echo "... src/packet.o" + @echo "... src/packet.i" + @echo "... src/packet.s" + @echo "... src/pem.o" + @echo "... src/pem.i" + @echo "... src/pem.s" + @echo "... src/publickey.o" + @echo "... src/publickey.i" + @echo "... src/publickey.s" + @echo "... src/scp.o" + @echo "... src/scp.i" + @echo "... src/scp.s" + @echo "... src/session.o" + @echo "... src/session.i" + @echo "... src/session.s" + @echo "... src/sftp.o" + @echo "... src/sftp.i" + @echo "... src/sftp.s" + @echo "... src/transport.o" + @echo "... src/transport.i" + @echo "... src/transport.s" + @echo "... src/userauth.o" + @echo "... src/userauth.i" + @echo "... src/userauth.s" + @echo "... src/version.o" + @echo "... src/version.i" + @echo "... src/version.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /Users/dlarimer/projects/AthenaRuntime && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/vendor/libssh2-1.4.2/README b/vendor/libssh2-1.4.2/README new file mode 100644 index 0000000..d297f31 --- /dev/null +++ b/vendor/libssh2-1.4.2/README @@ -0,0 +1,102 @@ +libssh2 - SSH2 library +====================== + +libssh2 is a library implementing the SSH2 protocol, available under +the revised BSD license. + +Web site: http://www.libssh2.org/ + +Mailing list: http://cool.haxx.se/mailman/listinfo/libssh2-devel + +The rest of this readme does not apply as the build system has been replaced +with CMake for use in mace on windows/linux and mac. + + + +Generic installation instructions are in INSTALL. Some ./configure +options deserve additional comments: + + * --enable-crypt-none + + The SSH2 Transport allows for unencrypted data + transmission using the "none" cipher. Because this is + such a huge security hole, it is typically disabled on + SSH2 implementations and is disabled in libssh2 by + default as well. + + Enabling this option will allow for "none" as a + negotiable method, however it still requires that the + method be advertized by the remote end and that no + more-preferable methods are available. + + * --enable-mac-none + + The SSH2 Transport also allows implementations to + forego a message authentication code. While this is + less of a security risk than using a "none" cipher, it + is still not recommended as disabling MAC hashes + removes a layer of security. + + Enabling this option will allow for "none" as a + negotiable method, however it still requires that the + method be advertized by the remote end and that no + more-preferable methods are available. + + * --disable-gex-new + + The diffie-hellman-group-exchange-sha1 (dh-gex) key + exchange method originally defined an exchange + negotiation using packet type 30 to request a + generation pair based on a single target value. Later + refinement of dh-gex provided for range and target + values. By default libssh2 will use the newer range + method. + + If you experience trouble connecting to an old SSH + server using dh-gex, try this option to fallback on + the older more reliable method. + + * --with-libgcrypt + * --without-libgcrypt + * --with-libgcrypt-prefix=DIR + + libssh2 can use the Libgcrypt library + (http://www.gnupg.org/) for cryptographic operations. + Either Libgcrypt or OpenSSL is required. + + Configure will attempt to locate Libgcrypt + automatically. + + If your installation of Libgcrypt is in another + location, specify it using --with-libgcrypt-prefix. + + * --with-openssl + * --without-openssl + * --with-libssl-prefix=[DIR] + + libssh2 can use the OpenSSL library + (http://www.openssl.org) for cryptographic operations. + Either Libgcrypt or OpenSSL is required. + + Configure will attempt to locate OpenSSL in the + default location. + + If your installation of OpenSSL is in another + location, specify it using --with-libssl-prefix. + + * --with-libz + * --without-libz + * --with-libz-prefix=[DIR] + + If present, libssh2 will attempt to use the zlib + (http://www.zlib.org) for payload compression, however + zlib is not required. + + If your installation of Libz is in another location, + specify it using --with-libz-prefix. + + * --enable-debug + + Will make the build use more pedantic and strict compiler + options as well as enable the libssh2_trace() function (for + showing debug traces). diff --git a/vendor/libssh2-1.4.2/RELEASE-NOTES b/vendor/libssh2-1.4.2/RELEASE-NOTES new file mode 100644 index 0000000..ee52e8c --- /dev/null +++ b/vendor/libssh2-1.4.2/RELEASE-NOTES @@ -0,0 +1,21 @@ +libssh2 1.4.2 + +This release includes the following bugfixes: + + o Return LIBSSH2_ERROR_SOCKET_DISCONNECT on EOF when reading banner + o userauth.c: fread() from public key file to correctly detect any errors + o configure.ac: Add option to disable build of the example applications + o Added 'Requires.private:' line to libssh2.pc + o SFTP: filter off incoming "zombie" responses + o gettimeofday: no need for a replacement under cygwin + o SSH_MSG_CHANNEL_REQUEST: default to want_reply + o win32/libssh2_config.h: Remove hardcoded #define LIBSSH2_HAVE_ZLIB + +This release would not have looked like this without help, code, reports and +advice from friends like these: + + Alexander Lamaison, Rafael Kitover, Guenter Knauf, Peter Stuge, + Oleksiy Zagorskyi + + Thanks! (and sorry if I forgot to mention someone) + diff --git a/vendor/libssh2-1.4.2/cmake_install.cmake b/vendor/libssh2-1.4.2/cmake_install.cmake new file mode 100644 index 0000000..52195e4 --- /dev/null +++ b/vendor/libssh2-1.4.2/cmake_install.cmake @@ -0,0 +1,37 @@ +# Install script for directory: /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2 + +# Set the install prefix +IF(NOT DEFINED CMAKE_INSTALL_PREFIX) + SET(CMAKE_INSTALL_PREFIX "/usr/local") +ENDIF(NOT DEFINED CMAKE_INSTALL_PREFIX) +STRING(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +IF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + IF(BUILD_TYPE) + STRING(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + ELSE(BUILD_TYPE) + SET(CMAKE_INSTALL_CONFIG_NAME "Release") + ENDIF(BUILD_TYPE) + MESSAGE(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +ENDIF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + +# Set the component getting installed. +IF(NOT CMAKE_INSTALL_COMPONENT) + IF(COMPONENT) + MESSAGE(STATUS "Install component: \"${COMPONENT}\"") + SET(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + ELSE(COMPONENT) + SET(CMAKE_INSTALL_COMPONENT) + ENDIF(COMPONENT) +ENDIF(NOT CMAKE_INSTALL_COMPONENT) + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE STATIC_LIBRARY FILES "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/libssh2.a") + IF(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libssh2.a" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libssh2.a") + EXECUTE_PROCESS(COMMAND "/opt/local/bin/ranlib" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libssh2.a") + ENDIF() +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + diff --git a/vendor/libssh2-1.4.2/include/libssh2.h b/vendor/libssh2-1.4.2/include/libssh2.h new file mode 100644 index 0000000..6af0028 --- /dev/null +++ b/vendor/libssh2-1.4.2/include/libssh2.h @@ -0,0 +1,1188 @@ +/* Copyright (c) 2004-2009, Sara Golemon + * Copyright (c) 2009-2012 Daniel Stenberg + * Copyright (c) 2010 Simon Josefsson + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#ifndef LIBSSH2_H +#define LIBSSH2_H 1 + +#define LIBSSH2_COPYRIGHT "2004-2012 The libssh2 project and its contributors." + +/* We use underscore instead of dash when appending DEV in dev versions just + to make the BANNER define (used by src/session.c) be a valid SSH + banner. Release versions have no appended strings and may of course not + have dashes either. */ +#define LIBSSH2_VERSION "1.4.2" + +/* The numeric version number is also available "in parts" by using these + defines: */ +#define LIBSSH2_VERSION_MAJOR 1 +#define LIBSSH2_VERSION_MINOR 4 +#define LIBSSH2_VERSION_PATCH 2 + +/* This is the numeric version of the libssh2 version number, meant for easier + parsing and comparions by programs. The LIBSSH2_VERSION_NUM define will + always follow this syntax: + + 0xXXYYZZ + + Where XX, YY and ZZ are the main version, release and patch numbers in + hexadecimal (using 8 bits each). All three numbers are always represented + using two digits. 1.2 would appear as "0x010200" while version 9.11.7 + appears as "0x090b07". + + This 6-digit (24 bits) hexadecimal number does not show pre-release number, + and it is always a greater number in a more recent release. It makes + comparisons with greater than and less than work. +*/ +#define LIBSSH2_VERSION_NUM 0x010402 + +/* + * This is the date and time when the full source package was created. The + * timestamp is not stored in the source code repo, as the timestamp is + * properly set in the tarballs by the maketgz script. + * + * The format of the date should follow this template: + * + * "Mon Feb 12 11:35:33 UTC 2007" + */ +#define LIBSSH2_TIMESTAMP "Fri May 18 21:30:56 UTC 2012" + +#ifndef RC_INVOKED + +#ifdef __cplusplus +extern "C" { +#endif +#ifdef _WIN32 +# include +# include +#endif + +#include +#include +#include +#include + +/* Allow alternate API prefix from CFLAGS or calling app */ +#ifndef LIBSSH2_API +# ifdef LIBSSH2_WIN32 +# ifdef LIBSSH2_LIBRARY +# define LIBSSH2_API __declspec(dllexport) +# else +# define LIBSSH2_API __declspec(dllimport) +# endif /* LIBSSH2_LIBRARY */ +# else /* !LIBSSH2_WIN32 */ +# define LIBSSH2_API +# endif /* LIBSSH2_WIN32 */ +#endif /* LIBSSH2_API */ + +#if defined(LIBSSH2_DARWIN) +# include +#endif + +#if (defined(NETWARE) && !defined(__NOVELL_LIBC__)) +# include +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +#endif + +#ifdef _MSC_VER +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 libssh2_uint64_t; +typedef __int64 libssh2_int64_t; +#ifndef ssize_t +typedef SSIZE_T ssize_t; +#endif +#else +typedef unsigned long long libssh2_uint64_t; +typedef long long libssh2_int64_t; +#endif + +#ifdef WIN32 +typedef SOCKET libssh2_socket_t; +#define LIBSSH2_INVALID_SOCKET INVALID_SOCKET +#else /* !WIN32 */ +typedef int libssh2_socket_t; +#define LIBSSH2_INVALID_SOCKET -1 +#endif /* WIN32 */ + +/* Part of every banner, user specified or not */ +#define LIBSSH2_SSH_BANNER "SSH-2.0-libssh2_" LIBSSH2_VERSION + +/* We *could* add a comment here if we so chose */ +#define LIBSSH2_SSH_DEFAULT_BANNER LIBSSH2_SSH_BANNER +#define LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF LIBSSH2_SSH_DEFAULT_BANNER "\r\n" + +/* Default generate and safe prime sizes for diffie-hellman-group-exchange-sha1 */ +#define LIBSSH2_DH_GEX_MINGROUP 1024 +#define LIBSSH2_DH_GEX_OPTGROUP 1536 +#define LIBSSH2_DH_GEX_MAXGROUP 2048 + +/* Defaults for pty requests */ +#define LIBSSH2_TERM_WIDTH 80 +#define LIBSSH2_TERM_HEIGHT 24 +#define LIBSSH2_TERM_WIDTH_PX 0 +#define LIBSSH2_TERM_HEIGHT_PX 0 + +/* 1/4 second */ +#define LIBSSH2_SOCKET_POLL_UDELAY 250000 +/* 0.25 * 120 == 30 seconds */ +#define LIBSSH2_SOCKET_POLL_MAXLOOPS 120 + +/* Maximum size to allow a payload to compress to, plays it safe by falling + short of spec limits */ +#define LIBSSH2_PACKET_MAXCOMP 32000 + +/* Maximum size to allow a payload to deccompress to, plays it safe by + allowing more than spec requires */ +#define LIBSSH2_PACKET_MAXDECOMP 40000 + +/* Maximum size for an inbound compressed payload, plays it safe by + overshooting spec limits */ +#define LIBSSH2_PACKET_MAXPAYLOAD 40000 + +/* Malloc callbacks */ +#define LIBSSH2_ALLOC_FUNC(name) void *name(size_t count, void **abstract) +#define LIBSSH2_REALLOC_FUNC(name) void *name(void *ptr, size_t count, \ + void **abstract) +#define LIBSSH2_FREE_FUNC(name) void name(void *ptr, void **abstract) + +typedef struct _LIBSSH2_USERAUTH_KBDINT_PROMPT +{ + char* text; + unsigned int length; + unsigned char echo; +} LIBSSH2_USERAUTH_KBDINT_PROMPT; + +typedef struct _LIBSSH2_USERAUTH_KBDINT_RESPONSE +{ + char* text; + unsigned int length; +} LIBSSH2_USERAUTH_KBDINT_RESPONSE; + +/* 'publickey' authentication callback */ +#define LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC(name) \ + int name(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, \ + const unsigned char *data, size_t data_len, void **abstract) + +/* 'keyboard-interactive' authentication callback */ +#define LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC(name_) \ + void name_(const char* name, int name_len, const char* instruction, \ + int instruction_len, int num_prompts, \ + const LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts, \ + LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses, void **abstract) + +/* Callbacks for special SSH packets */ +#define LIBSSH2_IGNORE_FUNC(name) \ + void name(LIBSSH2_SESSION *session, const char *message, int message_len, \ + void **abstract) + +#define LIBSSH2_DEBUG_FUNC(name) \ + void name(LIBSSH2_SESSION *session, int always_display, const char *message, \ + int message_len, const char *language, int language_len, \ + void **abstract) + +#define LIBSSH2_DISCONNECT_FUNC(name) \ + void name(LIBSSH2_SESSION *session, int reason, const char *message, \ + int message_len, const char *language, int language_len, \ + void **abstract) + +#define LIBSSH2_PASSWD_CHANGEREQ_FUNC(name) \ + void name(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, \ + void **abstract) + +#define LIBSSH2_MACERROR_FUNC(name) \ + int name(LIBSSH2_SESSION *session, const char *packet, int packet_len, \ + void **abstract) + +#define LIBSSH2_X11_OPEN_FUNC(name) \ + void name(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, \ + const char *shost, int sport, void **abstract) + +#define LIBSSH2_CHANNEL_CLOSE_FUNC(name) \ + void name(LIBSSH2_SESSION *session, void **session_abstract, \ + LIBSSH2_CHANNEL *channel, void **channel_abstract) + +/* I/O callbacks */ +#define LIBSSH2_RECV_FUNC(name) ssize_t name(libssh2_socket_t socket, \ + void *buffer, size_t length, \ + int flags, void **abstract) +#define LIBSSH2_SEND_FUNC(name) ssize_t name(libssh2_socket_t socket, \ + const void *buffer, size_t length,\ + int flags, void **abstract) + +/* libssh2_session_callback_set() constants */ +#define LIBSSH2_CALLBACK_IGNORE 0 +#define LIBSSH2_CALLBACK_DEBUG 1 +#define LIBSSH2_CALLBACK_DISCONNECT 2 +#define LIBSSH2_CALLBACK_MACERROR 3 +#define LIBSSH2_CALLBACK_X11 4 +#define LIBSSH2_CALLBACK_SEND 5 +#define LIBSSH2_CALLBACK_RECV 6 + +/* libssh2_session_method_pref() constants */ +#define LIBSSH2_METHOD_KEX 0 +#define LIBSSH2_METHOD_HOSTKEY 1 +#define LIBSSH2_METHOD_CRYPT_CS 2 +#define LIBSSH2_METHOD_CRYPT_SC 3 +#define LIBSSH2_METHOD_MAC_CS 4 +#define LIBSSH2_METHOD_MAC_SC 5 +#define LIBSSH2_METHOD_COMP_CS 6 +#define LIBSSH2_METHOD_COMP_SC 7 +#define LIBSSH2_METHOD_LANG_CS 8 +#define LIBSSH2_METHOD_LANG_SC 9 + +/* flags */ +#define LIBSSH2_FLAG_SIGPIPE 1 +#define LIBSSH2_FLAG_COMPRESS 2 + +typedef struct _LIBSSH2_SESSION LIBSSH2_SESSION; +typedef struct _LIBSSH2_CHANNEL LIBSSH2_CHANNEL; +typedef struct _LIBSSH2_LISTENER LIBSSH2_LISTENER; +typedef struct _LIBSSH2_KNOWNHOSTS LIBSSH2_KNOWNHOSTS; +typedef struct _LIBSSH2_AGENT LIBSSH2_AGENT; + +typedef struct _LIBSSH2_POLLFD { + unsigned char type; /* LIBSSH2_POLLFD_* below */ + + union { + int socket; /* File descriptors -- examined with system select() call */ + LIBSSH2_CHANNEL *channel; /* Examined by checking internal state */ + LIBSSH2_LISTENER *listener; /* Read polls only -- are inbound + connections waiting to be accepted? */ + } fd; + + unsigned long events; /* Requested Events */ + unsigned long revents; /* Returned Events */ +} LIBSSH2_POLLFD; + +/* Poll FD Descriptor Types */ +#define LIBSSH2_POLLFD_SOCKET 1 +#define LIBSSH2_POLLFD_CHANNEL 2 +#define LIBSSH2_POLLFD_LISTENER 3 + +/* Note: Win32 Doesn't actually have a poll() implementation, so some of these + values are faked with select() data */ +/* Poll FD events/revents -- Match sys/poll.h where possible */ +#define LIBSSH2_POLLFD_POLLIN 0x0001 /* Data available to be read or + connection available -- + All */ +#define LIBSSH2_POLLFD_POLLPRI 0x0002 /* Priority data available to + be read -- Socket only */ +#define LIBSSH2_POLLFD_POLLEXT 0x0002 /* Extended data available to + be read -- Channel only */ +#define LIBSSH2_POLLFD_POLLOUT 0x0004 /* Can may be written -- + Socket/Channel */ +/* revents only */ +#define LIBSSH2_POLLFD_POLLERR 0x0008 /* Error Condition -- Socket */ +#define LIBSSH2_POLLFD_POLLHUP 0x0010 /* HangUp/EOF -- Socket */ +#define LIBSSH2_POLLFD_SESSION_CLOSED 0x0010 /* Session Disconnect */ +#define LIBSSH2_POLLFD_POLLNVAL 0x0020 /* Invalid request -- Socket + Only */ +#define LIBSSH2_POLLFD_POLLEX 0x0040 /* Exception Condition -- + Socket/Win32 */ +#define LIBSSH2_POLLFD_CHANNEL_CLOSED 0x0080 /* Channel Disconnect */ +#define LIBSSH2_POLLFD_LISTENER_CLOSED 0x0080 /* Listener Disconnect */ + +#define HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION +/* Block Direction Types */ +#define LIBSSH2_SESSION_BLOCK_INBOUND 0x0001 +#define LIBSSH2_SESSION_BLOCK_OUTBOUND 0x0002 + +/* Hash Types */ +#define LIBSSH2_HOSTKEY_HASH_MD5 1 +#define LIBSSH2_HOSTKEY_HASH_SHA1 2 + +/* Hostkey Types */ +#define LIBSSH2_HOSTKEY_TYPE_UNKNOWN 0 +#define LIBSSH2_HOSTKEY_TYPE_RSA 1 +#define LIBSSH2_HOSTKEY_TYPE_DSS 2 + +/* Disconnect Codes (defined by SSH protocol) */ +#define SSH_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 +#define SSH_DISCONNECT_PROTOCOL_ERROR 2 +#define SSH_DISCONNECT_KEY_EXCHANGE_FAILED 3 +#define SSH_DISCONNECT_RESERVED 4 +#define SSH_DISCONNECT_MAC_ERROR 5 +#define SSH_DISCONNECT_COMPRESSION_ERROR 6 +#define SSH_DISCONNECT_SERVICE_NOT_AVAILABLE 7 +#define SSH_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED 8 +#define SSH_DISCONNECT_HOST_KEY_NOT_VERIFIABLE 9 +#define SSH_DISCONNECT_CONNECTION_LOST 10 +#define SSH_DISCONNECT_BY_APPLICATION 11 +#define SSH_DISCONNECT_TOO_MANY_CONNECTIONS 12 +#define SSH_DISCONNECT_AUTH_CANCELLED_BY_USER 13 +#define SSH_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE 14 +#define SSH_DISCONNECT_ILLEGAL_USER_NAME 15 + +/* Error Codes (defined by libssh2) */ +#define LIBSSH2_ERROR_NONE 0 + +/* The library once used -1 as a generic error return value on numerous places + through the code, which subsequently was converted to + LIBSSH2_ERROR_SOCKET_NONE uses over time. As this is a generic error code, + the goal is to never ever return this code but instead make sure that a + more accurate and descriptive error code is used. */ +#define LIBSSH2_ERROR_SOCKET_NONE -1 + +#define LIBSSH2_ERROR_BANNER_RECV -2 +#define LIBSSH2_ERROR_BANNER_SEND -3 +#define LIBSSH2_ERROR_INVALID_MAC -4 +#define LIBSSH2_ERROR_KEX_FAILURE -5 +#define LIBSSH2_ERROR_ALLOC -6 +#define LIBSSH2_ERROR_SOCKET_SEND -7 +#define LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE -8 +#define LIBSSH2_ERROR_TIMEOUT -9 +#define LIBSSH2_ERROR_HOSTKEY_INIT -10 +#define LIBSSH2_ERROR_HOSTKEY_SIGN -11 +#define LIBSSH2_ERROR_DECRYPT -12 +#define LIBSSH2_ERROR_SOCKET_DISCONNECT -13 +#define LIBSSH2_ERROR_PROTO -14 +#define LIBSSH2_ERROR_PASSWORD_EXPIRED -15 +#define LIBSSH2_ERROR_FILE -16 +#define LIBSSH2_ERROR_METHOD_NONE -17 +#define LIBSSH2_ERROR_AUTHENTICATION_FAILED -18 +#define LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED LIBSSH2_ERROR_AUTHENTICATION_FAILED +#define LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED -19 +#define LIBSSH2_ERROR_CHANNEL_OUTOFORDER -20 +#define LIBSSH2_ERROR_CHANNEL_FAILURE -21 +#define LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED -22 +#define LIBSSH2_ERROR_CHANNEL_UNKNOWN -23 +#define LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED -24 +#define LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED -25 +#define LIBSSH2_ERROR_CHANNEL_CLOSED -26 +#define LIBSSH2_ERROR_CHANNEL_EOF_SENT -27 +#define LIBSSH2_ERROR_SCP_PROTOCOL -28 +#define LIBSSH2_ERROR_ZLIB -29 +#define LIBSSH2_ERROR_SOCKET_TIMEOUT -30 +#define LIBSSH2_ERROR_SFTP_PROTOCOL -31 +#define LIBSSH2_ERROR_REQUEST_DENIED -32 +#define LIBSSH2_ERROR_METHOD_NOT_SUPPORTED -33 +#define LIBSSH2_ERROR_INVAL -34 +#define LIBSSH2_ERROR_INVALID_POLL_TYPE -35 +#define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36 +#define LIBSSH2_ERROR_EAGAIN -37 +#define LIBSSH2_ERROR_BUFFER_TOO_SMALL -38 +#define LIBSSH2_ERROR_BAD_USE -39 +#define LIBSSH2_ERROR_COMPRESS -40 +#define LIBSSH2_ERROR_OUT_OF_BOUNDARY -41 +#define LIBSSH2_ERROR_AGENT_PROTOCOL -42 +#define LIBSSH2_ERROR_SOCKET_RECV -43 +#define LIBSSH2_ERROR_ENCRYPT -44 +#define LIBSSH2_ERROR_BAD_SOCKET -45 + +/* this is a define to provide the old (<= 1.2.7) name */ +#define LIBSSH2_ERROR_BANNER_NONE LIBSSH2_ERROR_BANNER_RECV + +/* Global API */ +#define LIBSSH2_INIT_NO_CRYPTO 0x0001 + +/* + * libssh2_init() + * + * Initialize the libssh2 functions. This typically initialize the + * crypto library. It uses a global state, and is not thread safe -- + * you must make sure this function is not called concurrently. + * + * Flags can be: + * 0: Normal initialize + * LIBSSH2_INIT_NO_CRYPTO: Do not initialize the crypto library (ie. + * OPENSSL_add_cipher_algoritms() for OpenSSL + * + * Returns 0 if succeeded, or a negative value for error. + */ +LIBSSH2_API int libssh2_init(int flags); + +/* + * libssh2_exit() + * + * Exit the libssh2 functions and free's all memory used internal. + */ +LIBSSH2_API void libssh2_exit(void); + +/* + * libssh2_free() + * + * Deallocate memory allocated by earlier call to libssh2 functions. + */ +LIBSSH2_API void libssh2_free(LIBSSH2_SESSION *session, void *ptr); + +/* + * libssh2_session_supported_algs() + * + * Fills algs with a list of supported acryptographic algorithms. Returns a + * non-negative number (number of supported algorithms) on success or a + * negative number (an eror code) on failure. + * + * NOTE: on success, algs must be deallocated (by calling libssh2_free) when + * not needed anymore + */ +LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, + int method_type, + const char*** algs); + +/* Session API */ +LIBSSH2_API LIBSSH2_SESSION * +libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), + LIBSSH2_FREE_FUNC((*my_free)), + LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract); +#define libssh2_session_init() libssh2_session_init_ex(NULL, NULL, NULL, NULL) + +LIBSSH2_API void **libssh2_session_abstract(LIBSSH2_SESSION *session); + +LIBSSH2_API void *libssh2_session_callback_set(LIBSSH2_SESSION *session, + int cbtype, void *callback); +LIBSSH2_API int libssh2_session_banner_set(LIBSSH2_SESSION *session, + const char *banner); +LIBSSH2_API int libssh2_banner_set(LIBSSH2_SESSION *session, + const char *banner); + +LIBSSH2_API int libssh2_session_startup(LIBSSH2_SESSION *session, int sock); +LIBSSH2_API int libssh2_session_handshake(LIBSSH2_SESSION *session, + libssh2_socket_t sock); +LIBSSH2_API int libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, + int reason, + const char *description, + const char *lang); +#define libssh2_session_disconnect(session, description) \ + libssh2_session_disconnect_ex((session), SSH_DISCONNECT_BY_APPLICATION, \ + (description), "") + +LIBSSH2_API int libssh2_session_free(LIBSSH2_SESSION *session); + +LIBSSH2_API const char *libssh2_hostkey_hash(LIBSSH2_SESSION *session, + int hash_type); + +LIBSSH2_API const char *libssh2_session_hostkey(LIBSSH2_SESSION *session, + size_t *len, int *type); + +LIBSSH2_API int libssh2_session_method_pref(LIBSSH2_SESSION *session, + int method_type, + const char *prefs); +LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, + int method_type); +LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, + char **errmsg, + int *errmsg_len, int want_buf); +LIBSSH2_API int libssh2_session_last_errno(LIBSSH2_SESSION *session); +LIBSSH2_API int libssh2_session_block_directions(LIBSSH2_SESSION *session); + +LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, + int value); +LIBSSH2_API const char *libssh2_session_banner_get(LIBSSH2_SESSION *session); + +/* Userauth API */ +LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, + const char *username, + unsigned int username_len); +LIBSSH2_API int libssh2_userauth_authenticated(LIBSSH2_SESSION *session); + +LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, + const char *username, + unsigned int username_len, + const char *password, + unsigned int password_len, + LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb))); + +#define libssh2_userauth_password(session, username, password) \ + libssh2_userauth_password_ex((session), (username), strlen(username), \ + (password), strlen(password), NULL) + +LIBSSH2_API int +libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, + const char *username, + unsigned int username_len, + const char *publickey, + const char *privatekey, + const char *passphrase); + +#define libssh2_userauth_publickey_fromfile(session, username, publickey, \ + privatekey, passphrase) \ + libssh2_userauth_publickey_fromfile_ex((session), (username), \ + strlen(username), (publickey), \ + (privatekey), (passphrase)) + +LIBSSH2_API int +libssh2_userauth_publickey(LIBSSH2_SESSION *session, + const char *username, + const unsigned char *pubkeydata, + size_t pubkeydata_len, + LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), + void **abstract); + +LIBSSH2_API int +libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, + const char *username, + unsigned int username_len, + const char *publickey, + const char *privatekey, + const char *passphrase, + const char *hostname, + unsigned int hostname_len, + const char *local_username, + unsigned int local_username_len); + +#define libssh2_userauth_hostbased_fromfile(session, username, publickey, \ + privatekey, passphrase, hostname) \ + libssh2_userauth_hostbased_fromfile_ex((session), (username), \ + strlen(username), (publickey), \ + (privatekey), (passphrase), \ + (hostname), strlen(hostname), \ + (username), strlen(username)) + +/* + * response_callback is provided with filled by library prompts array, + * but client must allocate and fill individual responses. Responses + * array is already allocated. Responses data will be freed by libssh2 + * after callback return, but before subsequent callback invokation. + */ +LIBSSH2_API int +libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION* session, + const char *username, + unsigned int username_len, + LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback))); + +#define libssh2_userauth_keyboard_interactive(session, username, \ + response_callback) \ + libssh2_userauth_keyboard_interactive_ex((session), (username), \ + strlen(username), (response_callback)) + +LIBSSH2_API int libssh2_poll(LIBSSH2_POLLFD *fds, unsigned int nfds, + long timeout); + +/* Channel API */ +#define LIBSSH2_CHANNEL_WINDOW_DEFAULT (256*1024) +#define LIBSSH2_CHANNEL_PACKET_DEFAULT 32768 +#define LIBSSH2_CHANNEL_MINADJUST 1024 + +/* Extended Data Handling */ +#define LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL 0 +#define LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE 1 +#define LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE 2 + +#define SSH_EXTENDED_DATA_STDERR 1 + +/* Returned by any function that would block during a read/write opperation */ +#define LIBSSH2CHANNEL_EAGAIN LIBSSH2_ERROR_EAGAIN + +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *channel_type, + unsigned int channel_type_len, + unsigned int window_size, unsigned int packet_size, + const char *message, unsigned int message_len); + +#define libssh2_channel_open_session(session) \ + libssh2_channel_open_ex((session), "session", sizeof("session") - 1, \ + LIBSSH2_CHANNEL_WINDOW_DEFAULT, \ + LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0) + +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, + int port, const char *shost, int sport); +#define libssh2_channel_direct_tcpip(session, host, port) \ + libssh2_channel_direct_tcpip_ex((session), (host), (port), "127.0.0.1", 22) + +LIBSSH2_API LIBSSH2_LISTENER * +libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host, + int port, int *bound_port, int queue_maxsize); +#define libssh2_channel_forward_listen(session, port) \ + libssh2_channel_forward_listen_ex((session), NULL, (port), NULL, 16) + +LIBSSH2_API int libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener); + +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener); + +LIBSSH2_API int libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, + const char *varname, + unsigned int varname_len, + const char *value, + unsigned int value_len); + +#define libssh2_channel_setenv(channel, varname, value) \ + libssh2_channel_setenv_ex((channel), (varname), strlen(varname), (value), \ + strlen(value)) + +LIBSSH2_API int libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, + const char *term, + unsigned int term_len, + const char *modes, + unsigned int modes_len, + int width, int height, + int width_px, int height_px); +#define libssh2_channel_request_pty(channel, term) \ + libssh2_channel_request_pty_ex((channel), (term), strlen(term), NULL, 0, \ + LIBSSH2_TERM_WIDTH, LIBSSH2_TERM_HEIGHT, \ + LIBSSH2_TERM_WIDTH_PX, LIBSSH2_TERM_HEIGHT_PX) + +LIBSSH2_API int libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel, + int width, int height, + int width_px, + int height_px); +#define libssh2_channel_request_pty_size(channel, width, height) \ + libssh2_channel_request_pty_size_ex( (channel), (width), (height), 0, 0) + +LIBSSH2_API int libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, + int single_connection, + const char *auth_proto, + const char *auth_cookie, + int screen_number); +#define libssh2_channel_x11_req(channel, screen_number) \ + libssh2_channel_x11_req_ex((channel), 0, NULL, NULL, (screen_number)) + +LIBSSH2_API int libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, + const char *request, + unsigned int request_len, + const char *message, + unsigned int message_len); +#define libssh2_channel_shell(channel) \ + libssh2_channel_process_startup((channel), "shell", sizeof("shell") - 1, \ + NULL, 0) +#define libssh2_channel_exec(channel, command) \ + libssh2_channel_process_startup((channel), "exec", sizeof("exec") - 1, \ + (command), strlen(command)) +#define libssh2_channel_subsystem(channel, subsystem) \ + libssh2_channel_process_startup((channel), "subsystem", \ + sizeof("subsystem") - 1, (subsystem), \ + strlen(subsystem)) + +LIBSSH2_API ssize_t libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, + int stream_id, char *buf, + size_t buflen); +#define libssh2_channel_read(channel, buf, buflen) \ + libssh2_channel_read_ex((channel), 0, (buf), (buflen)) +#define libssh2_channel_read_stderr(channel, buf, buflen) \ + libssh2_channel_read_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen)) + +LIBSSH2_API int libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, + int extended); + +LIBSSH2_API unsigned long +libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, + unsigned long *read_avail, + unsigned long *window_size_initial); +#define libssh2_channel_window_read(channel) \ + libssh2_channel_window_read_ex((channel), NULL, NULL) + +/* libssh2_channel_receive_window_adjust is DEPRECATED, do not use! */ +LIBSSH2_API unsigned long +libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, + unsigned long adjustment, + unsigned char force); + +LIBSSH2_API int +libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL *channel, + unsigned long adjustment, + unsigned char force, + unsigned int *storewindow); + +LIBSSH2_API ssize_t libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, + int stream_id, const char *buf, + size_t buflen); + +#define libssh2_channel_write(channel, buf, buflen) \ + libssh2_channel_write_ex((channel), 0, (buf), (buflen)) +#define libssh2_channel_write_stderr(channel, buf, buflen) \ + libssh2_channel_write_ex((channel), SSH_EXTENDED_DATA_STDERR, (buf), (buflen)) + +LIBSSH2_API unsigned long +libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, + unsigned long *window_size_initial); +#define libssh2_channel_window_write(channel) \ + libssh2_channel_window_write_ex((channel), NULL) + +LIBSSH2_API void libssh2_session_set_blocking(LIBSSH2_SESSION* session, + int blocking); +LIBSSH2_API int libssh2_session_get_blocking(LIBSSH2_SESSION* session); + +LIBSSH2_API void libssh2_channel_set_blocking(LIBSSH2_CHANNEL *channel, + int blocking); + +LIBSSH2_API void libssh2_session_set_timeout(LIBSSH2_SESSION* session, + long timeout); +LIBSSH2_API long libssh2_session_get_timeout(LIBSSH2_SESSION* session); + +/* libssh2_channel_handle_extended_data is DEPRECATED, do not use! */ +LIBSSH2_API void libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, + int ignore_mode); +LIBSSH2_API int libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, + int ignore_mode); + +/* libssh2_channel_ignore_extended_data() is defined below for BC with version + * 0.1 + * + * Future uses should use libssh2_channel_handle_extended_data() directly if + * LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE is passed, extended data will be read + * (FIFO) from the standard data channel + */ +/* DEPRECATED */ +#define libssh2_channel_ignore_extended_data(channel, ignore) \ + libssh2_channel_handle_extended_data((channel), \ + (ignore) ? \ + LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE : \ + LIBSSH2_CHANNEL_EXTENDED_DATA_NORMAL ) + +#define LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA -1 +#define LIBSSH2_CHANNEL_FLUSH_ALL -2 +LIBSSH2_API int libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, + int streamid); +#define libssh2_channel_flush(channel) libssh2_channel_flush_ex((channel), 0) +#define libssh2_channel_flush_stderr(channel) \ + libssh2_channel_flush_ex((channel), SSH_EXTENDED_DATA_STDERR) + +LIBSSH2_API int libssh2_channel_get_exit_status(LIBSSH2_CHANNEL* channel); +LIBSSH2_API int libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL* channel, + char **exitsignal, + size_t *exitsignal_len, + char **errmsg, + size_t *errmsg_len, + char **langtag, + size_t *langtag_len); +LIBSSH2_API int libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel); +LIBSSH2_API int libssh2_channel_eof(LIBSSH2_CHANNEL *channel); +LIBSSH2_API int libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel); +LIBSSH2_API int libssh2_channel_close(LIBSSH2_CHANNEL *channel); +LIBSSH2_API int libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel); +LIBSSH2_API int libssh2_channel_free(LIBSSH2_CHANNEL *channel); + +LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_recv(LIBSSH2_SESSION *session, + const char *path, + struct stat *sb); +LIBSSH2_API LIBSSH2_CHANNEL *libssh2_scp_send_ex(LIBSSH2_SESSION *session, + const char *path, int mode, + size_t size, long mtime, + long atime); +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_scp_send64(LIBSSH2_SESSION *session, const char *path, int mode, + libssh2_int64_t size, time_t mtime, time_t atime); + +#define libssh2_scp_send(session, path, mode, size) \ + libssh2_scp_send_ex((session), (path), (mode), (size), 0, 0) + +LIBSSH2_API int libssh2_base64_decode(LIBSSH2_SESSION *session, char **dest, + unsigned int *dest_len, + const char *src, unsigned int src_len); + +LIBSSH2_API +const char *libssh2_version(int req_version_num); + +#define HAVE_LIBSSH2_KNOWNHOST_API 0x010101 /* since 1.1.1 */ +#define HAVE_LIBSSH2_VERSION_API 0x010100 /* libssh2_version since 1.1 */ + +struct libssh2_knownhost { + unsigned int magic; /* magic stored by the library */ + void *node; /* handle to the internal representation of this host */ + char *name; /* this is NULL if no plain text host name exists */ + char *key; /* key in base64/printable format */ + int typemask; +}; + +/* + * libssh2_knownhost_init + * + * Init a collection of known hosts. Returns the pointer to a collection. + * + */ +LIBSSH2_API LIBSSH2_KNOWNHOSTS * +libssh2_knownhost_init(LIBSSH2_SESSION *session); + +/* + * libssh2_knownhost_add + * + * Add a host and its associated key to the collection of known hosts. + * + * The 'type' argument specifies on what format the given host and keys are: + * + * plain - ascii "hostname.domain.tld" + * sha1 - SHA1( ) base64-encoded! + * custom - another hash + * + * If 'sha1' is selected as type, the salt must be provided to the salt + * argument. This too base64 encoded. + * + * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If + * a custom type is used, salt is ignored and you must provide the host + * pre-hashed when checking for it in the libssh2_knownhost_check() function. + * + * The keylen parameter may be omitted (zero) if the key is provided as a + * NULL-terminated base64-encoded string. + */ + +/* host format (2 bits) */ +#define LIBSSH2_KNOWNHOST_TYPE_MASK 0xffff +#define LIBSSH2_KNOWNHOST_TYPE_PLAIN 1 +#define LIBSSH2_KNOWNHOST_TYPE_SHA1 2 /* always base64 encoded */ +#define LIBSSH2_KNOWNHOST_TYPE_CUSTOM 3 + +/* key format (2 bits) */ +#define LIBSSH2_KNOWNHOST_KEYENC_MASK (3<<16) +#define LIBSSH2_KNOWNHOST_KEYENC_RAW (1<<16) +#define LIBSSH2_KNOWNHOST_KEYENC_BASE64 (2<<16) + +/* type of key (2 bits) */ +#define LIBSSH2_KNOWNHOST_KEY_MASK (3<<18) +#define LIBSSH2_KNOWNHOST_KEY_SHIFT 18 +#define LIBSSH2_KNOWNHOST_KEY_RSA1 (1<<18) +#define LIBSSH2_KNOWNHOST_KEY_SSHRSA (2<<18) +#define LIBSSH2_KNOWNHOST_KEY_SSHDSS (3<<18) + +LIBSSH2_API int +libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, + const char *host, + const char *salt, + const char *key, size_t keylen, int typemask, + struct libssh2_knownhost **store); + +/* + * libssh2_knownhost_addc + * + * Add a host and its associated key to the collection of known hosts. + * + * Takes a comment argument that may be NULL. A NULL comment indicates + * there is no comment and the entry will end directly after the key + * when written out to a file. An empty string "" comment will indicate an + * empty comment which will cause a single space to be written after the key. + * + * The 'type' argument specifies on what format the given host and keys are: + * + * plain - ascii "hostname.domain.tld" + * sha1 - SHA1( ) base64-encoded! + * custom - another hash + * + * If 'sha1' is selected as type, the salt must be provided to the salt + * argument. This too base64 encoded. + * + * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If + * a custom type is used, salt is ignored and you must provide the host + * pre-hashed when checking for it in the libssh2_knownhost_check() function. + * + * The keylen parameter may be omitted (zero) if the key is provided as a + * NULL-terminated base64-encoded string. + */ + +LIBSSH2_API int +libssh2_knownhost_addc(LIBSSH2_KNOWNHOSTS *hosts, + const char *host, + const char *salt, + const char *key, size_t keylen, + const char *comment, size_t commentlen, int typemask, + struct libssh2_knownhost **store); + +/* + * libssh2_knownhost_check + * + * Check a host and its associated key against the collection of known hosts. + * + * The type is the type/format of the given host name. + * + * plain - ascii "hostname.domain.tld" + * custom - prehashed base64 encoded. Note that this cannot use any salts. + * + * + * 'knownhost' may be set to NULL if you don't care about that info. + * + * Returns: + * + * LIBSSH2_KNOWNHOST_CHECK_* values, see below + * + */ + +#define LIBSSH2_KNOWNHOST_CHECK_MATCH 0 +#define LIBSSH2_KNOWNHOST_CHECK_MISMATCH 1 +#define LIBSSH2_KNOWNHOST_CHECK_NOTFOUND 2 +#define LIBSSH2_KNOWNHOST_CHECK_FAILURE 3 + +LIBSSH2_API int +libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts, + const char *host, const char *key, size_t keylen, + int typemask, + struct libssh2_knownhost **knownhost); + +/* this function is identital to the above one, but also takes a port + argument that allows libssh2 to do a better check */ +LIBSSH2_API int +libssh2_knownhost_checkp(LIBSSH2_KNOWNHOSTS *hosts, + const char *host, int port, + const char *key, size_t keylen, + int typemask, + struct libssh2_knownhost **knownhost); + +/* + * libssh2_knownhost_del + * + * Remove a host from the collection of known hosts. The 'entry' struct is + * retrieved by a call to libssh2_knownhost_check(). + * + */ +LIBSSH2_API int +libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts, + struct libssh2_knownhost *entry); + +/* + * libssh2_knownhost_free + * + * Free an entire collection of known hosts. + * + */ +LIBSSH2_API void +libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts); + +/* + * libssh2_knownhost_readline() + * + * Pass in a line of a file of 'type'. It makes libssh2 read this line. + * + * LIBSSH2_KNOWNHOST_FILE_OPENSSH is the only supported type. + * + */ +LIBSSH2_API int +libssh2_knownhost_readline(LIBSSH2_KNOWNHOSTS *hosts, + const char *line, size_t len, int type); + +/* + * libssh2_knownhost_readfile + * + * Add hosts+key pairs from a given file. + * + * Returns a negative value for error or number of successfully added hosts. + * + * This implementation currently only knows one 'type' (openssh), all others + * are reserved for future use. + */ + +#define LIBSSH2_KNOWNHOST_FILE_OPENSSH 1 + +LIBSSH2_API int +libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts, + const char *filename, int type); + +/* + * libssh2_knownhost_writeline() + * + * Ask libssh2 to convert a known host to an output line for storage. + * + * Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given + * output buffer is too small to hold the desired output. + * + * This implementation currently only knows one 'type' (openssh), all others + * are reserved for future use. + * + */ +LIBSSH2_API int +libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, + struct libssh2_knownhost *known, + char *buffer, size_t buflen, + size_t *outlen, /* the amount of written data */ + int type); + +/* + * libssh2_knownhost_writefile + * + * Write hosts+key pairs to a given file. + * + * This implementation currently only knows one 'type' (openssh), all others + * are reserved for future use. + */ + +LIBSSH2_API int +libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts, + const char *filename, int type); + +/* + * libssh2_knownhost_get() + * + * Traverse the internal list of known hosts. Pass NULL to 'prev' to get + * the first one. Or pass a poiner to the previously returned one to get the + * next. + * + * Returns: + * 0 if a fine host was stored in 'store' + * 1 if end of hosts + * [negative] on errors + */ +LIBSSH2_API int +libssh2_knownhost_get(LIBSSH2_KNOWNHOSTS *hosts, + struct libssh2_knownhost **store, + struct libssh2_knownhost *prev); + +#define HAVE_LIBSSH2_AGENT_API 0x010202 /* since 1.2.2 */ + +struct libssh2_agent_publickey { + unsigned int magic; /* magic stored by the library */ + void *node; /* handle to the internal representation of key */ + unsigned char *blob; /* public key blob */ + size_t blob_len; /* length of the public key blob */ + char *comment; /* comment in printable format */ +}; + +/* + * libssh2_agent_init + * + * Init an ssh-agent handle. Returns the pointer to the handle. + * + */ +LIBSSH2_API LIBSSH2_AGENT * +libssh2_agent_init(LIBSSH2_SESSION *session); + +/* + * libssh2_agent_connect() + * + * Connect to an ssh-agent. + * + * Returns 0 if succeeded, or a negative value for error. + */ +LIBSSH2_API int +libssh2_agent_connect(LIBSSH2_AGENT *agent); + +/* + * libssh2_agent_list_identities() + * + * Request an ssh-agent to list identities. + * + * Returns 0 if succeeded, or a negative value for error. + */ +LIBSSH2_API int +libssh2_agent_list_identities(LIBSSH2_AGENT *agent); + +/* + * libssh2_agent_get_identity() + * + * Traverse the internal list of public keys. Pass NULL to 'prev' to get + * the first one. Or pass a poiner to the previously returned one to get the + * next. + * + * Returns: + * 0 if a fine public key was stored in 'store' + * 1 if end of public keys + * [negative] on errors + */ +LIBSSH2_API int +libssh2_agent_get_identity(LIBSSH2_AGENT *agent, + struct libssh2_agent_publickey **store, + struct libssh2_agent_publickey *prev); + +/* + * libssh2_agent_userauth() + * + * Do publickey user authentication with the help of ssh-agent. + * + * Returns 0 if succeeded, or a negative value for error. + */ +LIBSSH2_API int +libssh2_agent_userauth(LIBSSH2_AGENT *agent, + const char *username, + struct libssh2_agent_publickey *identity); + +/* + * libssh2_agent_disconnect() + * + * Close a connection to an ssh-agent. + * + * Returns 0 if succeeded, or a negative value for error. + */ +LIBSSH2_API int +libssh2_agent_disconnect(LIBSSH2_AGENT *agent); + +/* + * libssh2_agent_free() + * + * Free an ssh-agent handle. This function also frees the internal + * collection of public keys. + */ +LIBSSH2_API void +libssh2_agent_free(LIBSSH2_AGENT *agent); + + +/* + * libssh2_keepalive_config() + * + * Set how often keepalive messages should be sent. WANT_REPLY + * indicates whether the keepalive messages should request a response + * from the server. INTERVAL is number of seconds that can pass + * without any I/O, use 0 (the default) to disable keepalives. To + * avoid some busy-loop corner-cases, if you specify an interval of 1 + * it will be treated as 2. + * + * Note that non-blocking applications are responsible for sending the + * keepalive messages using libssh2_keepalive_send(). + */ +LIBSSH2_API void libssh2_keepalive_config (LIBSSH2_SESSION *session, + int want_reply, + unsigned interval); + +/* + * libssh2_keepalive_send() + * + * Send a keepalive message if needed. SECONDS_TO_NEXT indicates how + * many seconds you can sleep after this call before you need to call + * it again. Returns 0 on success, or LIBSSH2_ERROR_SOCKET_SEND on + * I/O errors. + */ +LIBSSH2_API int libssh2_keepalive_send (LIBSSH2_SESSION *session, + int *seconds_to_next); + +/* NOTE NOTE NOTE + libssh2_trace() has no function in builds that aren't built with debug + enabled + */ +LIBSSH2_API int libssh2_trace(LIBSSH2_SESSION *session, int bitmask); +#define LIBSSH2_TRACE_TRANS (1<<1) +#define LIBSSH2_TRACE_KEX (1<<2) +#define LIBSSH2_TRACE_AUTH (1<<3) +#define LIBSSH2_TRACE_CONN (1<<4) +#define LIBSSH2_TRACE_SCP (1<<5) +#define LIBSSH2_TRACE_SFTP (1<<6) +#define LIBSSH2_TRACE_ERROR (1<<7) +#define LIBSSH2_TRACE_PUBLICKEY (1<<8) +#define LIBSSH2_TRACE_SOCKET (1<<9) + +typedef void (*libssh2_trace_handler_func)(LIBSSH2_SESSION*, + void*, + const char *, + size_t); +LIBSSH2_API int libssh2_trace_sethandler(LIBSSH2_SESSION *session, + void* context, + libssh2_trace_handler_func callback); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* !RC_INVOKED */ + +#endif /* LIBSSH2_H */ diff --git a/vendor/libssh2-1.4.2/include/libssh2_publickey.h b/vendor/libssh2-1.4.2/include/libssh2_publickey.h new file mode 100644 index 0000000..7350e9f --- /dev/null +++ b/vendor/libssh2-1.4.2/include/libssh2_publickey.h @@ -0,0 +1,118 @@ +/* Copyright (c) 2004-2006, Sara Golemon + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +/* Note: This include file is only needed for using the + * publickey SUBSYSTEM which is not the same as publickey + * authentication. For authentication you only need libssh2.h + * + * For more information on the publickey subsystem, + * refer to IETF draft: secsh-publickey + */ + +#ifndef LIBSSH2_PUBLICKEY_H +#define LIBSSH2_PUBLICKEY_H 1 + +#include "libssh2.h" + +typedef struct _LIBSSH2_PUBLICKEY LIBSSH2_PUBLICKEY; + +typedef struct _libssh2_publickey_attribute { + const char *name; + unsigned long name_len; + const char *value; + unsigned long value_len; + char mandatory; +} libssh2_publickey_attribute; + +typedef struct _libssh2_publickey_list { + unsigned char *packet; /* For freeing */ + + const unsigned char *name; + unsigned long name_len; + const unsigned char *blob; + unsigned long blob_len; + unsigned long num_attrs; + libssh2_publickey_attribute *attrs; /* free me */ +} libssh2_publickey_list; + +/* Generally use the first macro here, but if both name and value are string literals, you can use _fast() to take advantage of preprocessing */ +#define libssh2_publickey_attribute(name, value, mandatory) \ + { (name), strlen(name), (value), strlen(value), (mandatory) }, +#define libssh2_publickey_attribute_fast(name, value, mandatory) \ + { (name), sizeof(name) - 1, (value), sizeof(value) - 1, (mandatory) }, + +#ifdef __cplusplus +extern "C" { +#endif + +/* Publickey Subsystem */ +LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session); + +LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, + const unsigned char *name, + unsigned long name_len, + const unsigned char *blob, + unsigned long blob_len, char overwrite, + unsigned long num_attrs, + const libssh2_publickey_attribute attrs[]); +#define libssh2_publickey_add(pkey, name, blob, blob_len, overwrite, \ + num_attrs, attrs) \ + libssh2_publickey_add_ex((pkey), (name), strlen(name), (blob), (blob_len), \ + (overwrite), (num_attrs), (attrs)) + +LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, + const unsigned char *name, + unsigned long name_len, + const unsigned char *blob, + unsigned long blob_len); +#define libssh2_publickey_remove(pkey, name, blob, blob_len) \ + libssh2_publickey_remove_ex((pkey), (name), strlen(name), (blob), (blob_len)) + +LIBSSH2_API int +libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, + unsigned long *num_keys, + libssh2_publickey_list **pkey_list); +LIBSSH2_API void libssh2_publickey_list_free(LIBSSH2_PUBLICKEY *pkey, + libssh2_publickey_list *pkey_list); + +LIBSSH2_API int libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* ifndef: LIBSSH2_PUBLICKEY_H */ diff --git a/vendor/libssh2-1.4.2/include/libssh2_sftp.h b/vendor/libssh2-1.4.2/include/libssh2_sftp.h new file mode 100644 index 0000000..74884fb --- /dev/null +++ b/vendor/libssh2-1.4.2/include/libssh2_sftp.h @@ -0,0 +1,345 @@ +/* Copyright (c) 2004-2008, Sara Golemon + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#ifndef LIBSSH2_SFTP_H +#define LIBSSH2_SFTP_H 1 + +#include "libssh2.h" + +#ifndef WIN32 +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Note: Version 6 was documented at the time of writing + * However it was marked as "DO NOT IMPLEMENT" due to pending changes + * + * Let's start with Version 3 (The version found in OpenSSH) and go from there + */ +#define LIBSSH2_SFTP_VERSION 3 + +typedef struct _LIBSSH2_SFTP LIBSSH2_SFTP; +typedef struct _LIBSSH2_SFTP_HANDLE LIBSSH2_SFTP_HANDLE; +typedef struct _LIBSSH2_SFTP_ATTRIBUTES LIBSSH2_SFTP_ATTRIBUTES; +typedef struct _LIBSSH2_SFTP_STATVFS LIBSSH2_SFTP_STATVFS; + +/* Flags for open_ex() */ +#define LIBSSH2_SFTP_OPENFILE 0 +#define LIBSSH2_SFTP_OPENDIR 1 + +/* Flags for rename_ex() */ +#define LIBSSH2_SFTP_RENAME_OVERWRITE 0x00000001 +#define LIBSSH2_SFTP_RENAME_ATOMIC 0x00000002 +#define LIBSSH2_SFTP_RENAME_NATIVE 0x00000004 + +/* Flags for stat_ex() */ +#define LIBSSH2_SFTP_STAT 0 +#define LIBSSH2_SFTP_LSTAT 1 +#define LIBSSH2_SFTP_SETSTAT 2 + +/* Flags for symlink_ex() */ +#define LIBSSH2_SFTP_SYMLINK 0 +#define LIBSSH2_SFTP_READLINK 1 +#define LIBSSH2_SFTP_REALPATH 2 + +/* SFTP attribute flag bits */ +#define LIBSSH2_SFTP_ATTR_SIZE 0x00000001 +#define LIBSSH2_SFTP_ATTR_UIDGID 0x00000002 +#define LIBSSH2_SFTP_ATTR_PERMISSIONS 0x00000004 +#define LIBSSH2_SFTP_ATTR_ACMODTIME 0x00000008 +#define LIBSSH2_SFTP_ATTR_EXTENDED 0x80000000 + +/* SFTP statvfs flag bits */ +#define LIBSSH2_SFTP_ST_RDONLY 0x00000001 +#define LIBSSH2_SFTP_ST_NOSUID 0x00000002 + +struct _LIBSSH2_SFTP_ATTRIBUTES { + /* If flags & ATTR_* bit is set, then the value in this struct will be + * meaningful Otherwise it should be ignored + */ + unsigned long flags; + + libssh2_uint64_t filesize; + unsigned long uid, gid; + unsigned long permissions; + unsigned long atime, mtime; +}; + +struct _LIBSSH2_SFTP_STATVFS { + libssh2_uint64_t f_bsize; /* file system block size */ + libssh2_uint64_t f_frsize; /* fragment size */ + libssh2_uint64_t f_blocks; /* size of fs in f_frsize units */ + libssh2_uint64_t f_bfree; /* # free blocks */ + libssh2_uint64_t f_bavail; /* # free blocks for non-root */ + libssh2_uint64_t f_files; /* # inodes */ + libssh2_uint64_t f_ffree; /* # free inodes */ + libssh2_uint64_t f_favail; /* # free inodes for non-root */ + libssh2_uint64_t f_fsid; /* file system ID */ + libssh2_uint64_t f_flag; /* mount flags */ + libssh2_uint64_t f_namemax; /* maximum filename length */ +}; + +/* SFTP filetypes */ +#define LIBSSH2_SFTP_TYPE_REGULAR 1 +#define LIBSSH2_SFTP_TYPE_DIRECTORY 2 +#define LIBSSH2_SFTP_TYPE_SYMLINK 3 +#define LIBSSH2_SFTP_TYPE_SPECIAL 4 +#define LIBSSH2_SFTP_TYPE_UNKNOWN 5 +#define LIBSSH2_SFTP_TYPE_SOCKET 6 +#define LIBSSH2_SFTP_TYPE_CHAR_DEVICE 7 +#define LIBSSH2_SFTP_TYPE_BLOCK_DEVICE 8 +#define LIBSSH2_SFTP_TYPE_FIFO 9 + +/* + * Reproduce the POSIX file modes here for systems that are not POSIX + * compliant. + * + * These is used in "permissions" of "struct _LIBSSH2_SFTP_ATTRIBUTES" + */ +/* File type */ +#define LIBSSH2_SFTP_S_IFMT 0170000 /* type of file mask */ +#define LIBSSH2_SFTP_S_IFIFO 0010000 /* named pipe (fifo) */ +#define LIBSSH2_SFTP_S_IFCHR 0020000 /* character special */ +#define LIBSSH2_SFTP_S_IFDIR 0040000 /* directory */ +#define LIBSSH2_SFTP_S_IFBLK 0060000 /* block special */ +#define LIBSSH2_SFTP_S_IFREG 0100000 /* regular */ +#define LIBSSH2_SFTP_S_IFLNK 0120000 /* symbolic link */ +#define LIBSSH2_SFTP_S_IFSOCK 0140000 /* socket */ + +/* File mode */ +/* Read, write, execute/search by owner */ +#define LIBSSH2_SFTP_S_IRWXU 0000700 /* RWX mask for owner */ +#define LIBSSH2_SFTP_S_IRUSR 0000400 /* R for owner */ +#define LIBSSH2_SFTP_S_IWUSR 0000200 /* W for owner */ +#define LIBSSH2_SFTP_S_IXUSR 0000100 /* X for owner */ +/* Read, write, execute/search by group */ +#define LIBSSH2_SFTP_S_IRWXG 0000070 /* RWX mask for group */ +#define LIBSSH2_SFTP_S_IRGRP 0000040 /* R for group */ +#define LIBSSH2_SFTP_S_IWGRP 0000020 /* W for group */ +#define LIBSSH2_SFTP_S_IXGRP 0000010 /* X for group */ +/* Read, write, execute/search by others */ +#define LIBSSH2_SFTP_S_IRWXO 0000007 /* RWX mask for other */ +#define LIBSSH2_SFTP_S_IROTH 0000004 /* R for other */ +#define LIBSSH2_SFTP_S_IWOTH 0000002 /* W for other */ +#define LIBSSH2_SFTP_S_IXOTH 0000001 /* X for other */ + +/* macros to check for specific file types, added in 1.2.5 */ +#define LIBSSH2_SFTP_S_ISLNK(m) \ + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFLNK) +#define LIBSSH2_SFTP_S_ISREG(m) \ + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFREG) +#define LIBSSH2_SFTP_S_ISDIR(m) \ + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFDIR) +#define LIBSSH2_SFTP_S_ISCHR(m) \ + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFCHR) +#define LIBSSH2_SFTP_S_ISBLK(m) \ + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFBLK) +#define LIBSSH2_SFTP_S_ISFIFO(m) \ + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFIFO) +#define LIBSSH2_SFTP_S_ISSOCK(m) \ + (((m) & LIBSSH2_SFTP_S_IFMT) == LIBSSH2_SFTP_S_IFSOCK) + +/* SFTP File Transfer Flags -- (e.g. flags parameter to sftp_open()) + * Danger will robinson... APPEND doesn't have any effect on OpenSSH servers */ +#define LIBSSH2_FXF_READ 0x00000001 +#define LIBSSH2_FXF_WRITE 0x00000002 +#define LIBSSH2_FXF_APPEND 0x00000004 +#define LIBSSH2_FXF_CREAT 0x00000008 +#define LIBSSH2_FXF_TRUNC 0x00000010 +#define LIBSSH2_FXF_EXCL 0x00000020 + +/* SFTP Status Codes (returned by libssh2_sftp_last_error() ) */ +#define LIBSSH2_FX_OK 0 +#define LIBSSH2_FX_EOF 1 +#define LIBSSH2_FX_NO_SUCH_FILE 2 +#define LIBSSH2_FX_PERMISSION_DENIED 3 +#define LIBSSH2_FX_FAILURE 4 +#define LIBSSH2_FX_BAD_MESSAGE 5 +#define LIBSSH2_FX_NO_CONNECTION 6 +#define LIBSSH2_FX_CONNECTION_LOST 7 +#define LIBSSH2_FX_OP_UNSUPPORTED 8 +#define LIBSSH2_FX_INVALID_HANDLE 9 +#define LIBSSH2_FX_NO_SUCH_PATH 10 +#define LIBSSH2_FX_FILE_ALREADY_EXISTS 11 +#define LIBSSH2_FX_WRITE_PROTECT 12 +#define LIBSSH2_FX_NO_MEDIA 13 +#define LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM 14 +#define LIBSSH2_FX_QUOTA_EXCEEDED 15 +#define LIBSSH2_FX_UNKNOWN_PRINCIPLE 16 /* Initial mis-spelling */ +#define LIBSSH2_FX_UNKNOWN_PRINCIPAL 16 +#define LIBSSH2_FX_LOCK_CONFlICT 17 /* Initial mis-spelling */ +#define LIBSSH2_FX_LOCK_CONFLICT 17 +#define LIBSSH2_FX_DIR_NOT_EMPTY 18 +#define LIBSSH2_FX_NOT_A_DIRECTORY 19 +#define LIBSSH2_FX_INVALID_FILENAME 20 +#define LIBSSH2_FX_LINK_LOOP 21 + +/* Returned by any function that would block during a read/write opperation */ +#define LIBSSH2SFTP_EAGAIN LIBSSH2_ERROR_EAGAIN + +/* SFTP API */ +LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session); +LIBSSH2_API int libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp); +LIBSSH2_API unsigned long libssh2_sftp_last_error(LIBSSH2_SFTP *sftp); +LIBSSH2_API LIBSSH2_CHANNEL *libssh2_sftp_get_channel(LIBSSH2_SFTP *sftp); + +/* File / Directory Ops */ +LIBSSH2_API LIBSSH2_SFTP_HANDLE *libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, + const char *filename, + unsigned int filename_len, + unsigned long flags, + long mode, int open_type); +#define libssh2_sftp_open(sftp, filename, flags, mode) \ + libssh2_sftp_open_ex((sftp), (filename), strlen(filename), (flags), \ + (mode), LIBSSH2_SFTP_OPENFILE) +#define libssh2_sftp_opendir(sftp, path) \ + libssh2_sftp_open_ex((sftp), (path), strlen(path), 0, 0, \ + LIBSSH2_SFTP_OPENDIR) + +LIBSSH2_API ssize_t libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *handle, + char *buffer, size_t buffer_maxlen); + +LIBSSH2_API int libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *handle, \ + char *buffer, size_t buffer_maxlen, + char *longentry, + size_t longentry_maxlen, + LIBSSH2_SFTP_ATTRIBUTES *attrs); +#define libssh2_sftp_readdir(handle, buffer, buffer_maxlen, attrs) \ + libssh2_sftp_readdir_ex((handle), (buffer), (buffer_maxlen), NULL, 0, \ + (attrs)) + +LIBSSH2_API ssize_t libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle, + const char *buffer, size_t count); + +LIBSSH2_API int libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle); +#define libssh2_sftp_close(handle) libssh2_sftp_close_handle(handle) +#define libssh2_sftp_closedir(handle) libssh2_sftp_close_handle(handle) + +LIBSSH2_API void libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset); +LIBSSH2_API void libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle, + libssh2_uint64_t offset); +#define libssh2_sftp_rewind(handle) libssh2_sftp_seek64((handle), 0) + +LIBSSH2_API size_t libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle); +LIBSSH2_API libssh2_uint64_t libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE *handle); + +LIBSSH2_API int libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *handle, + LIBSSH2_SFTP_ATTRIBUTES *attrs, + int setstat); +#define libssh2_sftp_fstat(handle, attrs) \ + libssh2_sftp_fstat_ex((handle), (attrs), 0) +#define libssh2_sftp_fsetstat(handle, attrs) \ + libssh2_sftp_fstat_ex((handle), (attrs), 1) + +/* Miscellaneous Ops */ +LIBSSH2_API int libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, + const char *source_filename, + unsigned int srouce_filename_len, + const char *dest_filename, + unsigned int dest_filename_len, + long flags); +#define libssh2_sftp_rename(sftp, sourcefile, destfile) \ + libssh2_sftp_rename_ex((sftp), (sourcefile), strlen(sourcefile), \ + (destfile), strlen(destfile), \ + LIBSSH2_SFTP_RENAME_OVERWRITE | \ + LIBSSH2_SFTP_RENAME_ATOMIC | \ + LIBSSH2_SFTP_RENAME_NATIVE) + +LIBSSH2_API int libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, + const char *filename, + unsigned int filename_len); +#define libssh2_sftp_unlink(sftp, filename) \ + libssh2_sftp_unlink_ex((sftp), (filename), strlen(filename)) + +LIBSSH2_API int libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, + LIBSSH2_SFTP_STATVFS *st); + +LIBSSH2_API int libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp, + const char *path, + size_t path_len, + LIBSSH2_SFTP_STATVFS *st); + +LIBSSH2_API int libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, + const char *path, + unsigned int path_len, long mode); +#define libssh2_sftp_mkdir(sftp, path, mode) \ + libssh2_sftp_mkdir_ex((sftp), (path), strlen(path), (mode)) + +LIBSSH2_API int libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, + const char *path, + unsigned int path_len); +#define libssh2_sftp_rmdir(sftp, path) \ + libssh2_sftp_rmdir_ex((sftp), (path), strlen(path)) + +LIBSSH2_API int libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, + const char *path, + unsigned int path_len, + int stat_type, + LIBSSH2_SFTP_ATTRIBUTES *attrs); +#define libssh2_sftp_stat(sftp, path, attrs) \ + libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_STAT, \ + (attrs)) +#define libssh2_sftp_lstat(sftp, path, attrs) \ + libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_LSTAT, \ + (attrs)) +#define libssh2_sftp_setstat(sftp, path, attrs) \ + libssh2_sftp_stat_ex((sftp), (path), strlen(path), LIBSSH2_SFTP_SETSTAT, \ + (attrs)) + +LIBSSH2_API int libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, + const char *path, + unsigned int path_len, + char *target, + unsigned int target_len, int link_type); +#define libssh2_sftp_symlink(sftp, orig, linkpath) \ + libssh2_sftp_symlink_ex((sftp), (orig), strlen(orig), (linkpath), \ + strlen(linkpath), LIBSSH2_SFTP_SYMLINK) +#define libssh2_sftp_readlink(sftp, path, target, maxlen) \ + libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \ + LIBSSH2_SFTP_READLINK) +#define libssh2_sftp_realpath(sftp, path, target, maxlen) \ + libssh2_sftp_symlink_ex((sftp), (path), strlen(path), (target), (maxlen), \ + LIBSSH2_SFTP_REALPATH) + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* LIBSSH2_SFTP_H */ diff --git a/vendor/libssh2-1.4.2/libssh2_debug.a b/vendor/libssh2-1.4.2/libssh2_debug.a new file mode 100644 index 0000000000000000000000000000000000000000..f08659b371ce2d4c22843ca9ea986b923e82553b GIT binary patch literal 1108128 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%0D))|pOTX2L9I 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

=o!c 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 z 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

buj1wQKZZiSThIG3)Yht^PrxzwX|&zI{9& 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%0Dw-=)lbaTVsli}mSM9_#% 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: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 nz7Rj_yZ0SMKpq&5lIV< +#ifdef HAVE_SYS_UN_H +#include +#else +/* Use the existence of sys/un.h as a test if Unix domain socket is + supported. winsock*.h define PF_UNIX/AF_UNIX but do not actually + support them. */ +#undef PF_UNIX +#endif +#include "userauth.h" +#include "session.h" + +/* Requests from client to agent for protocol 1 key operations */ +#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1 +#define SSH_AGENTC_RSA_CHALLENGE 3 +#define SSH_AGENTC_ADD_RSA_IDENTITY 7 +#define SSH_AGENTC_REMOVE_RSA_IDENTITY 8 +#define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9 +#define SSH_AGENTC_ADD_RSA_ID_CONSTRAINED 24 + +/* Requests from client to agent for protocol 2 key operations */ +#define SSH2_AGENTC_REQUEST_IDENTITIES 11 +#define SSH2_AGENTC_SIGN_REQUEST 13 +#define SSH2_AGENTC_ADD_IDENTITY 17 +#define SSH2_AGENTC_REMOVE_IDENTITY 18 +#define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19 +#define SSH2_AGENTC_ADD_ID_CONSTRAINED 25 + +/* Key-type independent requests from client to agent */ +#define SSH_AGENTC_ADD_SMARTCARD_KEY 20 +#define SSH_AGENTC_REMOVE_SMARTCARD_KEY 21 +#define SSH_AGENTC_LOCK 22 +#define SSH_AGENTC_UNLOCK 23 +#define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26 + +/* Generic replies from agent to client */ +#define SSH_AGENT_FAILURE 5 +#define SSH_AGENT_SUCCESS 6 + +/* Replies from agent to client for protocol 1 key operations */ +#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2 +#define SSH_AGENT_RSA_RESPONSE 4 + +/* Replies from agent to client for protocol 2 key operations */ +#define SSH2_AGENT_IDENTITIES_ANSWER 12 +#define SSH2_AGENT_SIGN_RESPONSE 14 + +/* Key constraint identifiers */ +#define SSH_AGENT_CONSTRAIN_LIFETIME 1 +#define SSH_AGENT_CONSTRAIN_CONFIRM 2 + +/* non-blocking mode on agent connection is not yet implemented, but + for future use. */ +typedef enum { + agent_NB_state_init = 0, + agent_NB_state_request_created, + agent_NB_state_request_length_sent, + agent_NB_state_request_sent, + agent_NB_state_response_length_received, + agent_NB_state_response_received +} agent_nonblocking_states; + +typedef struct agent_transaction_ctx { + unsigned char *request; + size_t request_len; + unsigned char *response; + size_t response_len; + agent_nonblocking_states state; +} *agent_transaction_ctx_t; + +typedef int (*agent_connect_func)(LIBSSH2_AGENT *agent); +typedef int (*agent_transact_func)(LIBSSH2_AGENT *agent, + agent_transaction_ctx_t transctx); +typedef int (*agent_disconnect_func)(LIBSSH2_AGENT *agent); + +struct agent_publickey { + struct list_node node; + + /* this is the struct we expose externally */ + struct libssh2_agent_publickey external; +}; + +struct agent_ops { + agent_connect_func connect; + agent_transact_func transact; + agent_disconnect_func disconnect; +}; + +struct _LIBSSH2_AGENT +{ + LIBSSH2_SESSION *session; /* the session this "belongs to" */ + + libssh2_socket_t fd; + + struct agent_ops *ops; + + struct agent_transaction_ctx transctx; + struct agent_publickey *identity; + struct list_head head; /* list of public keys */ +}; + +#ifdef PF_UNIX +static int +agent_connect_unix(LIBSSH2_AGENT *agent) +{ + const char *path; + struct sockaddr_un s_un; + + path = getenv("SSH_AUTH_SOCK"); + if (!path) + return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE, + "no auth sock variable"); + + agent->fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (agent->fd < 0) + return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_SOCKET, + "failed creating socket"); + + s_un.sun_family = AF_UNIX; + strncpy (s_un.sun_path, path, sizeof s_un.sun_path); + if (connect(agent->fd, (struct sockaddr*)(&s_un), sizeof s_un) != 0) { + close (agent->fd); + return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, + "failed connecting with agent"); + } + + return LIBSSH2_ERROR_NONE; +} + +static int +agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) +{ + unsigned char buf[4]; + int rc; + + /* Send the length of the request */ + if (transctx->state == agent_NB_state_request_created) { + _libssh2_htonu32(buf, transctx->request_len); + rc = LIBSSH2_SEND_FD(agent->session, agent->fd, buf, sizeof buf, 0); + if (rc == -EAGAIN) + return LIBSSH2_ERROR_EAGAIN; + else if (rc < 0) + return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND, + "agent send failed"); + transctx->state = agent_NB_state_request_length_sent; + } + + /* Send the request body */ + if (transctx->state == agent_NB_state_request_length_sent) { + rc = LIBSSH2_SEND_FD(agent->session, agent->fd, transctx->request, + transctx->request_len, 0); + if (rc == -EAGAIN) + return LIBSSH2_ERROR_EAGAIN; + else if (rc < 0) + return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND, + "agent send failed"); + transctx->state = agent_NB_state_request_sent; + } + + /* Receive the length of a response */ + if (transctx->state == agent_NB_state_request_sent) { + rc = LIBSSH2_RECV_FD(agent->session, agent->fd, buf, sizeof buf, 0); + if (rc < 0) { + if (rc == -EAGAIN) + return LIBSSH2_ERROR_EAGAIN; + return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_RECV, + "agent recv failed"); + } + transctx->response_len = _libssh2_ntohu32(buf); + transctx->response = LIBSSH2_ALLOC(agent->session, + transctx->response_len); + if (!transctx->response) + return LIBSSH2_ERROR_ALLOC; + + transctx->state = agent_NB_state_response_length_received; + } + + /* Receive the response body */ + if (transctx->state == agent_NB_state_response_length_received) { + rc = LIBSSH2_RECV_FD(agent->session, agent->fd, transctx->response, + transctx->response_len, 0); + if (rc < 0) { + if (rc == -EAGAIN) + return LIBSSH2_ERROR_EAGAIN; + return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND, + "agent recv failed"); + } + transctx->state = agent_NB_state_response_received; + } + + return 0; +} + +static int +agent_disconnect_unix(LIBSSH2_AGENT *agent) +{ + int ret; + ret = close(agent->fd); + + if(ret == -1) + return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_DISCONNECT, + "failed closing the agent socket"); + return LIBSSH2_ERROR_NONE; +} + +struct agent_ops agent_ops_unix = { + agent_connect_unix, + agent_transact_unix, + agent_disconnect_unix +}; +#endif /* PF_UNIX */ + +#ifdef WIN32 +/* Code to talk to Pageant was taken from PuTTY. + * + * Portions copyright Robert de Bath, Joris van Rantwijk, Delian + * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas + * Barry, Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, + * Markus Kuhn, Colin Watson, and CORE SDI S.A. + */ +#define PAGEANT_COPYDATA_ID 0x804e50ba /* random goop */ +#define PAGEANT_MAX_MSGLEN 8192 + +static int +agent_connect_pageant(LIBSSH2_AGENT *agent) +{ + HWND hwnd; + hwnd = FindWindow("Pageant", "Pageant"); + if (!hwnd) + return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, + "failed connecting agent"); + agent->fd = 0; /* Mark as the connection has been established */ + return LIBSSH2_ERROR_NONE; +} + +static int +agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx) +{ + HWND hwnd; + char mapname[23]; + HANDLE filemap; + unsigned char *p; + unsigned char *p2; + int id; + COPYDATASTRUCT cds; + + if (!transctx || 4 + transctx->request_len > PAGEANT_MAX_MSGLEN) + return _libssh2_error(agent->session, LIBSSH2_ERROR_INVAL, + "illegal input"); + + hwnd = FindWindow("Pageant", "Pageant"); + if (!hwnd) + return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, + "found no pageant"); + + sprintf(mapname, "PageantRequest%08x", (unsigned)GetCurrentThreadId()); + filemap = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + 0, PAGEANT_MAX_MSGLEN, mapname); + + if (filemap == NULL || filemap == INVALID_HANDLE_VALUE) + return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, + "failed setting up pageant filemap"); + + p2 = p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0); + _libssh2_store_str(&p2, (const char *)transctx->request, + transctx->request_len); + + cds.dwData = PAGEANT_COPYDATA_ID; + cds.cbData = 1 + strlen(mapname); + cds.lpData = mapname; + + id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds); + if (id > 0) { + transctx->response_len = _libssh2_ntohu32(p); + if (transctx->response_len > PAGEANT_MAX_MSGLEN) { + UnmapViewOfFile(p); + CloseHandle(filemap); + return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL, + "agent setup fail"); + } + transctx->response = LIBSSH2_ALLOC(agent->session, + transctx->response_len); + if (!transctx->response) { + UnmapViewOfFile(p); + CloseHandle(filemap); + return _libssh2_error(agent->session, LIBSSH2_ERROR_ALLOC, + "agent malloc"); + } + memcpy(transctx->response, p + 4, transctx->response_len); + } + + UnmapViewOfFile(p); + CloseHandle(filemap); + return 0; +} + +static int +agent_disconnect_pageant(LIBSSH2_AGENT *agent) +{ + agent->fd = LIBSSH2_INVALID_SOCKET; + return 0; +} + +struct agent_ops agent_ops_pageant = { + agent_connect_pageant, + agent_transact_pageant, + agent_disconnect_pageant +}; +#endif /* WIN32 */ + +static struct { + const char *name; + struct agent_ops *ops; +} supported_backends[] = { +#ifdef WIN32 + {"Pageant", &agent_ops_pageant}, +#endif /* WIN32 */ +#ifdef PF_UNIX + {"Unix", &agent_ops_unix}, +#endif /* PF_UNIX */ + {NULL, NULL} +}; + +static int +agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, + const unsigned char *data, size_t data_len, void **abstract) +{ + LIBSSH2_AGENT *agent = (LIBSSH2_AGENT *) (*abstract); + agent_transaction_ctx_t transctx = &agent->transctx; + struct agent_publickey *identity = agent->identity; + ssize_t len = 1 + 4 + identity->external.blob_len + 4 + data_len + 4; + ssize_t method_len; + unsigned char *s; + int rc; + + /* Create a request to sign the data */ + if (transctx->state == agent_NB_state_init) { + s = transctx->request = LIBSSH2_ALLOC(session, len); + if (!transctx->request) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "out of memory"); + + *s++ = SSH2_AGENTC_SIGN_REQUEST; + /* key blob */ + _libssh2_store_str(&s, (const char *)identity->external.blob, + identity->external.blob_len); + /* data */ + _libssh2_store_str(&s, (const char *)data, data_len); + + /* flags */ + _libssh2_store_u32(&s, 0); + + transctx->request_len = s - transctx->request; + transctx->state = agent_NB_state_request_created; + } + + /* Make sure to be re-called as a result of EAGAIN. */ + if (*transctx->request != SSH2_AGENTC_SIGN_REQUEST) + return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, + "illegal request"); + + if (!agent->ops) + /* if no agent has been connected, bail out */ + return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, + "agent not connected"); + + rc = agent->ops->transact(agent, transctx); + if (rc) { + goto error; + } + LIBSSH2_FREE(session, transctx->request); + transctx->request = NULL; + + len = transctx->response_len; + s = transctx->response; + len--; + if (len < 0) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + if (*s != SSH2_AGENT_SIGN_RESPONSE) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + s++; + + /* Skip the entire length of the signature */ + len -= 4; + if (len < 0) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + s += 4; + + /* Skip signing method */ + len -= 4; + if (len < 0) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + method_len = _libssh2_ntohu32(s); + s += 4; + len -= method_len; + if (len < 0) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + s += method_len; + + /* Read the signature */ + len -= 4; + if (len < 0) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + *sig_len = _libssh2_ntohu32(s); + s += 4; + len -= *sig_len; + if (len < 0) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + + *sig = LIBSSH2_ALLOC(session, *sig_len); + if (!*sig) { + rc = LIBSSH2_ERROR_ALLOC; + goto error; + } + memcpy(*sig, s, *sig_len); + + error: + LIBSSH2_FREE(session, transctx->request); + transctx->request = NULL; + + LIBSSH2_FREE(session, transctx->response); + transctx->response = NULL; + + return _libssh2_error(session, rc, "agent sign failure"); +} + +static int +agent_list_identities(LIBSSH2_AGENT *agent) +{ + agent_transaction_ctx_t transctx = &agent->transctx; + ssize_t len, num_identities; + unsigned char *s; + int rc; + unsigned char c = SSH2_AGENTC_REQUEST_IDENTITIES; + + /* Create a request to list identities */ + if (transctx->state == agent_NB_state_init) { + transctx->request = &c; + transctx->request_len = 1; + transctx->state = agent_NB_state_request_created; + } + + /* Make sure to be re-called as a result of EAGAIN. */ + if (*transctx->request != SSH2_AGENTC_REQUEST_IDENTITIES) + return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE, + "illegal agent request"); + + if (!agent->ops) + /* if no agent has been connected, bail out */ + return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE, + "agent not connected"); + + rc = agent->ops->transact(agent, transctx); + if (rc) { + goto error; + } + transctx->request = NULL; + + len = transctx->response_len; + s = transctx->response; + len--; + if (len < 0) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + if (*s != SSH2_AGENT_IDENTITIES_ANSWER) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + s++; + + /* Read the length of identities */ + len -= 4; + if (len < 0) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + num_identities = _libssh2_ntohu32(s); + s += 4; + + while (num_identities--) { + struct agent_publickey *identity; + ssize_t comment_len; + + identity = LIBSSH2_ALLOC(agent->session, sizeof *identity); + if (!identity) { + rc = LIBSSH2_ERROR_ALLOC; + goto error; + } + + /* Read the length of the blob */ + len -= 4; + if (len < 0) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + identity->external.blob_len = _libssh2_ntohu32(s); + s += 4; + + /* Read the blob */ + len -= identity->external.blob_len; + if (len < 0) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + identity->external.blob = LIBSSH2_ALLOC(agent->session, + identity->external.blob_len); + if (!identity->external.blob) { + rc = LIBSSH2_ERROR_ALLOC; + goto error; + } + memcpy(identity->external.blob, s, identity->external.blob_len); + s += identity->external.blob_len; + + /* Read the length of the comment */ + len -= 4; + if (len < 0) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + comment_len = _libssh2_ntohu32(s); + s += 4; + + /* Read the comment */ + len -= comment_len; + if (len < 0) { + rc = LIBSSH2_ERROR_AGENT_PROTOCOL; + goto error; + } + identity->external.comment = LIBSSH2_ALLOC(agent->session, + comment_len + 1); + if (!identity->external.comment) { + rc = LIBSSH2_ERROR_ALLOC; + goto error; + } + identity->external.comment[comment_len] = '\0'; + memcpy(identity->external.comment, s, comment_len); + s += comment_len; + + _libssh2_list_add(&agent->head, &identity->node); + } + error: + LIBSSH2_FREE(agent->session, transctx->response); + transctx->response = NULL; + + return _libssh2_error(agent->session, rc, + "agent list id failed"); +} + +static void +agent_free_identities(LIBSSH2_AGENT *agent) { + struct agent_publickey *node; + struct agent_publickey *next; + + for (node = _libssh2_list_first(&agent->head); node; node = next) { + next = _libssh2_list_next(&node->node); + LIBSSH2_FREE(agent->session, node->external.blob); + LIBSSH2_FREE(agent->session, node->external.comment); + LIBSSH2_FREE(agent->session, node); + } + _libssh2_list_init(&agent->head); +} + +#define AGENT_PUBLICKEY_MAGIC 0x3bdefed2 +/* + * agent_publickey_to_external() + * + * Copies data from the internal to the external representation struct. + * + */ +static struct libssh2_agent_publickey * +agent_publickey_to_external(struct agent_publickey *node) +{ + struct libssh2_agent_publickey *ext = &node->external; + + ext->magic = AGENT_PUBLICKEY_MAGIC; + ext->node = node; + + return ext; +} + +/* + * libssh2_agent_init + * + * Init an ssh-agent handle. Returns the pointer to the handle. + * + */ +LIBSSH2_API LIBSSH2_AGENT * +libssh2_agent_init(LIBSSH2_SESSION *session) +{ + LIBSSH2_AGENT *agent; + + agent = LIBSSH2_ALLOC(session, sizeof *agent); + if (!agent) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate space for agent connection"); + return NULL; + } + memset(agent, 0, sizeof *agent); + agent->session = session; + _libssh2_list_init(&agent->head); + + return agent; +} + +/* + * libssh2_agent_connect() + * + * Connect to an ssh-agent. + * + * Returns 0 if succeeded, or a negative value for error. + */ +LIBSSH2_API int +libssh2_agent_connect(LIBSSH2_AGENT *agent) +{ + int i, rc = -1; + for (i = 0; supported_backends[i].name; i++) { + agent->ops = supported_backends[i].ops; + rc = agent->ops->connect(agent); + if (!rc) + return 0; + } + return rc; +} + +/* + * libssh2_agent_list_identities() + * + * Request ssh-agent to list identities. + * + * Returns 0 if succeeded, or a negative value for error. + */ +LIBSSH2_API int +libssh2_agent_list_identities(LIBSSH2_AGENT *agent) +{ + memset(&agent->transctx, 0, sizeof agent->transctx); + /* Abondon the last fetched identities */ + agent_free_identities(agent); + return agent_list_identities(agent); +} + +/* + * libssh2_agent_get_identity() + * + * Traverse the internal list of public keys. Pass NULL to 'prev' to get + * the first one. Or pass a poiner to the previously returned one to get the + * next. + * + * Returns: + * 0 if a fine public key was stored in 'store' + * 1 if end of public keys + * [negative] on errors + */ +LIBSSH2_API int +libssh2_agent_get_identity(LIBSSH2_AGENT *agent, + struct libssh2_agent_publickey **ext, + struct libssh2_agent_publickey *oprev) +{ + struct agent_publickey *node; + if (oprev && oprev->node) { + /* we have a starting point */ + struct agent_publickey *prev = oprev->node; + + /* get the next node in the list */ + node = _libssh2_list_next(&prev->node); + } + else + node = _libssh2_list_first(&agent->head); + + if (!node) + /* no (more) node */ + return 1; + + *ext = agent_publickey_to_external(node); + + return 0; +} + +/* + * libssh2_agent_userauth() + * + * Do publickey user authentication with the help of ssh-agent. + * + * Returns 0 if succeeded, or a negative value for error. + */ +LIBSSH2_API int +libssh2_agent_userauth(LIBSSH2_AGENT *agent, + const char *username, + struct libssh2_agent_publickey *identity) +{ + void *abstract = agent; + int rc; + + if (agent->session->userauth_pblc_state == libssh2_NB_state_idle) { + memset(&agent->transctx, 0, sizeof agent->transctx); + agent->identity = identity->node; + } + + BLOCK_ADJUST(rc, agent->session, + _libssh2_userauth_publickey(agent->session, username, + strlen(username), + identity->blob, + identity->blob_len, + agent_sign, + &abstract)); + return rc; +} + +/* + * libssh2_agent_disconnect() + * + * Close a connection to an ssh-agent. + * + * Returns 0 if succeeded, or a negative value for error. + */ +LIBSSH2_API int +libssh2_agent_disconnect(LIBSSH2_AGENT *agent) +{ + if (agent->ops && agent->fd != LIBSSH2_INVALID_SOCKET) + return agent->ops->disconnect(agent); + return 0; +} + +/* + * libssh2_agent_free() + * + * Free an ssh-agent handle. This function also frees the internal + * collection of public keys. + */ +LIBSSH2_API void +libssh2_agent_free(LIBSSH2_AGENT *agent) { + /* Allow connection freeing when the socket has lost its connection */ + if (agent->fd != LIBSSH2_INVALID_SOCKET) { + libssh2_agent_disconnect(agent); + } + agent_free_identities(agent); + LIBSSH2_FREE(agent->session, agent); +} diff --git a/vendor/libssh2-1.4.2/src/channel.c b/vendor/libssh2-1.4.2/src/channel.c new file mode 100644 index 0000000..63e5d5b --- /dev/null +++ b/vendor/libssh2-1.4.2/src/channel.c @@ -0,0 +1,2570 @@ +/* Copyright (c) 2004-2007 Sara Golemon + * Copyright (c) 2005 Mikhail Gusarov + * Copyright (c) 2008-2011 by Daniel Stenberg + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#ifdef HAVE_INTTYPES_H +#include +#endif +#include + +#include "channel.h" +#include "transport.h" +#include "packet.h" +#include "session.h" + +/* + * _libssh2_channel_nextid + * + * Determine the next channel ID we can use at our end + */ +uint32_t +_libssh2_channel_nextid(LIBSSH2_SESSION * session) +{ + uint32_t id = session->next_channel; + LIBSSH2_CHANNEL *channel; + + channel = _libssh2_list_first(&session->channels); + + while (channel) { + if (channel->local.id > id) { + id = channel->local.id; + } + channel = _libssh2_list_next(&channel->node); + } + + /* This is a shortcut to avoid waiting for close packets on channels we've + * forgotten about, This *could* be a problem if we request and close 4 + * billion or so channels in too rapid succession for the remote end to + * respond, but the worst case scenario is that some data meant for + * another channel Gets picked up by the new one.... Pretty unlikely all + * told... + */ + session->next_channel = id + 1; + _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Allocated new channel ID#%lu", + id); + return id; +} + +/* + * _libssh2_channel_locate + * + * Locate a channel pointer by number + */ +LIBSSH2_CHANNEL * +_libssh2_channel_locate(LIBSSH2_SESSION *session, uint32_t channel_id) +{ + LIBSSH2_CHANNEL *channel; + LIBSSH2_LISTENER *l; + + for(channel = _libssh2_list_first(&session->channels); + channel; + channel = _libssh2_list_next(&channel->node)) { + if (channel->local.id == channel_id) + return channel; + } + + /* We didn't find the channel in the session, let's then check its + listeners since each listener may have its own set of pending channels + */ + for(l = _libssh2_list_first(&session->listeners); l; + l = _libssh2_list_next(&l->node)) { + for(channel = _libssh2_list_first(&l->queue); + channel; + channel = _libssh2_list_next(&channel->node)) { + if (channel->local.id == channel_id) + return channel; + } + } + + return NULL; +} + +/* + * _libssh2_channel_open + * + * Establish a generic session channel + */ +LIBSSH2_CHANNEL * +_libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, + uint32_t channel_type_len, + uint32_t window_size, + uint32_t packet_size, + const unsigned char *message, + size_t message_len) +{ + static const unsigned char reply_codes[3] = { + SSH_MSG_CHANNEL_OPEN_CONFIRMATION, + SSH_MSG_CHANNEL_OPEN_FAILURE, + 0 + }; + unsigned char *s; + int rc; + + if (session->open_state == libssh2_NB_state_idle) { + session->open_channel = NULL; + session->open_packet = NULL; + session->open_data = NULL; + /* 17 = packet_type(1) + channel_type_len(4) + sender_channel(4) + + * window_size(4) + packet_size(4) */ + session->open_packet_len = channel_type_len + 17; + session->open_local_channel = _libssh2_channel_nextid(session); + + /* Zero the whole thing out */ + memset(&session->open_packet_requirev_state, 0, + sizeof(session->open_packet_requirev_state)); + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Opening Channel - win %d pack %d", window_size, + packet_size); + session->open_channel = + LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL)); + if (!session->open_channel) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate space for channel data"); + return NULL; + } + memset(session->open_channel, 0, sizeof(LIBSSH2_CHANNEL)); + + session->open_channel->channel_type_len = channel_type_len; + session->open_channel->channel_type = + LIBSSH2_ALLOC(session, channel_type_len); + if (!session->open_channel->channel_type) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed allocating memory for channel type name"); + LIBSSH2_FREE(session, session->open_channel); + session->open_channel = NULL; + return NULL; + } + memcpy(session->open_channel->channel_type, channel_type, + channel_type_len); + + /* REMEMBER: local as in locally sourced */ + session->open_channel->local.id = session->open_local_channel; + session->open_channel->remote.window_size = window_size; + session->open_channel->remote.window_size_initial = window_size; + session->open_channel->remote.packet_size = packet_size; + session->open_channel->session = session; + + _libssh2_list_add(&session->channels, + &session->open_channel->node); + + s = session->open_packet = + LIBSSH2_ALLOC(session, session->open_packet_len); + if (!session->open_packet) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate temporary space for packet"); + goto channel_error; + } + *(s++) = SSH_MSG_CHANNEL_OPEN; + _libssh2_store_str(&s, channel_type, channel_type_len); + _libssh2_store_u32(&s, session->open_local_channel); + _libssh2_store_u32(&s, window_size); + _libssh2_store_u32(&s, packet_size); + + /* Do not copy the message */ + + session->open_state = libssh2_NB_state_created; + } + + if (session->open_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, + session->open_packet, + session->open_packet_len, + message, message_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, rc, + "Would block sending channel-open request"); + return NULL; + } + else if (rc) { + _libssh2_error(session, rc, + "Unable to send channel-open request"); + goto channel_error; + } + + session->open_state = libssh2_NB_state_sent; + } + + if (session->open_state == libssh2_NB_state_sent) { + rc = _libssh2_packet_requirev(session, reply_codes, + &session->open_data, + &session->open_data_len, 1, + session->open_packet + 5 + + channel_type_len, 4, + &session->open_packet_requirev_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); + return NULL; + } else if (rc) { + goto channel_error; + } + + if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) { + session->open_channel->remote.id = + _libssh2_ntohu32(session->open_data + 5); + session->open_channel->local.window_size = + _libssh2_ntohu32(session->open_data + 9); + session->open_channel->local.window_size_initial = + _libssh2_ntohu32(session->open_data + 9); + session->open_channel->local.packet_size = + _libssh2_ntohu32(session->open_data + 13); + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Connection Established - ID: %lu/%lu win: %lu/%lu" + " pack: %lu/%lu", + session->open_channel->local.id, + session->open_channel->remote.id, + session->open_channel->local.window_size, + session->open_channel->remote.window_size, + session->open_channel->local.packet_size, + session->open_channel->remote.packet_size); + LIBSSH2_FREE(session, session->open_packet); + session->open_packet = NULL; + LIBSSH2_FREE(session, session->open_data); + session->open_data = NULL; + + session->open_state = libssh2_NB_state_idle; + return session->open_channel; + } + + if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_FAILURE) { + _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, + "Channel open failure"); + } + } + + channel_error: + + if (session->open_data) { + LIBSSH2_FREE(session, session->open_data); + session->open_data = NULL; + } + if (session->open_packet) { + LIBSSH2_FREE(session, session->open_packet); + session->open_packet = NULL; + } + if (session->open_channel) { + unsigned char channel_id[4]; + LIBSSH2_FREE(session, session->open_channel->channel_type); + + _libssh2_list_remove(&session->open_channel->node); + + /* Clear out packets meant for this channel */ + _libssh2_htonu32(channel_id, session->open_channel->local.id); + while ((_libssh2_packet_ask(session, SSH_MSG_CHANNEL_DATA, + &session->open_data, + &session->open_data_len, 1, + channel_id, 4) >= 0) + || + (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, + &session->open_data, + &session->open_data_len, 1, + channel_id, 4) >= 0)) { + LIBSSH2_FREE(session, session->open_data); + session->open_data = NULL; + } + + LIBSSH2_FREE(session, session->open_channel); + session->open_channel = NULL; + } + + session->open_state = libssh2_NB_state_idle; + return NULL; +} + +/* + * libssh2_channel_open_ex + * + * Establish a generic session channel + */ +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *type, + unsigned int type_len, + unsigned int window_size, unsigned int packet_size, + const char *msg, unsigned int msg_len) +{ + LIBSSH2_CHANNEL *ptr; + + if(!session) + return NULL; + + BLOCK_ADJUST_ERRNO(ptr, session, + _libssh2_channel_open(session, type, type_len, + window_size, packet_size, + (unsigned char *)msg, + msg_len)); + return ptr; +} + +/* + * libssh2_channel_direct_tcpip_ex + * + * Tunnel TCP/IP connect through the SSH session to direct host/port + */ +static LIBSSH2_CHANNEL * +channel_direct_tcpip(LIBSSH2_SESSION * session, const char *host, + int port, const char *shost, int sport) +{ + LIBSSH2_CHANNEL *channel; + unsigned char *s; + + if (session->direct_state == libssh2_NB_state_idle) { + session->direct_host_len = strlen(host); + session->direct_shost_len = strlen(shost); + /* host_len(4) + port(4) + shost_len(4) + sport(4) */ + session->direct_message_len = + session->direct_host_len + session->direct_shost_len + 16; + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Requesting direct-tcpip session to from %s:%d to %s:%d", + shost, sport, host, port); + + s = session->direct_message = + LIBSSH2_ALLOC(session, session->direct_message_len); + if (!session->direct_message) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for direct-tcpip connection"); + return NULL; + } + _libssh2_store_str(&s, host, session->direct_host_len); + _libssh2_store_u32(&s, port); + _libssh2_store_str(&s, shost, session->direct_shost_len); + _libssh2_store_u32(&s, sport); + } + + channel = + _libssh2_channel_open(session, "direct-tcpip", + sizeof("direct-tcpip") - 1, + LIBSSH2_CHANNEL_WINDOW_DEFAULT, + LIBSSH2_CHANNEL_PACKET_DEFAULT, + session->direct_message, + session->direct_message_len); + + if (!channel && + libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) { + /* The error code is still set to LIBSSH2_ERROR_EAGAIN, set our state + to created to avoid re-creating the package on next invoke */ + session->direct_state = libssh2_NB_state_created; + return NULL; + } + /* by default we set (keep?) idle state... */ + session->direct_state = libssh2_NB_state_idle; + + LIBSSH2_FREE(session, session->direct_message); + session->direct_message = NULL; + + return channel; +} + +/* + * libssh2_channel_direct_tcpip_ex + * + * Tunnel TCP/IP connect through the SSH session to direct host/port + */ +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host, + int port, const char *shost, int sport) +{ + LIBSSH2_CHANNEL *ptr; + + if(!session) + return NULL; + + BLOCK_ADJUST_ERRNO(ptr, session, + channel_direct_tcpip(session, host, port, shost, sport)); + return ptr; +} + +/* + * channel_forward_listen + * + * Bind a port on the remote host and listen for connections + */ +static LIBSSH2_LISTENER * +channel_forward_listen(LIBSSH2_SESSION * session, const char *host, + int port, int *bound_port, int queue_maxsize) +{ + unsigned char *s; + static const unsigned char reply_codes[3] = + { SSH_MSG_REQUEST_SUCCESS, SSH_MSG_REQUEST_FAILURE, 0 }; + int rc; + + if(!host) + host = "0.0.0.0"; + + if (session->fwdLstn_state == libssh2_NB_state_idle) { + session->fwdLstn_host_len = strlen(host); + /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + + port(4) */ + session->fwdLstn_packet_len = + session->fwdLstn_host_len + (sizeof("tcpip-forward") - 1) + 14; + + /* Zero the whole thing out */ + memset(&session->fwdLstn_packet_requirev_state, 0, + sizeof(session->fwdLstn_packet_requirev_state)); + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Requesting tcpip-forward session for %s:%d", host, + port); + + s = session->fwdLstn_packet = + LIBSSH2_ALLOC(session, session->fwdLstn_packet_len); + if (!session->fwdLstn_packet) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memeory for setenv packet"); + return NULL; + } + + *(s++) = SSH_MSG_GLOBAL_REQUEST; + _libssh2_store_str(&s, "tcpip-forward", sizeof("tcpip-forward") - 1); + *(s++) = 0x01; /* want_reply */ + + _libssh2_store_str(&s, host, session->fwdLstn_host_len); + _libssh2_store_u32(&s, port); + + session->fwdLstn_state = libssh2_NB_state_created; + } + + if (session->fwdLstn_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, + session->fwdLstn_packet, + session->fwdLstn_packet_len, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block sending global-request packet for " + "forward listen request"); + return NULL; + } + else if (rc) { + _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send global-request packet for forward " + "listen request"); + LIBSSH2_FREE(session, session->fwdLstn_packet); + session->fwdLstn_packet = NULL; + session->fwdLstn_state = libssh2_NB_state_idle; + return NULL; + } + LIBSSH2_FREE(session, session->fwdLstn_packet); + session->fwdLstn_packet = NULL; + + session->fwdLstn_state = libssh2_NB_state_sent; + } + + if (session->fwdLstn_state == libssh2_NB_state_sent) { + unsigned char *data; + size_t data_len; + rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, + 0, NULL, 0, + &session->fwdLstn_packet_requirev_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); + return NULL; + } else if (rc) { + _libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown"); + session->fwdLstn_state = libssh2_NB_state_idle; + return NULL; + } + + if (data[0] == SSH_MSG_REQUEST_SUCCESS) { + LIBSSH2_LISTENER *listener; + + listener = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_LISTENER)); + if (!listener) + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for listener queue"); + else { + memset(listener, 0, sizeof(LIBSSH2_LISTENER)); + listener->host = + LIBSSH2_ALLOC(session, session->fwdLstn_host_len + 1); + if (!listener->host) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for listener queue"); + LIBSSH2_FREE(session, listener); + listener = NULL; + } + else { + listener->session = session; + memcpy(listener->host, host ? host : "0.0.0.0", + session->fwdLstn_host_len); + listener->host[session->fwdLstn_host_len] = 0; + if (data_len >= 5 && !port) { + listener->port = _libssh2_ntohu32(data + 1); + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Dynamic tcpip-forward port allocated: %d", + listener->port); + } + else + listener->port = port; + + listener->queue_size = 0; + listener->queue_maxsize = queue_maxsize; + + /* append this to the parent's list of listeners */ + _libssh2_list_add(&session->listeners, &listener->node); + + if (bound_port) { + *bound_port = listener->port; + } + } + } + + LIBSSH2_FREE(session, data); + session->fwdLstn_state = libssh2_NB_state_idle; + return listener; + } + else if (data[0] == SSH_MSG_REQUEST_FAILURE) { + LIBSSH2_FREE(session, data); + _libssh2_error(session, LIBSSH2_ERROR_REQUEST_DENIED, + "Unable to complete request for forward-listen"); + session->fwdLstn_state = libssh2_NB_state_idle; + return NULL; + } + } + + session->fwdLstn_state = libssh2_NB_state_idle; + + return NULL; +} + +/* + * libssh2_channel_forward_listen_ex + * + * Bind a port on the remote host and listen for connections + */ +LIBSSH2_API LIBSSH2_LISTENER * +libssh2_channel_forward_listen_ex(LIBSSH2_SESSION *session, const char *host, + int port, int *bound_port, int queue_maxsize) +{ + LIBSSH2_LISTENER *ptr; + + if(!session) + return NULL; + + BLOCK_ADJUST_ERRNO(ptr, session, + channel_forward_listen(session, host, port, bound_port, + queue_maxsize)); + return ptr; +} + +/* + * _libssh2_channel_forward_cancel + * + * Stop listening on a remote port and free the listener + * Toss out any pending (un-accept()ed) connections + * + * Return 0 on success, LIBSSH2_ERROR_EAGAIN if would block, -1 on error + */ +int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener) +{ + LIBSSH2_SESSION *session = listener->session; + LIBSSH2_CHANNEL *queued; + unsigned char *packet, *s; + size_t host_len = strlen(listener->host); + /* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4) + + port(4) */ + size_t packet_len = + host_len + 14 + sizeof("cancel-tcpip-forward") - 1; + int rc; + + if (listener->chanFwdCncl_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Cancelling tcpip-forward session for %s:%d", + listener->host, listener->port); + + s = packet = LIBSSH2_ALLOC(session, packet_len); + if (!packet) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memeory for setenv packet"); + return LIBSSH2_ERROR_ALLOC; + } + + *(s++) = SSH_MSG_GLOBAL_REQUEST; + _libssh2_store_str(&s, "cancel-tcpip-forward", + sizeof("cancel-tcpip-forward") - 1); + *(s++) = 0x00; /* want_reply */ + + _libssh2_store_str(&s, listener->host, host_len); + _libssh2_store_u32(&s, listener->port); + + listener->chanFwdCncl_state = libssh2_NB_state_created; + } else { + packet = listener->chanFwdCncl_data; + } + + if (listener->chanFwdCncl_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, packet, packet_len, NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, rc, + "Would block sending forward request"); + listener->chanFwdCncl_data = packet; + return rc; + } + else if (rc) { + _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send global-request packet for forward " + "listen request"); + LIBSSH2_FREE(session, packet); + listener->chanFwdCncl_state = libssh2_NB_state_idle; + return LIBSSH2_ERROR_SOCKET_SEND; + } + LIBSSH2_FREE(session, packet); + + listener->chanFwdCncl_state = libssh2_NB_state_sent; + } + + queued = _libssh2_list_first(&listener->queue); + while (queued) { + LIBSSH2_CHANNEL *next = _libssh2_list_next(&queued->node); + + rc = _libssh2_channel_free(queued); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + queued = next; + } + LIBSSH2_FREE(session, listener->host); + + /* remove this entry from the parent's list of listeners */ + _libssh2_list_remove(&listener->node); + + LIBSSH2_FREE(session, listener); + + listener->chanFwdCncl_state = libssh2_NB_state_idle; + + return 0; +} + +/* + * libssh2_channel_forward_cancel + * + * Stop listening on a remote port and free the listener + * Toss out any pending (un-accept()ed) connections + * + * Return 0 on success, LIBSSH2_ERROR_EAGAIN if would block, -1 on error + */ +LIBSSH2_API int +libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener) +{ + int rc; + + if(!listener) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, listener->session, + _libssh2_channel_forward_cancel(listener)); + return rc; +} + +/* + * channel_forward_accept + * + * Accept a connection + */ +static LIBSSH2_CHANNEL * +channel_forward_accept(LIBSSH2_LISTENER *listener) +{ + int rc; + + do { + rc = _libssh2_transport_read(listener->session); + } while (rc > 0); + + if (_libssh2_list_first(&listener->queue)) { + LIBSSH2_CHANNEL *channel = _libssh2_list_first(&listener->queue); + + /* detach channel from listener's queue */ + _libssh2_list_remove(&channel->node); + + listener->queue_size--; + + /* add channel to session's channel list */ + _libssh2_list_add(&channel->session->channels, &channel->node); + + return channel; + } + + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(listener->session, LIBSSH2_ERROR_EAGAIN, + "Would block waiting for packet"); + } + else + _libssh2_error(listener->session, LIBSSH2_ERROR_CHANNEL_UNKNOWN, + "Channel not found"); + return NULL; +} + +/* + * libssh2_channel_forward_accept + * + * Accept a connection + */ +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_channel_forward_accept(LIBSSH2_LISTENER *listener) +{ + LIBSSH2_CHANNEL *ptr; + + if(!listener) + return NULL; + + BLOCK_ADJUST_ERRNO(ptr, listener->session, + channel_forward_accept(listener)); + return ptr; + +} + +/* + * channel_setenv + * + * Set an environment variable prior to requesting a shell/program/subsystem + */ +static int channel_setenv(LIBSSH2_CHANNEL *channel, + const char *varname, unsigned int varname_len, + const char *value, unsigned int value_len) +{ + LIBSSH2_SESSION *session = channel->session; + unsigned char *s, *data; + static const unsigned char reply_codes[3] = + { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; + size_t data_len; + int rc; + + if (channel->setenv_state == libssh2_NB_state_idle) { + /* 21 = packet_type(1) + channel_id(4) + request_len(4) + + * request(3)"env" + want_reply(1) + varname_len(4) + value_len(4) */ + channel->setenv_packet_len = varname_len + value_len + 21; + + /* Zero the whole thing out */ + memset(&channel->setenv_packet_requirev_state, 0, + sizeof(channel->setenv_packet_requirev_state)); + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Setting remote environment variable: %s=%s on " + "channel %lu/%lu", + varname, value, channel->local.id, channel->remote.id); + + s = channel->setenv_packet = + LIBSSH2_ALLOC(session, channel->setenv_packet_len); + if (!channel->setenv_packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memeory " + "for setenv packet"); + } + + *(s++) = SSH_MSG_CHANNEL_REQUEST; + _libssh2_store_u32(&s, channel->remote.id); + _libssh2_store_str(&s, "env", sizeof("env") - 1); + *(s++) = 0x01; + _libssh2_store_str(&s, varname, varname_len); + _libssh2_store_str(&s, value, value_len); + + channel->setenv_state = libssh2_NB_state_created; + } + + if (channel->setenv_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, + channel->setenv_packet, + channel->setenv_packet_len, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, rc, + "Would block sending setenv request"); + return rc; + } else if (rc) { + LIBSSH2_FREE(session, channel->setenv_packet); + channel->setenv_packet = NULL; + channel->setenv_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send channel-request packet for " + "setenv request"); + } + LIBSSH2_FREE(session, channel->setenv_packet); + channel->setenv_packet = NULL; + + _libssh2_htonu32(channel->setenv_local_channel, channel->local.id); + + channel->setenv_state = libssh2_NB_state_sent; + } + + if (channel->setenv_state == libssh2_NB_state_sent) { + rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, + 1, channel->setenv_local_channel, 4, + &channel-> + setenv_packet_requirev_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + if (rc) { + channel->setenv_state = libssh2_NB_state_idle; + return rc; + } + + if (data[0] == SSH_MSG_CHANNEL_SUCCESS) { + LIBSSH2_FREE(session, data); + channel->setenv_state = libssh2_NB_state_idle; + return 0; + } + + LIBSSH2_FREE(session, data); + } + + channel->setenv_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, + "Unable to complete request for channel-setenv"); +} + +/* + * libssh2_channel_setenv_ex + * + * Set an environment variable prior to requesting a shell/program/subsystem + */ +LIBSSH2_API int +libssh2_channel_setenv_ex(LIBSSH2_CHANNEL *channel, + const char *varname, unsigned int varname_len, + const char *value, unsigned int value_len) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, + channel_setenv(channel, varname, varname_len, + value, value_len)); + return rc; +} + +/* + * channel_request_pty + * Duh... Request a PTY + */ +static int channel_request_pty(LIBSSH2_CHANNEL *channel, + const char *term, unsigned int term_len, + const char *modes, unsigned int modes_len, + int width, int height, + int width_px, int height_px) +{ + LIBSSH2_SESSION *session = channel->session; + unsigned char *s; + static const unsigned char reply_codes[3] = + { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; + int rc; + + if (channel->reqPTY_state == libssh2_NB_state_idle) { + /* 41 = packet_type(1) + channel(4) + pty_req_len(4) + "pty_req"(7) + + * want_reply(1) + term_len(4) + width(4) + height(4) + width_px(4) + + * height_px(4) + modes_len(4) */ + if(term_len + modes_len > 256) { + return _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "term + mode lengths too large"); + } + + channel->reqPTY_packet_len = term_len + modes_len + 41; + + /* Zero the whole thing out */ + memset(&channel->reqPTY_packet_requirev_state, 0, + sizeof(channel->reqPTY_packet_requirev_state)); + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Allocating tty on channel %lu/%lu", channel->local.id, + channel->remote.id); + + s = channel->reqPTY_packet; + + *(s++) = SSH_MSG_CHANNEL_REQUEST; + _libssh2_store_u32(&s, channel->remote.id); + _libssh2_store_str(&s, (char *)"pty-req", sizeof("pty-req") - 1); + + *(s++) = 0x01; + + _libssh2_store_str(&s, term, term_len); + _libssh2_store_u32(&s, width); + _libssh2_store_u32(&s, height); + _libssh2_store_u32(&s, width_px); + _libssh2_store_u32(&s, height_px); + _libssh2_store_str(&s, modes, modes_len); + + channel->reqPTY_state = libssh2_NB_state_created; + } + + if (channel->reqPTY_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, channel->reqPTY_packet, + channel->reqPTY_packet_len, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, rc, + "Would block sending pty request"); + return rc; + } else if (rc) { + channel->reqPTY_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Unable to send pty-request packet"); + } + _libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id); + + channel->reqPTY_state = libssh2_NB_state_sent; + } + + if (channel->reqPTY_state == libssh2_NB_state_sent) { + unsigned char *data; + size_t data_len; + unsigned char code; + rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, + 1, channel->reqPTY_local_channel, 4, + &channel->reqPTY_packet_requirev_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + channel->reqPTY_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Failed to require the PTY package"); + } + + code = data[0]; + + LIBSSH2_FREE(session, data); + channel->reqPTY_state = libssh2_NB_state_idle; + + if (code == SSH_MSG_CHANNEL_SUCCESS) + return 0; + } + + return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, + "Unable to complete request for channel request-pty"); +} + +/* + * libssh2_channel_request_pty_ex + * Duh... Request a PTY + */ +LIBSSH2_API int +libssh2_channel_request_pty_ex(LIBSSH2_CHANNEL *channel, const char *term, + unsigned int term_len, const char *modes, + unsigned int modes_len, int width, int height, + int width_px, int height_px) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, + channel_request_pty(channel, term, term_len, modes, + modes_len, width, height, + width_px, height_px)); + return rc; +} + +static int +channel_request_pty_size(LIBSSH2_CHANNEL * channel, int width, + int height, int width_px, int height_px) +{ + LIBSSH2_SESSION *session = channel->session; + unsigned char *s; + int rc; + int retcode = LIBSSH2_ERROR_PROTO; + + if (channel->reqPTY_state == libssh2_NB_state_idle) { + channel->reqPTY_packet_len = 39; + + /* Zero the whole thing out */ + memset(&channel->reqPTY_packet_requirev_state, 0, + sizeof(channel->reqPTY_packet_requirev_state)); + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "changing tty size on channel %lu/%lu", + channel->local.id, + channel->remote.id); + + s = channel->reqPTY_packet; + + *(s++) = SSH_MSG_CHANNEL_REQUEST; + _libssh2_store_u32(&s, channel->remote.id); + _libssh2_store_str(&s, (char *)"window-change", + sizeof("window-change") - 1); + *(s++) = 0x00; /* Don't reply */ + _libssh2_store_u32(&s, width); + _libssh2_store_u32(&s, height); + _libssh2_store_u32(&s, width_px); + _libssh2_store_u32(&s, height_px); + + channel->reqPTY_state = libssh2_NB_state_created; + } + + if (channel->reqPTY_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, channel->reqPTY_packet, + channel->reqPTY_packet_len, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, rc, + "Would block sending window-change request"); + return rc; + } else if (rc) { + channel->reqPTY_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Unable to send window-change packet"); + } + _libssh2_htonu32(channel->reqPTY_local_channel, channel->local.id); + retcode = LIBSSH2_ERROR_NONE; + } + + channel->reqPTY_state = libssh2_NB_state_idle; + return retcode; +} + +LIBSSH2_API int +libssh2_channel_request_pty_size_ex(LIBSSH2_CHANNEL *channel, int width, + int height, int width_px, int height_px) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, + channel_request_pty_size(channel, width, height, width_px, + height_px)); + return rc; +} + +/* Keep this an even number */ +#define LIBSSH2_X11_RANDOM_COOKIE_LEN 32 + +/* + * channel_x11_req + * Request X11 forwarding + */ +static int +channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection, + const char *auth_proto, const char *auth_cookie, + int screen_number) +{ + LIBSSH2_SESSION *session = channel->session; + unsigned char *s; + static const unsigned char reply_codes[3] = + { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; + size_t proto_len = + auth_proto ? strlen(auth_proto) : (sizeof("MIT-MAGIC-COOKIE-1") - 1); + size_t cookie_len = + auth_cookie ? strlen(auth_cookie) : LIBSSH2_X11_RANDOM_COOKIE_LEN; + int rc; + + if (channel->reqX11_state == libssh2_NB_state_idle) { + /* 30 = packet_type(1) + channel(4) + x11_req_len(4) + "x11-req"(7) + + * want_reply(1) + single_cnx(1) + proto_len(4) + cookie_len(4) + + * screen_num(4) */ + channel->reqX11_packet_len = proto_len + cookie_len + 30; + + /* Zero the whole thing out */ + memset(&channel->reqX11_packet_requirev_state, 0, + sizeof(channel->reqX11_packet_requirev_state)); + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Requesting x11-req for channel %lu/%lu: single=%d " + "proto=%s cookie=%s screen=%d", + channel->local.id, channel->remote.id, + single_connection, + auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1", + auth_cookie ? auth_cookie : "", screen_number); + + s = channel->reqX11_packet = + LIBSSH2_ALLOC(session, channel->reqX11_packet_len); + if (!channel->reqX11_packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for pty-request"); + } + + *(s++) = SSH_MSG_CHANNEL_REQUEST; + _libssh2_store_u32(&s, channel->remote.id); + _libssh2_store_str(&s, "x11-req", sizeof("x11-req") - 1); + + *(s++) = 0x01; /* want_reply */ + *(s++) = single_connection ? 0x01 : 0x00; + + _libssh2_store_str(&s, auth_proto?auth_proto:"MIT-MAGIC-COOKIE-1", + proto_len); + + _libssh2_store_u32(&s, cookie_len); + if (auth_cookie) { + memcpy(s, auth_cookie, cookie_len); + } else { + int i; + /* note: the extra +1 below is necessary since the sprintf() + loop will always write 3 bytes so the last one will write + the trailing zero at the LIBSSH2_X11_RANDOM_COOKIE_LEN/2 + border */ + unsigned char buffer[(LIBSSH2_X11_RANDOM_COOKIE_LEN / 2) +1]; + + _libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); + for(i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) { + sprintf((char *)&s[i*2], "%02X", buffer[i]); + } + } + s += cookie_len; + + _libssh2_store_u32(&s, screen_number); + channel->reqX11_state = libssh2_NB_state_created; + } + + if (channel->reqX11_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, channel->reqX11_packet, + channel->reqX11_packet_len, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, rc, + "Would block sending X11-req packet"); + return rc; + } + if (rc) { + LIBSSH2_FREE(session, channel->reqX11_packet); + channel->reqX11_packet = NULL; + channel->reqX11_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Unable to send x11-req packet"); + } + LIBSSH2_FREE(session, channel->reqX11_packet); + channel->reqX11_packet = NULL; + + _libssh2_htonu32(channel->reqX11_local_channel, channel->local.id); + + channel->reqX11_state = libssh2_NB_state_sent; + } + + if (channel->reqX11_state == libssh2_NB_state_sent) { + size_t data_len; + unsigned char *data; + unsigned char code; + + rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, + 1, channel->reqX11_local_channel, 4, + &channel->reqX11_packet_requirev_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + channel->reqX11_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "waiting for x11-req response packet"); + } + + code = data[0]; + LIBSSH2_FREE(session, data); + channel->reqX11_state = libssh2_NB_state_idle; + + if (code == SSH_MSG_CHANNEL_SUCCESS) + return 0; + } + + return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, + "Unable to complete request for channel x11-req"); +} + +/* + * libssh2_channel_x11_req_ex + * Request X11 forwarding + */ +LIBSSH2_API int +libssh2_channel_x11_req_ex(LIBSSH2_CHANNEL *channel, int single_connection, + const char *auth_proto, const char *auth_cookie, + int screen_number) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, + channel_x11_req(channel, single_connection, auth_proto, + auth_cookie, screen_number)); + return rc; +} + + +/* + * _libssh2_channel_process_startup + * + * Primitive for libssh2_channel_(shell|exec|subsystem) + */ +int +_libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, + const char *request, size_t request_len, + const char *message, size_t message_len) +{ + LIBSSH2_SESSION *session = channel->session; + unsigned char *s; + static const unsigned char reply_codes[3] = + { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 }; + int rc; + + if (channel->process_state == libssh2_NB_state_idle) { + /* 10 = packet_type(1) + channel(4) + request_len(4) + want_reply(1) */ + channel->process_packet_len = request_len + 10; + + /* Zero the whole thing out */ + memset(&channel->process_packet_requirev_state, 0, + sizeof(channel->process_packet_requirev_state)); + + if (message) + channel->process_packet_len += + 4; + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "starting request(%s) on channel %lu/%lu, message=%s", + request, channel->local.id, channel->remote.id, + message?message:""); + s = channel->process_packet = + LIBSSH2_ALLOC(session, channel->process_packet_len); + if (!channel->process_packet) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory " + "for channel-process request"); + + *(s++) = SSH_MSG_CHANNEL_REQUEST; + _libssh2_store_u32(&s, channel->remote.id); + _libssh2_store_str(&s, request, request_len); + *(s++) = 0x01; + + if (message) + _libssh2_store_u32(&s, message_len); + + channel->process_state = libssh2_NB_state_created; + } + + if (channel->process_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, + channel->process_packet, + channel->process_packet_len, + (unsigned char *)message, message_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, rc, + "Would block sending channel request"); + return rc; + } + else if (rc) { + LIBSSH2_FREE(session, channel->process_packet); + channel->process_packet = NULL; + channel->process_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Unable to send channel request"); + } + LIBSSH2_FREE(session, channel->process_packet); + channel->process_packet = NULL; + + _libssh2_htonu32(channel->process_local_channel, channel->local.id); + + channel->process_state = libssh2_NB_state_sent; + } + + if (channel->process_state == libssh2_NB_state_sent) { + unsigned char *data; + size_t data_len; + unsigned char code; + rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len, + 1, channel->process_local_channel, 4, + &channel->process_packet_requirev_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + channel->process_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Failed waiting for channel success"); + } + + code = data[0]; + LIBSSH2_FREE(session, data); + channel->process_state = libssh2_NB_state_idle; + + if (code == SSH_MSG_CHANNEL_SUCCESS) + return 0; + } + + return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED, + "Unable to complete request for " + "channel-process-startup"); +} + +/* + * libssh2_channel_process_startup + * + * Primitive for libssh2_channel_(shell|exec|subsystem) + */ +LIBSSH2_API int +libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, + const char *req, unsigned int req_len, + const char *msg, unsigned int msg_len) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, + _libssh2_channel_process_startup(channel, req, req_len, + msg, msg_len)); + return rc; +} + + +/* + * libssh2_channel_set_blocking + * + * Set a channel's BEHAVIOR blocking on or off. The socket will remain non- + * blocking. + */ +LIBSSH2_API void +libssh2_channel_set_blocking(LIBSSH2_CHANNEL * channel, int blocking) +{ + if(channel) + (void) _libssh2_session_set_blocking(channel->session, blocking); +} + +/* + * _libssh2_channel_flush + * + * Flush data from one (or all) stream + * Returns number of bytes flushed, or negative on failure + */ +int +_libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid) +{ + if (channel->flush_state == libssh2_NB_state_idle) { + LIBSSH2_PACKET *packet = + _libssh2_list_first(&channel->session->packets); + channel->flush_refund_bytes = 0; + channel->flush_flush_bytes = 0; + + while (packet) { + LIBSSH2_PACKET *next = _libssh2_list_next(&packet->node); + unsigned char packet_type = packet->data[0]; + + if (((packet_type == SSH_MSG_CHANNEL_DATA) + || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)) + && (_libssh2_ntohu32(packet->data + 1) == channel->local.id)) { + /* It's our channel at least */ + long packet_stream_id = + (packet_type == SSH_MSG_CHANNEL_DATA) ? 0 : + _libssh2_ntohu32(packet->data + 5); + if ((streamid == LIBSSH2_CHANNEL_FLUSH_ALL) + || ((packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA) + && ((streamid == LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA) + || (streamid == packet_stream_id))) + || ((packet_type == SSH_MSG_CHANNEL_DATA) + && (streamid == 0))) { + int bytes_to_flush = packet->data_len - packet->data_head; + + _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, + "Flushing %d bytes of data from stream " + "%lu on channel %lu/%lu", + bytes_to_flush, packet_stream_id, + channel->local.id, channel->remote.id); + + /* It's one of the streams we wanted to flush */ + channel->flush_refund_bytes += packet->data_len - 13; + channel->flush_flush_bytes += bytes_to_flush; + + LIBSSH2_FREE(channel->session, packet->data); + + /* remove this packet from the parent's list */ + _libssh2_list_remove(&packet->node); + LIBSSH2_FREE(channel->session, packet); + } + } + packet = next; + } + + channel->flush_state = libssh2_NB_state_created; + } + + if (channel->flush_refund_bytes) { + int rc; + + rc = _libssh2_channel_receive_window_adjust(channel, + channel->flush_refund_bytes, + 1, NULL); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + } + + channel->flush_state = libssh2_NB_state_idle; + + return channel->flush_flush_bytes; +} + +/* + * libssh2_channel_flush_ex + * + * Flush data from one (or all) stream + * Returns number of bytes flushed, or negative on failure + */ +LIBSSH2_API int +libssh2_channel_flush_ex(LIBSSH2_CHANNEL *channel, int stream) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, + _libssh2_channel_flush(channel, stream)); + return rc; +} + +/* + * libssh2_channel_get_exit_status + * + * Return the channel's program exit status. Note that the actual protocol + * provides the full 32bit this function returns. We cannot abuse it to + * return error values in case of errors so we return a zero if channel is + * NULL. + */ +LIBSSH2_API int +libssh2_channel_get_exit_status(LIBSSH2_CHANNEL *channel) +{ + if(!channel) + return 0; + + return channel->exit_status; +} + +/* + * libssh2_channel_get_exit_signal + * + * Get exit signal (without leading "SIG"), error message, and language + * tag into newly allocated buffers of indicated length. Caller can + * use NULL pointers to indicate that the value should not be set. The + * *_len variables are set if they are non-NULL even if the + * corresponding string parameter is NULL. Returns LIBSSH2_ERROR_NONE + * on success, or an API error code. + */ +LIBSSH2_API int +libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL *channel, + char **exitsignal, + size_t *exitsignal_len, + char **errmsg, + size_t *errmsg_len, + char **langtag, + size_t *langtag_len) +{ + LIBSSH2_SESSION *session = channel->session; + size_t namelen = 0; + + if (channel) { + if (channel->exit_signal) { + namelen = strlen(channel->exit_signal); + if (exitsignal) { + *exitsignal = LIBSSH2_ALLOC(session, namelen + 1); + if (!*exitsignal) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for signal name"); + } + memcpy(*exitsignal, channel->exit_signal, namelen); + (*exitsignal)[namelen] = '\0'; + } + if (exitsignal_len) + *exitsignal_len = namelen; + } else { + if (exitsignal) + *exitsignal = NULL; + if (exitsignal_len) + *exitsignal_len = 0; + } + + /* TODO: set error message and language tag */ + + if (errmsg) + *errmsg = NULL; + + if (errmsg_len) + *errmsg_len = 0; + + if (langtag) + *langtag = NULL; + + if (langtag_len) + *langtag_len = 0; + } + + return LIBSSH2_ERROR_NONE; +} + +/* + * _libssh2_channel_receive_window_adjust + * + * Adjust the receive window for a channel by adjustment bytes. If the amount + * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the + * adjustment amount will be queued for a later packet. + * + * Calls _libssh2_error() ! + */ +int +_libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel, + uint32_t adjustment, + unsigned char force, + unsigned int *store) +{ + int rc; + + if (channel->adjust_state == libssh2_NB_state_idle) { + if (!force + && (adjustment + channel->adjust_queue < + LIBSSH2_CHANNEL_MINADJUST)) { + _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, + "Queueing %lu bytes for receive window adjustment " + "for channel %lu/%lu", + adjustment, channel->local.id, channel->remote.id); + channel->adjust_queue += adjustment; + if(store) + *store = channel->remote.window_size; + return 0; + } + + if (!adjustment && !channel->adjust_queue) { + if(store) + *store = channel->remote.window_size; + return 0; + } + + adjustment += channel->adjust_queue; + channel->adjust_queue = 0; + + /* Adjust the window based on the block we just freed */ + channel->adjust_adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST; + _libssh2_htonu32(&channel->adjust_adjust[1], channel->remote.id); + _libssh2_htonu32(&channel->adjust_adjust[5], adjustment); + _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, + "Adjusting window %lu bytes for data on " + "channel %lu/%lu", + adjustment, channel->local.id, channel->remote.id); + + channel->adjust_state = libssh2_NB_state_created; + } + + rc = _libssh2_transport_send(channel->session, channel->adjust_adjust, 9, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(channel->session, rc, + "Would block sending window adjust"); + return rc; + } + else if (rc) { + channel->adjust_queue = adjustment; + return _libssh2_error(channel->session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send transfer-window adjustment " + "packet, deferring"); + } + else { + channel->remote.window_size += adjustment; + } + + channel->adjust_state = libssh2_NB_state_idle; + + if(store) + *store = channel->remote.window_size; + return 0; +} + +/* + * libssh2_channel_receive_window_adjust + * + * DEPRECATED + * + * Adjust the receive window for a channel by adjustment bytes. If the amount + * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the + * adjustment amount will be queued for a later packet. + * + * Returns the new size of the receive window (as understood by remote end). + * Note that it might return EAGAIN too which is highly stupid. + * + */ +LIBSSH2_API unsigned long +libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel, + unsigned long adj, + unsigned char force) +{ + unsigned int window; + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, + _libssh2_channel_receive_window_adjust(channel, adj, + force, &window)); + + /* stupid - but this is how it was made to work before and this is just + kept for backwards compatibility */ + return rc?(unsigned long)rc:window; +} + +/* + * libssh2_channel_receive_window_adjust2 + * + * Adjust the receive window for a channel by adjustment bytes. If the amount + * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the + * adjustment amount will be queued for a later packet. + * + * Stores the new size of the receive window in the data 'window' points to. + * + * Returns the "normal" error code: 0 for success, negative for failure. + */ +LIBSSH2_API int +libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL *channel, + unsigned long adj, + unsigned char force, + unsigned int *window) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, + _libssh2_channel_receive_window_adjust(channel, adj, force, + window)); + return rc; +} + +int +_libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode) +{ + if (channel->extData2_state == libssh2_NB_state_idle) { + _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, + "Setting channel %lu/%lu handle_extended_data" + " mode to %d", + channel->local.id, channel->remote.id, ignore_mode); + channel->remote.extended_data_ignore_mode = ignore_mode; + + channel->extData2_state = libssh2_NB_state_created; + } + + if (channel->extData2_state == libssh2_NB_state_idle) { + if (ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) { + int rc = + _libssh2_channel_flush(channel, + LIBSSH2_CHANNEL_FLUSH_EXTENDED_DATA); + if(LIBSSH2_ERROR_EAGAIN == rc) + return rc; + } + } + + channel->extData2_state = libssh2_NB_state_idle; + return 0; +} + +/* + * libssh2_channel_handle_extended_data2() + * + */ +LIBSSH2_API int +libssh2_channel_handle_extended_data2(LIBSSH2_CHANNEL *channel, + int mode) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, _libssh2_channel_extended_data(channel, + mode)); + return rc; +} + +/* + * libssh2_channel_handle_extended_data + * + * DEPRECATED DO NOTE USE! + * + * How should extended data look to the calling app? Keep it in separate + * channels[_read() _read_stdder()]? (NORMAL) Merge the extended data to the + * standard data? [everything via _read()]? (MERGE) Ignore it entirely [toss + * out packets as they come in]? (IGNORE) + */ +LIBSSH2_API void +libssh2_channel_handle_extended_data(LIBSSH2_CHANNEL *channel, + int ignore_mode) +{ + (void)libssh2_channel_handle_extended_data2(channel, ignore_mode); +} + + + +/* + * _libssh2_channel_read + * + * Read data from a channel + * + * It is important to not return 0 until the currently read channel is + * complete. If we read stuff from the wire but it was no payload data to fill + * in the buffer with, we MUST make sure to return LIBSSH2_ERROR_EAGAIN. + * + * The receive window must be maintained (enlarged) by the user of this + * function. + */ +ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, + char *buf, size_t buflen) +{ + LIBSSH2_SESSION *session = channel->session; + int rc; + int bytes_read = 0; + int bytes_want; + int unlink_packet; + LIBSSH2_PACKET *read_packet; + LIBSSH2_PACKET *read_next; + + if (channel->read_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "channel_read() wants %d bytes from channel %lu/%lu " + "stream #%d", + (int) buflen, channel->local.id, channel->remote.id, + stream_id); + channel->read_state = libssh2_NB_state_created; + } + + rc = 1; /* set to >0 to let the while loop start */ + + /* Process all pending incoming packets in all states in order to "even + out" the network readings. Tests prove that this way produces faster + transfers. */ + while (rc > 0) + rc = _libssh2_transport_read(session); + + if ((rc < 0) && (rc != LIBSSH2_ERROR_EAGAIN)) + return _libssh2_error(session, rc, "transport read"); + + read_packet = _libssh2_list_first(&session->packets); + while (read_packet && (bytes_read < (int) buflen)) { + /* previously this loop condition also checked for + !channel->remote.close but we cannot let it do this: + + We may have a series of packets to read that are still pending even + if a close has been received. Acknowledging the close too early + makes us flush buffers prematurely and loose data. + */ + + LIBSSH2_PACKET *readpkt = read_packet; + + /* In case packet gets destroyed during this iteration */ + read_next = _libssh2_list_next(&readpkt->node); + + channel->read_local_id = + _libssh2_ntohu32(readpkt->data + 1); + + /* + * Either we asked for a specific extended data stream + * (and data was available), + * or the standard stream (and data was available), + * or the standard stream with extended_data_merge + * enabled and data was available + */ + if ((stream_id + && (readpkt->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) + && (channel->local.id == channel->read_local_id) + && (stream_id == (int) _libssh2_ntohu32(readpkt->data + 5))) + || (!stream_id && (readpkt->data[0] == SSH_MSG_CHANNEL_DATA) + && (channel->local.id == channel->read_local_id)) + || (!stream_id + && (readpkt->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) + && (channel->local.id == channel->read_local_id) + && (channel->remote.extended_data_ignore_mode == + LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) { + + /* figure out much more data we want to read */ + bytes_want = buflen - bytes_read; + unlink_packet = FALSE; + + if (bytes_want >= (int) (readpkt->data_len - readpkt->data_head)) { + /* we want more than this node keeps, so adjust the number and + delete this node after the copy */ + bytes_want = readpkt->data_len - readpkt->data_head; + unlink_packet = TRUE; + } + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "channel_read() got %d of data from %lu/%lu/%d%s", + bytes_want, channel->local.id, + channel->remote.id, stream_id, + unlink_packet?" [ul]":""); + + /* copy data from this struct to the target buffer */ + memcpy(&buf[bytes_read], + &readpkt->data[readpkt->data_head], bytes_want); + + /* advance pointer and counter */ + readpkt->data_head += bytes_want; + bytes_read += bytes_want; + + /* if drained, remove from list */ + if (unlink_packet) { + /* detach readpkt from session->packets list */ + _libssh2_list_remove(&readpkt->node); + + LIBSSH2_FREE(session, readpkt->data); + LIBSSH2_FREE(session, readpkt); + } + } + + /* check the next struct in the chain */ + read_packet = read_next; + } + + if (!bytes_read) { + channel->read_state = libssh2_NB_state_idle; + + /* If the channel is already at EOF or even closed, we need to signal + that back. We may have gotten that info while draining the incoming + transport layer until EAGAIN so we must not be fooled by that + return code. */ + if(channel->remote.eof || channel->remote.close) + return 0; + else if(rc != LIBSSH2_ERROR_EAGAIN) + return 0; + + /* if the transport layer said EAGAIN then we say so as well */ + return _libssh2_error(session, rc, "would block"); + } + else + /* make sure we remain in the created state to focus on emptying the + data we already have in the packet brigade before we try to read + more off the network again */ + channel->read_state = libssh2_NB_state_created; + + return bytes_read; +} + +/* + * libssh2_channel_read_ex + * + * Read data from a channel (blocking or non-blocking depending on set state) + * + * When this is done non-blocking, it is important to not return 0 until the + * currently read channel is complete. If we read stuff from the wire but it + * was no payload data to fill in the buffer with, we MUST make sure to return + * LIBSSH2_ERROR_EAGAIN. + * + * This function will first make sure there's a receive window enough to + * receive a full buffer's wort of contents. An application may choose to + * adjust the receive window more to increase transfer performance. + */ +LIBSSH2_API ssize_t +libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf, + size_t buflen) +{ + int rc; + unsigned long recv_window; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + recv_window = libssh2_channel_window_read_ex(channel, NULL, NULL); + + if(buflen > recv_window) { + BLOCK_ADJUST(rc, channel->session, + _libssh2_channel_receive_window_adjust(channel, buflen, + 1, NULL)); + } + + BLOCK_ADJUST(rc, channel->session, + _libssh2_channel_read(channel, stream_id, buf, buflen)); + return rc; +} + +/* + * _libssh2_channel_packet_data_len + * + * Return the size of the data block of the current packet, or 0 if there + * isn't a packet. + */ +size_t +_libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id) +{ + LIBSSH2_SESSION *session = channel->session; + LIBSSH2_PACKET *read_packet; + uint32_t read_local_id; + + read_packet = _libssh2_list_first(&session->packets); + if (read_packet == NULL) + return 0; + + while (read_packet) { + read_local_id = _libssh2_ntohu32(read_packet->data + 1); + + /* + * Either we asked for a specific extended data stream + * (and data was available), + * or the standard stream (and data was available), + * or the standard stream with extended_data_merge + * enabled and data was available + */ + if ((stream_id + && (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) + && (channel->local.id == read_local_id) + && (stream_id == (int) _libssh2_ntohu32(read_packet->data + 5))) + || + (!stream_id + && (read_packet->data[0] == SSH_MSG_CHANNEL_DATA) + && (channel->local.id == read_local_id)) + || + (!stream_id + && (read_packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) + && (channel->local.id == read_local_id) + && (channel->remote.extended_data_ignore_mode + == LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) + { + return (read_packet->data_len - read_packet->data_head); + } + read_packet = _libssh2_list_next(&read_packet->node); + } + + return 0; +} + +/* + * _libssh2_channel_write + * + * Send data to a channel. Note that if this returns EAGAIN, the caller must + * call this function again with the SAME input arguments. + * + * Returns: number of bytes sent, or if it returns a negative number, that is + * the error code! + */ +ssize_t +_libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, + const unsigned char *buf, size_t buflen) +{ + int rc = 0; + LIBSSH2_SESSION *session = channel->session; + ssize_t wrote = 0; /* counter for this specific this call */ + + /* In theory we could split larger buffers into several smaller packets + * but it turns out to be really hard and nasty to do while still offering + * the API/prototype. + * + * Instead we only deal with the first 32K in this call and for the parent + * function to call it again with the remainder! 32K is a conservative + * limit based on the text in RFC4253 section 6.1. + */ + if(buflen > 32700) + buflen = 32700; + + if (channel->write_state == libssh2_NB_state_idle) { + unsigned char *s = channel->write_packet; + + _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN, + "Writing %d bytes on channel %lu/%lu, stream #%d", + (int) buflen, channel->local.id, channel->remote.id, + stream_id); + + if (channel->local.close) + return _libssh2_error(channel->session, + LIBSSH2_ERROR_CHANNEL_CLOSED, + "We've already closed this channel"); + else if (channel->local.eof) + return _libssh2_error(channel->session, + LIBSSH2_ERROR_CHANNEL_EOF_SENT, + "EOF has already been received, " + "data might be ignored"); + + /* drain the incoming flow first, mostly to make sure we get all + * pending window adjust packets */ + do + rc = _libssh2_transport_read(session); + while (rc > 0); + + if((rc < 0) && (rc != LIBSSH2_ERROR_EAGAIN)) + return rc; + + if(channel->local.window_size <= 0) + /* there's no room for data so we stop */ + return (rc==LIBSSH2_ERROR_EAGAIN?rc:0); + + channel->write_bufwrite = buflen; + + *(s++) = stream_id ? SSH_MSG_CHANNEL_EXTENDED_DATA : + SSH_MSG_CHANNEL_DATA; + _libssh2_store_u32(&s, channel->remote.id); + if (stream_id) + _libssh2_store_u32(&s, stream_id); + + /* Don't exceed the remote end's limits */ + /* REMEMBER local means local as the SOURCE of the data */ + if (channel->write_bufwrite > channel->local.window_size) { + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Splitting write block due to %lu byte " + "window_size on %lu/%lu/%d", + channel->local.window_size, channel->local.id, + channel->remote.id, stream_id); + channel->write_bufwrite = channel->local.window_size; + } + if (channel->write_bufwrite > channel->local.packet_size) { + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Splitting write block due to %lu byte " + "packet_size on %lu/%lu/%d", + channel->local.packet_size, channel->local.id, + channel->remote.id, stream_id); + channel->write_bufwrite = channel->local.packet_size; + } + /* store the size here only, the buffer is passed in as-is to + _libssh2_transport_send() */ + _libssh2_store_u32(&s, channel->write_bufwrite); + channel->write_packet_len = s - channel->write_packet; + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Sending %d bytes on channel %lu/%lu, stream_id=%d", + (int) channel->write_bufwrite, channel->local.id, + channel->remote.id, stream_id); + + channel->write_state = libssh2_NB_state_created; + } + + if (channel->write_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, channel->write_packet, + channel->write_packet_len, + buf, channel->write_bufwrite); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return _libssh2_error(session, rc, + "Unable to send channel data"); + } + else if (rc) { + channel->write_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Unable to send channel data"); + } + /* Shrink local window size */ + channel->local.window_size -= channel->write_bufwrite; + + wrote += channel->write_bufwrite; + + /* Since _libssh2_transport_write() succeeded, we must return + now to allow the caller to provide the next chunk of data. + + We cannot move on to send the next piece of data that may + already have been provided in this same function call, as we + risk getting EAGAIN for that and we can't return information + both about sent data as well as EAGAIN. So, by returning short + now, the caller will call this function again with new data to + send */ + + channel->write_state = libssh2_NB_state_idle; + + return wrote; + } + + return LIBSSH2_ERROR_INVAL; /* reaching this point is really bad */ +} + +/* + * libssh2_channel_write_ex + * + * Send data to a channel + */ +LIBSSH2_API ssize_t +libssh2_channel_write_ex(LIBSSH2_CHANNEL *channel, int stream_id, + const char *buf, size_t buflen) +{ + ssize_t rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, + _libssh2_channel_write(channel, stream_id, + (unsigned char *)buf, buflen)); + return rc; +} + +/* + * channel_send_eof + * + * Send EOF on channel + */ +static int channel_send_eof(LIBSSH2_CHANNEL *channel) +{ + LIBSSH2_SESSION *session = channel->session; + unsigned char packet[5]; /* packet_type(1) + channelno(4) */ + int rc; + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Sending EOF on channel %lu/%lu", + channel->local.id, channel->remote.id); + packet[0] = SSH_MSG_CHANNEL_EOF; + _libssh2_htonu32(packet + 1, channel->remote.id); + rc = _libssh2_transport_send(session, packet, 5, NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, rc, + "Would block sending EOF"); + return rc; + } + else if (rc) { + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send EOF on channel"); + } + channel->local.eof = 1; + + return 0; +} + +/* + * libssh2_channel_send_eof + * + * Send EOF on channel + */ +LIBSSH2_API int +libssh2_channel_send_eof(LIBSSH2_CHANNEL *channel) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, channel_send_eof(channel)); + return rc; +} + +/* + * libssh2_channel_eof + * + * Read channel's eof status + */ +LIBSSH2_API int +libssh2_channel_eof(LIBSSH2_CHANNEL * channel) +{ + LIBSSH2_SESSION *session; + LIBSSH2_PACKET *packet; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + session = channel->session; + packet = _libssh2_list_first(&session->packets); + + while (packet) { + if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) + || (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) + && (channel->local.id == _libssh2_ntohu32(packet->data + 1))) { + /* There's data waiting to be read yet, mask the EOF status */ + return 0; + } + packet = _libssh2_list_next(&packet->node); + } + + return channel->remote.eof; +} + +/* + * channel_wait_eof + * + * Awaiting channel EOF + */ +static int channel_wait_eof(LIBSSH2_CHANNEL *channel) +{ + LIBSSH2_SESSION *session = channel->session; + int rc; + + if (channel->wait_eof_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Awaiting close of channel %lu/%lu", channel->local.id, + channel->remote.id); + + channel->wait_eof_state = libssh2_NB_state_created; + } + + /* + * While channel is not eof, read more packets from the network. + * Either the EOF will be set or network timeout will occur. + */ + do { + if (channel->remote.eof) { + break; + } + rc = _libssh2_transport_read(session); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + else if (rc < 0) { + channel->wait_eof_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "_libssh2_transport_read() bailed out!"); + } + } while (1); + + channel->wait_eof_state = libssh2_NB_state_idle; + + return 0; +} + +/* + * libssh2_channel_wait_eof + * + * Awaiting channel EOF + */ +LIBSSH2_API int +libssh2_channel_wait_eof(LIBSSH2_CHANNEL *channel) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, channel_wait_eof(channel)); + return rc; +} + +int _libssh2_channel_close(LIBSSH2_CHANNEL * channel) +{ + LIBSSH2_SESSION *session = channel->session; + int rc = 0; + int retcode; + + if (channel->local.close) { + /* Already closed, act like we sent another close, + * even though we didn't... shhhhhh */ + channel->close_state = libssh2_NB_state_idle; + return 0; + } + + if (!channel->local.eof) + if ((retcode = channel_send_eof(channel))) + return retcode; + + /* ignore if we have received a remote eof or not, as it is now too + late for us to wait for it. Continue closing! */ + + if (channel->close_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Closing channel %lu/%lu", + channel->local.id, channel->remote.id); + + channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE; + _libssh2_htonu32(channel->close_packet + 1, channel->remote.id); + + channel->close_state = libssh2_NB_state_created; + } + + if (channel->close_state == libssh2_NB_state_created) { + retcode = _libssh2_transport_send(session, channel->close_packet, 5, + NULL, 0); + if (retcode == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, rc, + "Would block sending close-channel"); + return retcode; + } else if (retcode) { + channel->close_state = libssh2_NB_state_idle; + return _libssh2_error(session, retcode, + "Unable to send close-channel request"); + } + + channel->close_state = libssh2_NB_state_sent; + } + + if (channel->close_state == libssh2_NB_state_sent) { + /* We must wait for the remote SSH_MSG_CHANNEL_CLOSE message */ + + while (!channel->remote.close && !rc && + (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED)) + rc = _libssh2_transport_read(session); + } + + if(rc != LIBSSH2_ERROR_EAGAIN) { + /* set the local close state first when we're perfectly confirmed to not + do any more EAGAINs */ + channel->local.close = 1; + + /* We call the callback last in this function to make it keep the local + data as long as EAGAIN is returned. */ + if (channel->close_cb) { + LIBSSH2_CHANNEL_CLOSE(session, channel); + } + + channel->close_state = libssh2_NB_state_idle; + } + + /* return 0 or an error */ + return rc>=0?0:rc; +} + +/* + * libssh2_channel_close + * + * Close a channel + */ +LIBSSH2_API int +libssh2_channel_close(LIBSSH2_CHANNEL *channel) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, _libssh2_channel_close(channel) ); + return rc; +} + +/* + * channel_wait_closed + * + * Awaiting channel close after EOF + */ +static int channel_wait_closed(LIBSSH2_CHANNEL *channel) +{ + LIBSSH2_SESSION *session = channel->session; + int rc; + + if (!libssh2_channel_eof(channel)) { + return _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "libssh2_channel_wait_closed() invoked when " + "channel is not in EOF state"); + } + + if (channel->wait_closed_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Awaiting close of channel %lu/%lu", channel->local.id, + channel->remote.id); + + channel->wait_closed_state = libssh2_NB_state_created; + } + + /* + * While channel is not closed, read more packets from the network. + * Either the channel will be closed or network timeout will occur. + */ + if (!channel->remote.close) { + do { + rc = _libssh2_transport_read(session); + if (channel->remote.close) + /* it is now closed, move on! */ + break; + } while (rc > 0); + if(rc < 0) + return rc; + } + + channel->wait_closed_state = libssh2_NB_state_idle; + + return 0; +} + +/* + * libssh2_channel_wait_closed + * + * Awaiting channel close after EOF + */ +LIBSSH2_API int +libssh2_channel_wait_closed(LIBSSH2_CHANNEL *channel) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, channel_wait_closed(channel)); + return rc; +} + +/* + * _libssh2_channel_free + * + * Make sure a channel is closed, then remove the channel from the session + * and free its resource(s) + * + * Returns 0 on success, negative on failure + */ +int _libssh2_channel_free(LIBSSH2_CHANNEL *channel) +{ + LIBSSH2_SESSION *session = channel->session; + unsigned char channel_id[4]; + unsigned char *data; + size_t data_len; + int rc; + + assert(session); + + if (channel->free_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Freeing channel %lu/%lu resources", channel->local.id, + channel->remote.id); + + channel->free_state = libssh2_NB_state_created; + } + + /* Allow channel freeing even when the socket has lost its connection */ + if (!channel->local.close + && (session->socket_state == LIBSSH2_SOCKET_CONNECTED)) { + rc = _libssh2_channel_close(channel); + + if(rc == LIBSSH2_ERROR_EAGAIN) + return rc; + + /* ignore all other errors as they otherwise risk blocking the channel + free from happening */ + } + + channel->free_state = libssh2_NB_state_idle; + + if (channel->exit_signal) { + LIBSSH2_FREE(session, channel->exit_signal); + } + + /* + * channel->remote.close *might* not be set yet, Well... + * We've sent the close packet, what more do you want? + * Just let packet_add ignore it when it finally arrives + */ + + /* Clear out packets meant for this channel */ + _libssh2_htonu32(channel_id, channel->local.id); + while ((_libssh2_packet_ask(session, SSH_MSG_CHANNEL_DATA, &data, + &data_len, 1, channel_id, 4) >= 0) + || + (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data, + &data_len, 1, channel_id, 4) >= 0)) { + LIBSSH2_FREE(session, data); + } + + /* free "channel_type" */ + if (channel->channel_type) { + LIBSSH2_FREE(session, channel->channel_type); + } + + /* Unlink from channel list */ + _libssh2_list_remove(&channel->node); + + /* + * Make sure all memory used in the state variables are free + */ + if (channel->setenv_packet) { + LIBSSH2_FREE(session, channel->setenv_packet); + } + if (channel->reqX11_packet) { + LIBSSH2_FREE(session, channel->reqX11_packet); + } + if (channel->process_packet) { + LIBSSH2_FREE(session, channel->process_packet); + } + + LIBSSH2_FREE(session, channel); + + return 0; +} + +/* + * libssh2_channel_free + * + * Make sure a channel is closed, then remove the channel from the session + * and free its resource(s) + * + * Returns 0 on success, negative on failure + */ +LIBSSH2_API int +libssh2_channel_free(LIBSSH2_CHANNEL *channel) +{ + int rc; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, channel->session, _libssh2_channel_free(channel)); + return rc; +} +/* + * libssh2_channel_window_read_ex + * + * Check the status of the read window. Returns the number of bytes which the + * remote end may send without overflowing the window limit read_avail (if + * passed) will be populated with the number of bytes actually available to be + * read window_size_initial (if passed) will be populated with the + * window_size_initial as defined by the channel_open request + */ +LIBSSH2_API unsigned long +libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel, + unsigned long *read_avail, + unsigned long *window_size_initial) +{ + if(!channel) + return 0; /* no channel, no window! */ + + if (window_size_initial) { + *window_size_initial = channel->remote.window_size_initial; + } + + if (read_avail) { + size_t bytes_queued = 0; + LIBSSH2_PACKET *packet = + _libssh2_list_first(&channel->session->packets); + + while (packet) { + unsigned char packet_type = packet->data[0]; + + if (((packet_type == SSH_MSG_CHANNEL_DATA) + || (packet_type == SSH_MSG_CHANNEL_EXTENDED_DATA)) + && (_libssh2_ntohu32(packet->data + 1) == channel->local.id)) { + bytes_queued += packet->data_len - packet->data_head; + } + + packet = _libssh2_list_next(&packet->node); + } + + *read_avail = bytes_queued; + } + + return channel->remote.window_size; +} + +/* + * libssh2_channel_window_write_ex + * + * Check the status of the write window Returns the number of bytes which may + * be safely writen on the channel without blocking window_size_initial (if + * passed) will be populated with the size of the initial window as defined by + * the channel_open request + */ +LIBSSH2_API unsigned long +libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel, + unsigned long *window_size_initial) +{ + if(!channel) + return 0; /* no channel, no window! */ + + if (window_size_initial) { + /* For locally initiated channels this is very often 0, so it's not + * *that* useful as information goes */ + *window_size_initial = channel->local.window_size_initial; + } + + return channel->local.window_size; +} diff --git a/vendor/libssh2-1.4.2/src/channel.h b/vendor/libssh2-1.4.2/src/channel.h new file mode 100644 index 0000000..dc0ee37 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/channel.h @@ -0,0 +1,141 @@ +#ifndef __LIBSSH2_CHANNEL_H +#define __LIBSSH2_CHANNEL_H +/* Copyright (c) 2008-2010 by Daniel Stenberg + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +/* + * _libssh2_channel_receive_window_adjust + * + * Adjust the receive window for a channel by adjustment bytes. If the amount + * to be adjusted is less than LIBSSH2_CHANNEL_MINADJUST and force is 0 the + * adjustment amount will be queued for a later packet. + * + * Always non-blocking. + */ +int _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel, + uint32_t adjustment, + unsigned char force, + unsigned int *store); + +/* + * _libssh2_channel_flush + * + * Flush data from one (or all) stream + * Returns number of bytes flushed, or negative on failure + */ +int _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid); + +/* + * _libssh2_channel_free + * + * Make sure a channel is closed, then remove the channel from the session + * and free its resource(s) + * + * Returns 0 on success, negative on failure + */ +int _libssh2_channel_free(LIBSSH2_CHANNEL *channel); + +int +_libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode); + +/* + * _libssh2_channel_write + * + * Send data to a channel + */ +ssize_t +_libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, + const unsigned char *buf, size_t buflen); + +/* + * _libssh2_channel_open + * + * Establish a generic session channel + */ +LIBSSH2_CHANNEL * +_libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type, + uint32_t channel_type_len, + uint32_t window_size, + uint32_t packet_size, + const unsigned char *message, size_t message_len); + + +/* + * _libssh2_channel_process_startup + * + * Primitive for libssh2_channel_(shell|exec|subsystem) + */ +int +_libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, + const char *request, size_t request_len, + const char *message, size_t message_len); + +/* + * _libssh2_channel_read + * + * Read data from a channel + * + * It is important to not return 0 until the currently read channel is + * complete. If we read stuff from the wire but it was no payload data to fill + * in the buffer with, we MUST make sure to return PACKET_EAGAIN. + */ +ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, + char *buf, size_t buflen); + +uint32_t _libssh2_channel_nextid(LIBSSH2_SESSION * session); + +LIBSSH2_CHANNEL *_libssh2_channel_locate(LIBSSH2_SESSION * session, + uint32_t channel_id); + +size_t _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, + int stream_id); + +int _libssh2_channel_close(LIBSSH2_CHANNEL * channel); + +/* + * _libssh2_channel_forward_cancel + * + * Stop listening on a remote port and free the listener + * Toss out any pending (un-accept()ed) connections + * + * Return 0 on success, LIBSSH2_ERROR_EAGAIN if would block, -1 on error + */ +int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener); + +#endif /* __LIBSSH2_CHANNEL_H */ + diff --git a/vendor/libssh2-1.4.2/src/comp.c b/vendor/libssh2-1.4.2/src/comp.c new file mode 100644 index 0000000..0296f62 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/comp.c @@ -0,0 +1,390 @@ +/* Copyright (c) 2004-2007, Sara Golemon + * Copyright (c) 2010, Daniel Stenberg + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" +#ifdef LIBSSH2_HAVE_ZLIB +# include +#endif + +#include "comp.h" + +/* ******** + * none * + ******** */ + +/* + * comp_method_none_comp + * + * Minimalist compression: Absolutely none + */ +static int +comp_method_none_comp(LIBSSH2_SESSION *session, + unsigned char *dest, + size_t *dest_len, + const unsigned char *src, + size_t src_len, + void **abstract) +{ + (void) session; + (void) abstract; + (void) dest; + (void) dest_len; + (void) src; + (void) src_len; + + return 0; +} + +/* + * comp_method_none_decomp + * + * Minimalist decompression: Absolutely none + */ +static int +comp_method_none_decomp(LIBSSH2_SESSION * session, + unsigned char **dest, + size_t *dest_len, + size_t payload_limit, + const unsigned char *src, + size_t src_len, void **abstract) +{ + (void) session; + (void) payload_limit; + (void) abstract; + *dest = (unsigned char *) src; + *dest_len = src_len; + return 0; +} + + + +static const LIBSSH2_COMP_METHOD comp_method_none = { + "none", + 0, /* not really compressing */ + NULL, + comp_method_none_comp, + comp_method_none_decomp, + NULL +}; + +#ifdef LIBSSH2_HAVE_ZLIB +/* ******** + * zlib * + ******** */ + +/* Memory management wrappers + * Yes, I realize we're doing a callback to a callback, + * Deal... + */ + +static voidpf +comp_method_zlib_alloc(voidpf opaque, uInt items, uInt size) +{ + LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque; + + return (voidpf) LIBSSH2_ALLOC(session, items * size); +} + +static void +comp_method_zlib_free(voidpf opaque, voidpf address) +{ + LIBSSH2_SESSION *session = (LIBSSH2_SESSION *) opaque; + + LIBSSH2_FREE(session, address); +} + + + +/* libssh2_comp_method_zlib_init + * All your bandwidth are belong to us (so save some) + */ +static int +comp_method_zlib_init(LIBSSH2_SESSION * session, int compr, + void **abstract) +{ + z_stream *strm; + int status; + + strm = LIBSSH2_ALLOC(session, sizeof(z_stream)); + if (!strm) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "zlib compression/decompression"); + } + memset(strm, 0, sizeof(z_stream)); + + strm->opaque = (voidpf) session; + strm->zalloc = (alloc_func) comp_method_zlib_alloc; + strm->zfree = (free_func) comp_method_zlib_free; + if (compr) { + /* deflate */ + status = deflateInit(strm, Z_DEFAULT_COMPRESSION); + } else { + /* inflate */ + status = inflateInit(strm); + } + + if (status != Z_OK) { + LIBSSH2_FREE(session, strm); + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "unhandled zlib error %d", status); + return LIBSSH2_ERROR_COMPRESS; + } + *abstract = strm; + + return LIBSSH2_ERROR_NONE; +} + +/* + * libssh2_comp_method_zlib_comp + * + * Compresses source to destination. Without allocation. + */ +static int +comp_method_zlib_comp(LIBSSH2_SESSION *session, + unsigned char *dest, + + /* dest_len is a pointer to allow this function to + update it with the final actual size used */ + size_t *dest_len, + const unsigned char *src, + size_t src_len, + void **abstract) +{ + z_stream *strm = *abstract; + int out_maxlen = *dest_len; + int status; + + strm->next_in = (unsigned char *) src; + strm->avail_in = src_len; + strm->next_out = dest; + strm->avail_out = out_maxlen; + + status = deflate(strm, Z_PARTIAL_FLUSH); + + if (status != Z_OK) { + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "unhandled zlib compression error %d", status); + return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, + "compression failure"); + } + + *dest_len = out_maxlen - strm->avail_out; + return 0; +} + +/* + * libssh2_comp_method_zlib_decomp + * + * Decompresses source to destination. Allocates the output memory. + */ +static int +comp_method_zlib_decomp(LIBSSH2_SESSION * session, + unsigned char **dest, + size_t *dest_len, + size_t payload_limit, + const unsigned char *src, + size_t src_len, void **abstract) +{ + z_stream *strm = *abstract; + /* A short-term alloc of a full data chunk is better than a series of + reallocs */ + char *out; + int out_maxlen = 8 * src_len; + int limiter = 0; + + /* If strm is null, then we have not yet been initialized. */ + if (strm == NULL) + return _libssh2_error(session, LIBSSH2_ERROR_COMPRESS, + "decompression unitilized");; + + /* In practice they never come smaller than this */ + if (out_maxlen < 25) + out_maxlen = 25; + + if (out_maxlen > (int) payload_limit) + out_maxlen = payload_limit; + + strm->next_in = (unsigned char *) src; + strm->avail_in = src_len; + strm->next_out = (unsigned char *) LIBSSH2_ALLOC(session, out_maxlen); + out = (char *) strm->next_out; + strm->avail_out = out_maxlen; + if (!strm->next_out) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate decompression buffer"); + while (strm->avail_in) { + int status; + + status = inflate(strm, Z_PARTIAL_FLUSH); + + if (status != Z_OK) { + LIBSSH2_FREE(session, out); + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "unhandled zlib error %d", status); + return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, + "decompression failure"); + } + if (strm->avail_in) { + size_t out_ofs = out_maxlen - strm->avail_out; + char *newout; + + out_maxlen += 8 * strm->avail_in; + + if ((out_maxlen > (int) payload_limit) && limiter++) { + LIBSSH2_FREE(session, out); + return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, + "Excessive growth in decompression phase"); + } + + newout = LIBSSH2_REALLOC(session, out, out_maxlen); + if (!newout) { + LIBSSH2_FREE(session, out); + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to expand decompression buffer"); + } + out = newout; + strm->next_out = (unsigned char *) out + out_ofs; + strm->avail_out += 8 * strm->avail_in; + } else + while (!strm->avail_out) { + /* Done with input, might be a byte or two in internal buffer + * during compress. Or potentially many bytes if it's a + * decompress + */ + int grow_size = 2048; + char *newout; + + if (out_maxlen >= (int) payload_limit) { + LIBSSH2_FREE(session, out); + return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, + "Excessive growth in decompression " + "phase"); + } + + if (grow_size > (int) (payload_limit - out_maxlen)) { + grow_size = payload_limit - out_maxlen; + } + + out_maxlen += grow_size; + strm->avail_out = grow_size; + + newout = LIBSSH2_REALLOC(session, out, out_maxlen); + if (!newout) { + LIBSSH2_FREE(session, out); + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to expand final " + "decompress buffer"); + } + out = newout; + strm->next_out = (unsigned char *) out + out_maxlen - + grow_size; + + status = inflate(strm, Z_PARTIAL_FLUSH); + + if (status != Z_OK) { + LIBSSH2_FREE(session, out); + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "unhandled zlib error %d", status); + return _libssh2_error(session, LIBSSH2_ERROR_ZLIB, + "decompression failure"); + } + } + } + + *dest = (unsigned char *) out; + *dest_len = out_maxlen - strm->avail_out; + + return 0; +} + + +/* libssh2_comp_method_zlib_dtor + * All done, no more compression for you + */ +static int +comp_method_zlib_dtor(LIBSSH2_SESSION *session, int compr, void **abstract) +{ + z_stream *strm = *abstract; + + if (strm) { + if (compr) + deflateEnd(strm); + else + inflateEnd(strm); + LIBSSH2_FREE(session, strm); + } + + *abstract = NULL; + return 0; +} + +static const LIBSSH2_COMP_METHOD comp_method_zlib = { + "zlib", + 1, /* yes, this compresses */ + comp_method_zlib_init, + comp_method_zlib_comp, + comp_method_zlib_decomp, + comp_method_zlib_dtor, +}; +#endif /* LIBSSH2_HAVE_ZLIB */ + +/* If compression is enabled by the API, then this array is used which then + may allow compression if zlib is available at build time */ +static const LIBSSH2_COMP_METHOD *comp_methods[] = { +#ifdef LIBSSH2_HAVE_ZLIB + &comp_method_zlib, +#endif /* LIBSSH2_HAVE_ZLIB */ + &comp_method_none, + NULL +}; + +/* If compression is disabled by the API, then this array is used */ +static const LIBSSH2_COMP_METHOD *no_comp_methods[] = { + &comp_method_none, + NULL +}; + +const LIBSSH2_COMP_METHOD ** +_libssh2_comp_methods(LIBSSH2_SESSION *session) +{ + if(session->flag.compress) + return comp_methods; + else + return no_comp_methods; +} diff --git a/vendor/libssh2-1.4.2/src/comp.h b/vendor/libssh2-1.4.2/src/comp.h new file mode 100644 index 0000000..8edc150 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/comp.h @@ -0,0 +1,45 @@ +#ifndef __LIBSSH2_COMP_H +#define __LIBSSH2_COMP_H + +/* Copyright (C) 2009-2010 by Daniel Stenberg + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +#include "libssh2_priv.h" + +const LIBSSH2_COMP_METHOD **_libssh2_comp_methods(LIBSSH2_SESSION *session); + +#endif /* __LIBSSH2_COMP_H */ diff --git a/vendor/libssh2-1.4.2/src/crypt.c b/vendor/libssh2-1.4.2/src/crypt.c new file mode 100644 index 0000000..93d99c4 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/crypt.c @@ -0,0 +1,334 @@ +/* Copyright (c) 2009, 2010 Simon Josefsson + * Copyright (c) 2004-2007, Sara Golemon + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" + +#ifdef LIBSSH2_CRYPT_NONE + +/* crypt_none_crypt + * Minimalist cipher: VERY secure *wink* + */ +static int +crypt_none_crypt(LIBSSH2_SESSION * session, unsigned char *buf, + void **abstract) +{ + /* Do nothing to the data! */ + return 0; +} + +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_none = { + "none", + 8, /* blocksize (SSH2 defines minimum blocksize as 8) */ + 0, /* iv_len */ + 0, /* secret_len */ + 0, /* flags */ + NULL, + crypt_none_crypt, + NULL +}; +#endif /* LIBSSH2_CRYPT_NONE */ + +struct crypt_ctx +{ + int encrypt; + _libssh2_cipher_type(algo); + _libssh2_cipher_ctx h; +}; + +static int +crypt_init(LIBSSH2_SESSION * session, + const LIBSSH2_CRYPT_METHOD * method, + unsigned char *iv, int *free_iv, + unsigned char *secret, int *free_secret, + int encrypt, void **abstract) +{ + struct crypt_ctx *ctx = LIBSSH2_ALLOC(session, + sizeof(struct crypt_ctx)); + if (!ctx) + return LIBSSH2_ERROR_ALLOC; + + ctx->encrypt = encrypt; + ctx->algo = method->algo; + if (_libssh2_cipher_init(&ctx->h, ctx->algo, iv, secret, encrypt)) { + LIBSSH2_FREE(session, ctx); + return -1; + } + *abstract = ctx; + *free_iv = 1; + *free_secret = 1; + return 0; +} + +static int +crypt_encrypt(LIBSSH2_SESSION * session, unsigned char *block, + void **abstract) +{ + struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract; + (void) session; + return _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block); +} + +static int +crypt_dtor(LIBSSH2_SESSION * session, void **abstract) +{ + struct crypt_ctx **cctx = (struct crypt_ctx **) abstract; + if (cctx && *cctx) { + _libssh2_cipher_dtor(&(*cctx)->h); + LIBSSH2_FREE(session, *cctx); + *abstract = NULL; + } + return 0; +} + +#if LIBSSH2_AES_CTR +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_ctr = { + "aes128-ctr", + 16, /* blocksize */ + 16, /* initial value length */ + 16, /* secret length -- 16*8 == 128bit */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes128ctr +}; + +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_ctr = { + "aes192-ctr", + 16, /* blocksize */ + 16, /* initial value length */ + 24, /* secret length -- 24*8 == 192bit */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes192ctr +}; + +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_ctr = { + "aes256-ctr", + 16, /* blocksize */ + 16, /* initial value length */ + 32, /* secret length -- 32*8 == 256bit */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes256ctr +}; +#endif + +#if LIBSSH2_AES +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes128_cbc = { + "aes128-cbc", + 16, /* blocksize */ + 16, /* initial value length */ + 16, /* secret length -- 16*8 == 128bit */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes128 +}; + +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes192_cbc = { + "aes192-cbc", + 16, /* blocksize */ + 16, /* initial value length */ + 24, /* secret length -- 24*8 == 192bit */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes192 +}; + +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_aes256_cbc = { + "aes256-cbc", + 16, /* blocksize */ + 16, /* initial value length */ + 32, /* secret length -- 32*8 == 256bit */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes256 +}; + +/* rijndael-cbc@lysator.liu.se == aes256-cbc */ +static const LIBSSH2_CRYPT_METHOD + libssh2_crypt_method_rijndael_cbc_lysator_liu_se = { + "rijndael-cbc@lysator.liu.se", + 16, /* blocksize */ + 16, /* initial value length */ + 32, /* secret length -- 32*8 == 256bit */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_aes256 +}; +#endif /* LIBSSH2_AES */ + +#if LIBSSH2_BLOWFISH +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_blowfish_cbc = { + "blowfish-cbc", + 8, /* blocksize */ + 8, /* initial value length */ + 16, /* secret length */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_blowfish +}; +#endif /* LIBSSH2_BLOWFISH */ + +#if LIBSSH2_RC4 +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour = { + "arcfour", + 8, /* blocksize */ + 8, /* initial value length */ + 16, /* secret length */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_arcfour +}; + +static int +crypt_init_arcfour128(LIBSSH2_SESSION * session, + const LIBSSH2_CRYPT_METHOD * method, + unsigned char *iv, int *free_iv, + unsigned char *secret, int *free_secret, + int encrypt, void **abstract) +{ + int rc; + + rc = crypt_init (session, method, iv, free_iv, secret, free_secret, + encrypt, abstract); + if (rc == 0) { + struct crypt_ctx *cctx = *(struct crypt_ctx **) abstract; + unsigned char block[8]; + size_t discard = 1536; + for (; discard; discard -= 8) + _libssh2_cipher_crypt(&cctx->h, cctx->algo, cctx->encrypt, block); + } + + return rc; +} + +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_arcfour128 = { + "arcfour128", + 8, /* blocksize */ + 8, /* initial value length */ + 16, /* secret length */ + 0, /* flags */ + &crypt_init_arcfour128, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_arcfour +}; +#endif /* LIBSSH2_RC4 */ + +#if LIBSSH2_CAST +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_cast128_cbc = { + "cast128-cbc", + 8, /* blocksize */ + 8, /* initial value length */ + 16, /* secret length */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_cast5 +}; +#endif /* LIBSSH2_CAST */ + +#if LIBSSH2_3DES +static const LIBSSH2_CRYPT_METHOD libssh2_crypt_method_3des_cbc = { + "3des-cbc", + 8, /* blocksize */ + 8, /* initial value length */ + 24, /* secret length */ + 0, /* flags */ + &crypt_init, + &crypt_encrypt, + &crypt_dtor, + _libssh2_cipher_3des +}; +#endif + +static const LIBSSH2_CRYPT_METHOD *_libssh2_crypt_methods[] = { +#if LIBSSH2_AES_CTR + &libssh2_crypt_method_aes128_ctr, + &libssh2_crypt_method_aes192_ctr, + &libssh2_crypt_method_aes256_ctr, +#endif /* LIBSSH2_AES */ +#if LIBSSH2_AES + &libssh2_crypt_method_aes256_cbc, + &libssh2_crypt_method_rijndael_cbc_lysator_liu_se, /* == aes256-cbc */ + &libssh2_crypt_method_aes192_cbc, + &libssh2_crypt_method_aes128_cbc, +#endif /* LIBSSH2_AES */ +#if LIBSSH2_BLOWFISH + &libssh2_crypt_method_blowfish_cbc, +#endif /* LIBSSH2_BLOWFISH */ +#if LIBSSH2_RC4 + &libssh2_crypt_method_arcfour128, + &libssh2_crypt_method_arcfour, +#endif /* LIBSSH2_RC4 */ +#if LIBSSH2_CAST + &libssh2_crypt_method_cast128_cbc, +#endif /* LIBSSH2_CAST */ +#if LIBSSH2_3DES + &libssh2_crypt_method_3des_cbc, +#endif /* LIBSSH2_DES */ +#ifdef LIBSSH2_CRYPT_NONE + &libssh2_crypt_method_none, +#endif + NULL +}; + +/* Expose to kex.c */ +const LIBSSH2_CRYPT_METHOD ** +libssh2_crypt_methods(void) +{ + return _libssh2_crypt_methods; +} diff --git a/vendor/libssh2-1.4.2/src/crypto.h b/vendor/libssh2-1.4.2/src/crypto.h new file mode 100644 index 0000000..8cf34f5 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/crypto.h @@ -0,0 +1,118 @@ +/* Copyright (C) 2009, 2010 Simon Josefsson + * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. + * Copyright (C) 2010 Daniel Stenberg + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ +#ifndef LIBSSH2_CRYPTO_H +#define LIBSSH2_CRYPTO_H + +#ifdef LIBSSH2_LIBGCRYPT +#include "libgcrypt.h" +#else +#include "openssl.h" +#endif + +int _libssh2_rsa_new(libssh2_rsa_ctx ** rsa, + const unsigned char *edata, + unsigned long elen, + const unsigned char *ndata, + unsigned long nlen, + const unsigned char *ddata, + unsigned long dlen, + const unsigned char *pdata, + unsigned long plen, + const unsigned char *qdata, + unsigned long qlen, + const unsigned char *e1data, + unsigned long e1len, + const unsigned char *e2data, + unsigned long e2len, + const unsigned char *coeffdata, unsigned long coefflen); +int _libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, + LIBSSH2_SESSION * session, + const char *filename, + unsigned const char *passphrase); +int _libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa, + const unsigned char *sig, + unsigned long sig_len, + const unsigned char *m, unsigned long m_len); +int _libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, + libssh2_rsa_ctx * rsactx, + const unsigned char *hash, + size_t hash_len, + unsigned char **signature, + size_t *signature_len); + +int _libssh2_dsa_new(libssh2_dsa_ctx ** dsa, + const unsigned char *pdata, + unsigned long plen, + const unsigned char *qdata, + unsigned long qlen, + const unsigned char *gdata, + unsigned long glen, + const unsigned char *ydata, + unsigned long ylen, + const unsigned char *x, unsigned long x_len); +int _libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, + LIBSSH2_SESSION * session, + const char *filename, + unsigned const char *passphrase); +int _libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, + const unsigned char *sig, + const unsigned char *m, unsigned long m_len); +int _libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, + const unsigned char *hash, + unsigned long hash_len, unsigned char *sig); + +int _libssh2_cipher_init(_libssh2_cipher_ctx * h, + _libssh2_cipher_type(algo), + unsigned char *iv, + unsigned char *secret, int encrypt); + +int _libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, + _libssh2_cipher_type(algo), + int encrypt, unsigned char *block); + +int _libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + const char *privatekey, + const char *passphrase); + +void _libssh2_init_aes_ctr(void); + +#endif diff --git a/vendor/libssh2-1.4.2/src/global.c b/vendor/libssh2-1.4.2/src/global.c new file mode 100644 index 0000000..dc45e70 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/global.c @@ -0,0 +1,78 @@ +/* Copyright (c) 2010 Lars Nordin + * Copyright (C) 2010 Simon Josefsson + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" + +static int _libssh2_initialized = 0; +static int _libssh2_init_flags = 0; + +LIBSSH2_API int +libssh2_init(int flags) +{ + if (_libssh2_initialized == 0 && !(flags & LIBSSH2_INIT_NO_CRYPTO)) { + libssh2_crypto_init(); + _libssh2_init_aes_ctr(); + } + + _libssh2_initialized++; + _libssh2_init_flags |= flags; + + return 0; +} + +LIBSSH2_API void +libssh2_exit(void) +{ + if (_libssh2_initialized == 0) + return; + + _libssh2_initialized--; + + if (!(_libssh2_init_flags & LIBSSH2_INIT_NO_CRYPTO)) { + libssh2_crypto_exit(); + } + + return; +} + +void +_libssh2_init_if_needed(void) +{ + if (_libssh2_initialized == 0) + (void)libssh2_init (0); +} diff --git a/vendor/libssh2-1.4.2/src/hostkey.c b/vendor/libssh2-1.4.2/src/hostkey.c new file mode 100644 index 0000000..53f7479 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/hostkey.c @@ -0,0 +1,485 @@ +/* Copyright (c) 2004-2006, Sara Golemon + * Copyright (c) 2009 by Daniel Stenberg + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" +#include "misc.h" + +/* Needed for struct iovec on some platforms */ +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#if LIBSSH2_RSA +/* *********** + * ssh-rsa * + *********** */ + +static int hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, + void **abstract); + +/* + * hostkey_method_ssh_rsa_init + * + * Initialize the server hostkey working area with e/n pair + */ +static int +hostkey_method_ssh_rsa_init(LIBSSH2_SESSION * session, + const unsigned char *hostkey_data, + size_t hostkey_data_len, + void **abstract) +{ + libssh2_rsa_ctx *rsactx; + const unsigned char *s, *e, *n; + unsigned long len, e_len, n_len; + + (void) hostkey_data_len; + + if (*abstract) { + hostkey_method_ssh_rsa_dtor(session, abstract); + *abstract = NULL; + } + + s = hostkey_data; + len = _libssh2_ntohu32(s); + s += 4; + + if (len != 7 || strncmp((char *) s, "ssh-rsa", 7) != 0) { + return -1; + } + s += 7; + + e_len = _libssh2_ntohu32(s); + s += 4; + + e = s; + s += e_len; + n_len = _libssh2_ntohu32(s); + s += 4; + n = s; + + if (_libssh2_rsa_new(&rsactx, e, e_len, n, n_len, NULL, 0, + NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0)) + return -1; + + *abstract = rsactx; + + return 0; +} + +/* + * hostkey_method_ssh_rsa_initPEM + * + * Load a Private Key from a PEM file + */ +static int +hostkey_method_ssh_rsa_initPEM(LIBSSH2_SESSION * session, + const char *privkeyfile, + unsigned const char *passphrase, + void **abstract) +{ + libssh2_rsa_ctx *rsactx; + int ret; + + if (*abstract) { + hostkey_method_ssh_rsa_dtor(session, abstract); + *abstract = NULL; + } + + ret = _libssh2_rsa_new_private(&rsactx, session, privkeyfile, passphrase); + if (ret) { + return -1; + } + + *abstract = rsactx; + + return 0; +} + +/* + * hostkey_method_ssh_rsa_sign + * + * Verify signature created by remote + */ +static int +hostkey_method_ssh_rsa_sig_verify(LIBSSH2_SESSION * session, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, + size_t m_len, void **abstract) +{ + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); + (void) session; + + /* Skip past keyname_len(4) + keyname(7){"ssh-rsa"} + signature_len(4) */ + sig += 15; + sig_len -= 15; + return _libssh2_rsa_sha1_verify(rsactx, sig, sig_len, m, m_len); +} + +/* + * hostkey_method_ssh_rsa_signv + * + * Construct a signature from an array of vectors + */ +static int +hostkey_method_ssh_rsa_signv(LIBSSH2_SESSION * session, + unsigned char **signature, + size_t *signature_len, + int veccount, + const struct iovec datavec[], + void **abstract) +{ + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); + int ret; + int i; + unsigned char hash[SHA_DIGEST_LENGTH]; + libssh2_sha1_ctx ctx; + + libssh2_sha1_init(&ctx); + for(i = 0; i < veccount; i++) { + libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len); + } + libssh2_sha1_final(ctx, hash); + + ret = _libssh2_rsa_sha1_sign(session, rsactx, hash, SHA_DIGEST_LENGTH, + signature, signature_len); + if (ret) { + return -1; + } + + return 0; +} + +/* + * hostkey_method_ssh_rsa_dtor + * + * Shutdown the hostkey + */ +static int +hostkey_method_ssh_rsa_dtor(LIBSSH2_SESSION * session, void **abstract) +{ + libssh2_rsa_ctx *rsactx = (libssh2_rsa_ctx *) (*abstract); + (void) session; + + _libssh2_rsa_free(rsactx); + + *abstract = NULL; + + return 0; +} + +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_rsa = { + "ssh-rsa", + MD5_DIGEST_LENGTH, + hostkey_method_ssh_rsa_init, + hostkey_method_ssh_rsa_initPEM, + hostkey_method_ssh_rsa_sig_verify, + hostkey_method_ssh_rsa_signv, + NULL, /* encrypt */ + hostkey_method_ssh_rsa_dtor, +}; +#endif /* LIBSSH2_RSA */ + +#if LIBSSH2_DSA +/* *********** + * ssh-dss * + *********** */ + +static int hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, + void **abstract); + +/* + * hostkey_method_ssh_dss_init + * + * Initialize the server hostkey working area with p/q/g/y set + */ +static int +hostkey_method_ssh_dss_init(LIBSSH2_SESSION * session, + const unsigned char *hostkey_data, + size_t hostkey_data_len, + void **abstract) +{ + libssh2_dsa_ctx *dsactx; + const unsigned char *p, *q, *g, *y, *s; + unsigned long p_len, q_len, g_len, y_len, len; + (void) hostkey_data_len; + + if (*abstract) { + hostkey_method_ssh_dss_dtor(session, abstract); + *abstract = NULL; + } + + s = hostkey_data; + len = _libssh2_ntohu32(s); + s += 4; + if (len != 7 || strncmp((char *) s, "ssh-dss", 7) != 0) { + return -1; + } + s += 7; + + p_len = _libssh2_ntohu32(s); + s += 4; + p = s; + s += p_len; + q_len = _libssh2_ntohu32(s); + s += 4; + q = s; + s += q_len; + g_len = _libssh2_ntohu32(s); + s += 4; + g = s; + s += g_len; + y_len = _libssh2_ntohu32(s); + s += 4; + y = s; + /* s += y_len; */ + + _libssh2_dsa_new(&dsactx, p, p_len, q, q_len, g, g_len, y, y_len, NULL, 0); + + *abstract = dsactx; + + return 0; +} + +/* + * hostkey_method_ssh_dss_initPEM + * + * Load a Private Key from a PEM file + */ +static int +hostkey_method_ssh_dss_initPEM(LIBSSH2_SESSION * session, + const char *privkeyfile, + unsigned const char *passphrase, + void **abstract) +{ + libssh2_dsa_ctx *dsactx; + int ret; + + if (*abstract) { + hostkey_method_ssh_dss_dtor(session, abstract); + *abstract = NULL; + } + + ret = _libssh2_dsa_new_private(&dsactx, session, privkeyfile, passphrase); + if (ret) { + return -1; + } + + *abstract = dsactx; + + return 0; +} + +/* + * libssh2_hostkey_method_ssh_dss_sign + * + * Verify signature created by remote + */ +static int +hostkey_method_ssh_dss_sig_verify(LIBSSH2_SESSION * session, + const unsigned char *sig, + size_t sig_len, + const unsigned char *m, + size_t m_len, void **abstract) +{ + libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract); + + /* Skip past keyname_len(4) + keyname(7){"ssh-dss"} + signature_len(4) */ + sig += 15; + sig_len -= 15; + if (sig_len != 40) { + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Invalid DSS signature length"); + } + return _libssh2_dsa_sha1_verify(dsactx, sig, m, m_len); +} + +/* + * hostkey_method_ssh_dss_signv + * + * Construct a signature from an array of vectors + */ +static int +hostkey_method_ssh_dss_signv(LIBSSH2_SESSION * session, + unsigned char **signature, + size_t *signature_len, + int veccount, + const struct iovec datavec[], + void **abstract) +{ + libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract); + unsigned char hash[SHA_DIGEST_LENGTH]; + libssh2_sha1_ctx ctx; + int i; + + *signature = LIBSSH2_ALLOC(session, 2 * SHA_DIGEST_LENGTH); + if (!*signature) { + return -1; + } + + *signature_len = 2 * SHA_DIGEST_LENGTH; + memset(*signature, 0, 2 * SHA_DIGEST_LENGTH); + + libssh2_sha1_init(&ctx); + for(i = 0; i < veccount; i++) { + libssh2_sha1_update(ctx, datavec[i].iov_base, datavec[i].iov_len); + } + libssh2_sha1_final(ctx, hash); + + if (_libssh2_dsa_sha1_sign(dsactx, hash, SHA_DIGEST_LENGTH, *signature)) { + LIBSSH2_FREE(session, *signature); + return -1; + } + + return 0; +} + +/* + * libssh2_hostkey_method_ssh_dss_dtor + * + * Shutdown the hostkey method + */ +static int +hostkey_method_ssh_dss_dtor(LIBSSH2_SESSION * session, void **abstract) +{ + libssh2_dsa_ctx *dsactx = (libssh2_dsa_ctx *) (*abstract); + (void) session; + + _libssh2_dsa_free(dsactx); + + *abstract = NULL; + + return 0; +} + +static const LIBSSH2_HOSTKEY_METHOD hostkey_method_ssh_dss = { + "ssh-dss", + MD5_DIGEST_LENGTH, + hostkey_method_ssh_dss_init, + hostkey_method_ssh_dss_initPEM, + hostkey_method_ssh_dss_sig_verify, + hostkey_method_ssh_dss_signv, + NULL, /* encrypt */ + hostkey_method_ssh_dss_dtor, +}; +#endif /* LIBSSH2_DSA */ + +static const LIBSSH2_HOSTKEY_METHOD *hostkey_methods[] = { +#if LIBSSH2_RSA + &hostkey_method_ssh_rsa, +#endif /* LIBSSH2_RSA */ +#if LIBSSH2_DSA + &hostkey_method_ssh_dss, +#endif /* LIBSSH2_DSA */ + NULL +}; + +const LIBSSH2_HOSTKEY_METHOD ** +libssh2_hostkey_methods(void) +{ + return hostkey_methods; +} + +/* + * libssh2_hostkey_hash + * + * Returns hash signature + * Returned buffer should NOT be freed + * Length of buffer is determined by hash type + * i.e. MD5 == 16, SHA1 == 20 + */ +LIBSSH2_API const char * +libssh2_hostkey_hash(LIBSSH2_SESSION * session, int hash_type) +{ + switch (hash_type) { +#if LIBSSH2_MD5 + case LIBSSH2_HOSTKEY_HASH_MD5: + return (char *) session->server_hostkey_md5; + break; +#endif /* LIBSSH2_MD5 */ + case LIBSSH2_HOSTKEY_HASH_SHA1: + return (char *) session->server_hostkey_sha1; + break; + default: + return NULL; + } +} + +static int hostkey_type(const unsigned char *hostkey, size_t len) +{ + const unsigned char rsa[] = { + 0, 0, 0, 0x07, 's', 's', 'h', '-', 'r', 's', 'a' + }; + const unsigned char dss[] = { + 0, 0, 0, 0x07, 's', 's', 'h', '-', 'd', 's', 's' + }; + + if (len < 11) + return LIBSSH2_HOSTKEY_TYPE_UNKNOWN; + + if (!memcmp(rsa, hostkey, 11)) + return LIBSSH2_HOSTKEY_TYPE_RSA; + + if (!memcmp(dss, hostkey, 11)) + return LIBSSH2_HOSTKEY_TYPE_DSS; + + return LIBSSH2_HOSTKEY_TYPE_UNKNOWN; +} + +/* + * libssh2_session_hostkey() + * + * Returns the server key and length. + * + */ +LIBSSH2_API const char * +libssh2_session_hostkey(LIBSSH2_SESSION *session, size_t *len, int *type) +{ + if(session->server_hostkey_len) { + if(len) + *len = session->server_hostkey_len; + if (type) + *type = hostkey_type(session->server_hostkey, + session->server_hostkey_len); + return (char *) session->server_hostkey; + } + if(len) + *len = 0; + return NULL; +} + diff --git a/vendor/libssh2-1.4.2/src/keepalive.c b/vendor/libssh2-1.4.2/src/keepalive.c new file mode 100644 index 0000000..260206a --- /dev/null +++ b/vendor/libssh2-1.4.2/src/keepalive.c @@ -0,0 +1,98 @@ +/* Copyright (C) 2010 Simon Josefsson + * Author: Simon Josefsson + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +#include "libssh2_priv.h" +#include "transport.h" /* _libssh2_transport_write */ + +/* Keep-alive stuff. */ + +LIBSSH2_API void +libssh2_keepalive_config (LIBSSH2_SESSION *session, + int want_reply, + unsigned interval) +{ + if (interval == 1) + session->keepalive_interval = 2; + else + session->keepalive_interval = interval; + session->keepalive_want_reply = want_reply ? 1 : 0; +} + +LIBSSH2_API int +libssh2_keepalive_send (LIBSSH2_SESSION *session, + int *seconds_to_next) +{ + time_t now; + + if (!session->keepalive_interval) { + if (seconds_to_next) + *seconds_to_next = 0; + return 0; + } + + now = time (NULL); + + if (session->keepalive_last_sent + session->keepalive_interval <= now) { + /* Format is + "SSH_MSG_GLOBAL_REQUEST || 4-byte len || str || want-reply". */ + unsigned char keepalive_data[] + = "\x50\x00\x00\x00\x15keepalive@libssh2.orgW"; + size_t len = sizeof (keepalive_data) - 1; + int rc; + + keepalive_data[len - 1] = session->keepalive_want_reply; + + rc = _libssh2_transport_send(session, keepalive_data, len, NULL, 0); + /* Silently ignore PACKET_EAGAIN here: if the write buffer is + already full, sending another keepalive is not useful. */ + if (rc && rc != LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send keepalive message"); + return rc; + } + + session->keepalive_last_sent = now; + if (seconds_to_next) + *seconds_to_next = session->keepalive_interval; + } else if (seconds_to_next) { + *seconds_to_next = (int) session->keepalive_last_sent + + session->keepalive_interval - now; + } + + return 0; +} diff --git a/vendor/libssh2-1.4.2/src/kex.c b/vendor/libssh2-1.4.2/src/kex.c new file mode 100644 index 0000000..0a72cb7 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/kex.c @@ -0,0 +1,2008 @@ +/* Copyright (c) 2004-2007, Sara Golemon + * Copyright (c) 2010, Daniel Stenberg + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" + +#include "transport.h" +#include "comp.h" +#include "mac.h" + +/* TODO: Switch this to an inline and handle alloc() failures */ +/* Helper macro called from kex_method_diffie_hellman_group1_sha1_key_exchange */ +#define LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(value, reqlen, version) \ + { \ + libssh2_sha1_ctx hash; \ + unsigned long len = 0; \ + if (!(value)) { \ + value = LIBSSH2_ALLOC(session, reqlen + SHA_DIGEST_LENGTH); \ + } \ + if (value) \ + while (len < (unsigned long)reqlen) { \ + libssh2_sha1_init(&hash); \ + libssh2_sha1_update(hash, exchange_state->k_value, \ + exchange_state->k_value_len); \ + libssh2_sha1_update(hash, exchange_state->h_sig_comp, \ + SHA_DIGEST_LENGTH); \ + if (len > 0) { \ + libssh2_sha1_update(hash, value, len); \ + } else { \ + libssh2_sha1_update(hash, (version), 1); \ + libssh2_sha1_update(hash, session->session_id, \ + session->session_id_len); \ + } \ + libssh2_sha1_final(hash, (value) + len); \ + len += SHA_DIGEST_LENGTH; \ + } \ + } + +/* + * diffie_hellman_sha1 + * + * Diffie Hellman Key Exchange, Group Agnostic + */ +static int diffie_hellman_sha1(LIBSSH2_SESSION *session, + _libssh2_bn *g, + _libssh2_bn *p, + int group_order, + unsigned char packet_type_init, + unsigned char packet_type_reply, + unsigned char *midhash, + unsigned long midhash_len, + kmdhgGPsha1kex_state_t *exchange_state) +{ + int ret = 0; + int rc; + + if (exchange_state->state == libssh2_NB_state_idle) { + /* Setup initial values */ + exchange_state->e_packet = NULL; + exchange_state->s_packet = NULL; + exchange_state->k_value = NULL; + exchange_state->ctx = _libssh2_bn_ctx_new(); + exchange_state->x = _libssh2_bn_init(); /* Random from client */ + exchange_state->e = _libssh2_bn_init(); /* g^x mod p */ + exchange_state->f = _libssh2_bn_init(); /* g^(Random from server) mod p */ + exchange_state->k = _libssh2_bn_init(); /* The shared secret: f^x mod p */ + + /* Zero the whole thing out */ + memset(&exchange_state->req_state, 0, sizeof(packet_require_state_t)); + + /* Generate x and e */ + _libssh2_bn_rand(exchange_state->x, group_order, 0, -1); + _libssh2_bn_mod_exp(exchange_state->e, g, exchange_state->x, p, + exchange_state->ctx); + + /* Send KEX init */ + /* packet_type(1) + String Length(4) + leading 0(1) */ + exchange_state->e_packet_len = + _libssh2_bn_bytes(exchange_state->e) + 6; + if (_libssh2_bn_bits(exchange_state->e) % 8) { + /* Leading 00 not needed */ + exchange_state->e_packet_len--; + } + + exchange_state->e_packet = + LIBSSH2_ALLOC(session, exchange_state->e_packet_len); + if (!exchange_state->e_packet) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Out of memory error"); + goto clean_exit; + } + exchange_state->e_packet[0] = packet_type_init; + _libssh2_htonu32(exchange_state->e_packet + 1, + exchange_state->e_packet_len - 5); + if (_libssh2_bn_bits(exchange_state->e) % 8) { + _libssh2_bn_to_bin(exchange_state->e, + exchange_state->e_packet + 5); + } else { + exchange_state->e_packet[5] = 0; + _libssh2_bn_to_bin(exchange_state->e, + exchange_state->e_packet + 6); + } + + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending KEX packet %d", + (int) packet_type_init); + exchange_state->state = libssh2_NB_state_created; + } + + if (exchange_state->state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, exchange_state->e_packet, + exchange_state->e_packet_len, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + ret = _libssh2_error(session, rc, + "Unable to send KEX init message"); + goto clean_exit; + } + exchange_state->state = libssh2_NB_state_sent; + } + + if (exchange_state->state == libssh2_NB_state_sent) { + if (session->burn_optimistic_kexinit) { + /* The first KEX packet to come along will be the guess initially + * sent by the server. That guess turned out to be wrong so we + * need to silently ignore it */ + int burn_type; + + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Waiting for badly guessed KEX packet (to be ignored)"); + burn_type = + _libssh2_packet_burn(session, &exchange_state->burn_state); + if (burn_type == LIBSSH2_ERROR_EAGAIN) { + return burn_type; + } else if (burn_type <= 0) { + /* Failed to receive a packet */ + ret = burn_type; + goto clean_exit; + } + session->burn_optimistic_kexinit = 0; + + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Burnt packet of type: %02x", + (unsigned int) burn_type); + } + + exchange_state->state = libssh2_NB_state_sent1; + } + + if (exchange_state->state == libssh2_NB_state_sent1) { + /* Wait for KEX reply */ + rc = _libssh2_packet_require(session, packet_type_reply, + &exchange_state->s_packet, + &exchange_state->s_packet_len, 0, NULL, + 0, &exchange_state->req_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + if (rc) { + ret = _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, + "Timed out waiting for KEX reply"); + goto clean_exit; + } + + /* Parse KEXDH_REPLY */ + exchange_state->s = exchange_state->s_packet + 1; + + session->server_hostkey_len = _libssh2_ntohu32(exchange_state->s); + exchange_state->s += 4; + session->server_hostkey = + LIBSSH2_ALLOC(session, session->server_hostkey_len); + if (!session->server_hostkey) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for a copy " + "of the host key"); + goto clean_exit; + } + memcpy(session->server_hostkey, exchange_state->s, + session->server_hostkey_len); + exchange_state->s += session->server_hostkey_len; + +#if LIBSSH2_MD5 + { + libssh2_md5_ctx fingerprint_ctx; + + libssh2_md5_init(&fingerprint_ctx); + libssh2_md5_update(fingerprint_ctx, session->server_hostkey, + session->server_hostkey_len); + libssh2_md5_final(fingerprint_ctx, session->server_hostkey_md5); + } +#ifdef LIBSSH2DEBUG + { + char fingerprint[50], *fprint = fingerprint; + int i; + for(i = 0; i < 16; i++, fprint += 3) { + snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]); + } + *(--fprint) = '\0'; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Server's MD5 Fingerprint: %s", fingerprint); + } +#endif /* LIBSSH2DEBUG */ +#endif /* ! LIBSSH2_MD5 */ + + { + libssh2_sha1_ctx fingerprint_ctx; + + libssh2_sha1_init(&fingerprint_ctx); + libssh2_sha1_update(fingerprint_ctx, session->server_hostkey, + session->server_hostkey_len); + libssh2_sha1_final(fingerprint_ctx, session->server_hostkey_sha1); + } +#ifdef LIBSSH2DEBUG + { + char fingerprint[64], *fprint = fingerprint; + int i; + + for(i = 0; i < 20; i++, fprint += 3) { + snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]); + } + *(--fprint) = '\0'; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Server's SHA1 Fingerprint: %s", fingerprint); + } +#endif /* LIBSSH2DEBUG */ + + if (session->hostkey->init(session, session->server_hostkey, + session->server_hostkey_len, + &session->server_hostkey_abstract)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, + "Unable to initialize hostkey importer"); + goto clean_exit; + } + + exchange_state->f_value_len = _libssh2_ntohu32(exchange_state->s); + exchange_state->s += 4; + exchange_state->f_value = exchange_state->s; + exchange_state->s += exchange_state->f_value_len; + _libssh2_bn_from_bin(exchange_state->f, exchange_state->f_value_len, + exchange_state->f_value); + + exchange_state->h_sig_len = _libssh2_ntohu32(exchange_state->s); + exchange_state->s += 4; + exchange_state->h_sig = exchange_state->s; + + /* Compute the shared secret */ + _libssh2_bn_mod_exp(exchange_state->k, exchange_state->f, + exchange_state->x, p, exchange_state->ctx); + exchange_state->k_value_len = _libssh2_bn_bytes(exchange_state->k) + 5; + if (_libssh2_bn_bits(exchange_state->k) % 8) { + /* don't need leading 00 */ + exchange_state->k_value_len--; + } + exchange_state->k_value = + LIBSSH2_ALLOC(session, exchange_state->k_value_len); + if (!exchange_state->k_value) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate buffer for K"); + goto clean_exit; + } + _libssh2_htonu32(exchange_state->k_value, + exchange_state->k_value_len - 4); + if (_libssh2_bn_bits(exchange_state->k) % 8) { + _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 4); + } else { + exchange_state->k_value[4] = 0; + _libssh2_bn_to_bin(exchange_state->k, exchange_state->k_value + 5); + } + + libssh2_sha1_init(&exchange_state->exchange_hash); + if (session->local.banner) { + _libssh2_htonu32(exchange_state->h_sig_comp, + strlen((char *) session->local.banner) - 2); + libssh2_sha1_update(exchange_state->exchange_hash, + exchange_state->h_sig_comp, 4); + libssh2_sha1_update(exchange_state->exchange_hash, + (char *) session->local.banner, + strlen((char *) session->local.banner) - 2); + } else { + _libssh2_htonu32(exchange_state->h_sig_comp, + sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); + libssh2_sha1_update(exchange_state->exchange_hash, + exchange_state->h_sig_comp, 4); + libssh2_sha1_update(exchange_state->exchange_hash, + LIBSSH2_SSH_DEFAULT_BANNER, + sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1); + } + + _libssh2_htonu32(exchange_state->h_sig_comp, + strlen((char *) session->remote.banner)); + libssh2_sha1_update(exchange_state->exchange_hash, + exchange_state->h_sig_comp, 4); + libssh2_sha1_update(exchange_state->exchange_hash, + session->remote.banner, + strlen((char *) session->remote.banner)); + + _libssh2_htonu32(exchange_state->h_sig_comp, + session->local.kexinit_len); + libssh2_sha1_update(exchange_state->exchange_hash, + exchange_state->h_sig_comp, 4); + libssh2_sha1_update(exchange_state->exchange_hash, + session->local.kexinit, + session->local.kexinit_len); + + _libssh2_htonu32(exchange_state->h_sig_comp, + session->remote.kexinit_len); + libssh2_sha1_update(exchange_state->exchange_hash, + exchange_state->h_sig_comp, 4); + libssh2_sha1_update(exchange_state->exchange_hash, + session->remote.kexinit, + session->remote.kexinit_len); + + _libssh2_htonu32(exchange_state->h_sig_comp, + session->server_hostkey_len); + libssh2_sha1_update(exchange_state->exchange_hash, + exchange_state->h_sig_comp, 4); + libssh2_sha1_update(exchange_state->exchange_hash, + session->server_hostkey, + session->server_hostkey_len); + + if (packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) { + /* diffie-hellman-group-exchange hashes additional fields */ +#ifdef LIBSSH2_DH_GEX_NEW + _libssh2_htonu32(exchange_state->h_sig_comp, + LIBSSH2_DH_GEX_MINGROUP); + _libssh2_htonu32(exchange_state->h_sig_comp + 4, + LIBSSH2_DH_GEX_OPTGROUP); + _libssh2_htonu32(exchange_state->h_sig_comp + 8, + LIBSSH2_DH_GEX_MAXGROUP); + libssh2_sha1_update(exchange_state->exchange_hash, + exchange_state->h_sig_comp, 12); +#else + _libssh2_htonu32(exchange_state->h_sig_comp, + LIBSSH2_DH_GEX_OPTGROUP); + libssh2_sha1_update(exchange_state->exchange_hash, + exchange_state->h_sig_comp, 4); +#endif + } + + if (midhash) { + libssh2_sha1_update(exchange_state->exchange_hash, midhash, + midhash_len); + } + + libssh2_sha1_update(exchange_state->exchange_hash, + exchange_state->e_packet + 1, + exchange_state->e_packet_len - 1); + + _libssh2_htonu32(exchange_state->h_sig_comp, + exchange_state->f_value_len); + libssh2_sha1_update(exchange_state->exchange_hash, + exchange_state->h_sig_comp, 4); + libssh2_sha1_update(exchange_state->exchange_hash, + exchange_state->f_value, + exchange_state->f_value_len); + + libssh2_sha1_update(exchange_state->exchange_hash, + exchange_state->k_value, + exchange_state->k_value_len); + + libssh2_sha1_final(exchange_state->exchange_hash, + exchange_state->h_sig_comp); + + if (session->hostkey-> + sig_verify(session, exchange_state->h_sig, + exchange_state->h_sig_len, exchange_state->h_sig_comp, + 20, &session->server_hostkey_abstract)) { + ret = _libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, + "Unable to verify hostkey signature"); + goto clean_exit; + } + + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sending NEWKEYS message"); + exchange_state->c = SSH_MSG_NEWKEYS; + + exchange_state->state = libssh2_NB_state_sent2; + } + + if (exchange_state->state == libssh2_NB_state_sent2) { + rc = _libssh2_transport_send(session, &exchange_state->c, 1, NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + ret = _libssh2_error(session, rc, "Unable to send NEWKEYS message"); + goto clean_exit; + } + + exchange_state->state = libssh2_NB_state_sent3; + } + + if (exchange_state->state == libssh2_NB_state_sent3) { + rc = _libssh2_packet_require(session, SSH_MSG_NEWKEYS, + &exchange_state->tmp, + &exchange_state->tmp_len, 0, NULL, 0, + &exchange_state->req_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + ret = _libssh2_error(session, rc, "Timed out waiting for NEWKEYS"); + goto clean_exit; + } + /* The first key exchange has been performed, + switch to active crypt/comp/mac mode */ + session->state |= LIBSSH2_STATE_NEWKEYS; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Received NEWKEYS message"); + + /* This will actually end up being just packet_type(1) + for this packet type anyway */ + LIBSSH2_FREE(session, exchange_state->tmp); + + if (!session->session_id) { + session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH); + if (!session->session_id) { + ret = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate buffer for SHA digest"); + goto clean_exit; + } + memcpy(session->session_id, exchange_state->h_sig_comp, + SHA_DIGEST_LENGTH); + session->session_id_len = SHA_DIGEST_LENGTH; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "session_id calculated"); + } + + /* Cleanup any existing cipher */ + if (session->local.crypt->dtor) { + session->local.crypt->dtor(session, + &session->local.crypt_abstract); + } + + /* Calculate IV/Secret/Key for each direction */ + if (session->local.crypt->init) { + unsigned char *iv = NULL, *secret = NULL; + int free_iv = 0, free_secret = 0; + + LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, + session->local.crypt-> + iv_len, "A"); + if (!iv) { + ret = -1; + goto clean_exit; + } + LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, + session->local.crypt-> + secret_len, "C"); + if (!secret) { + LIBSSH2_FREE(session, iv); + ret = LIBSSH2_ERROR_KEX_FAILURE; + goto clean_exit; + } + if (session->local.crypt-> + init(session, session->local.crypt, iv, &free_iv, secret, + &free_secret, 1, &session->local.crypt_abstract)) { + LIBSSH2_FREE(session, iv); + LIBSSH2_FREE(session, secret); + ret = LIBSSH2_ERROR_KEX_FAILURE; + goto clean_exit; + } + + if (free_iv) { + memset(iv, 0, session->local.crypt->iv_len); + LIBSSH2_FREE(session, iv); + } + + if (free_secret) { + memset(secret, 0, session->local.crypt->secret_len); + LIBSSH2_FREE(session, secret); + } + } + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Client to Server IV and Key calculated"); + + if (session->remote.crypt->dtor) { + /* Cleanup any existing cipher */ + session->remote.crypt->dtor(session, + &session->remote.crypt_abstract); + } + + if (session->remote.crypt->init) { + unsigned char *iv = NULL, *secret = NULL; + int free_iv = 0, free_secret = 0; + + LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, + session->remote.crypt-> + iv_len, "B"); + if (!iv) { + ret = LIBSSH2_ERROR_KEX_FAILURE; + goto clean_exit; + } + LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, + session->remote.crypt-> + secret_len, "D"); + if (!secret) { + LIBSSH2_FREE(session, iv); + ret = LIBSSH2_ERROR_KEX_FAILURE; + goto clean_exit; + } + if (session->remote.crypt-> + init(session, session->remote.crypt, iv, &free_iv, secret, + &free_secret, 0, &session->remote.crypt_abstract)) { + LIBSSH2_FREE(session, iv); + LIBSSH2_FREE(session, secret); + ret = LIBSSH2_ERROR_KEX_FAILURE; + goto clean_exit; + } + + if (free_iv) { + memset(iv, 0, session->remote.crypt->iv_len); + LIBSSH2_FREE(session, iv); + } + + if (free_secret) { + memset(secret, 0, session->remote.crypt->secret_len); + LIBSSH2_FREE(session, secret); + } + } + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Server to Client IV and Key calculated"); + + if (session->local.mac->dtor) { + session->local.mac->dtor(session, &session->local.mac_abstract); + } + + if (session->local.mac->init) { + unsigned char *key = NULL; + int free_key = 0; + + LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, + session->local.mac-> + key_len, "E"); + if (!key) { + ret = LIBSSH2_ERROR_KEX_FAILURE; + goto clean_exit; + } + session->local.mac->init(session, key, &free_key, + &session->local.mac_abstract); + + if (free_key) { + memset(key, 0, session->local.mac->key_len); + LIBSSH2_FREE(session, key); + } + } + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Client to Server HMAC Key calculated"); + + if (session->remote.mac->dtor) { + session->remote.mac->dtor(session, &session->remote.mac_abstract); + } + + if (session->remote.mac->init) { + unsigned char *key = NULL; + int free_key = 0; + + LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, + session->remote.mac-> + key_len, "F"); + if (!key) { + ret = LIBSSH2_ERROR_KEX_FAILURE; + goto clean_exit; + } + session->remote.mac->init(session, key, &free_key, + &session->remote.mac_abstract); + + if (free_key) { + memset(key, 0, session->remote.mac->key_len); + LIBSSH2_FREE(session, key); + } + } + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Server to Client HMAC Key calculated"); + + /* Initialize compression for each direction */ + + /* Cleanup any existing compression */ + if (session->local.comp && session->local.comp->dtor) { + session->local.comp->dtor(session, 1, + &session->local.comp_abstract); + } + + if (session->local.comp && session->local.comp->init) { + if (session->local.comp->init(session, 1, + &session->local.comp_abstract)) { + ret = LIBSSH2_ERROR_KEX_FAILURE; + goto clean_exit; + } + } + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Client to Server compression initialized"); + + if (session->remote.comp && session->remote.comp->dtor) { + session->remote.comp->dtor(session, 0, + &session->remote.comp_abstract); + } + + if (session->remote.comp && session->remote.comp->init) { + if (session->remote.comp->init(session, 0, + &session->remote.comp_abstract)) { + ret = LIBSSH2_ERROR_KEX_FAILURE; + goto clean_exit; + } + } + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Server to Client compression initialized"); + + } + + clean_exit: + _libssh2_bn_free(exchange_state->x); + exchange_state->x = NULL; + _libssh2_bn_free(exchange_state->e); + exchange_state->e = NULL; + _libssh2_bn_free(exchange_state->f); + exchange_state->f = NULL; + _libssh2_bn_free(exchange_state->k); + exchange_state->k = NULL; + _libssh2_bn_ctx_free(exchange_state->ctx); + exchange_state->ctx = NULL; + + if (exchange_state->e_packet) { + LIBSSH2_FREE(session, exchange_state->e_packet); + exchange_state->e_packet = NULL; + } + + if (exchange_state->s_packet) { + LIBSSH2_FREE(session, exchange_state->s_packet); + exchange_state->s_packet = NULL; + } + + if (exchange_state->k_value) { + LIBSSH2_FREE(session, exchange_state->k_value); + exchange_state->k_value = NULL; + } + + exchange_state->state = libssh2_NB_state_idle; + + return ret; +} + + + +/* kex_method_diffie_hellman_group1_sha1_key_exchange + * Diffie-Hellman Group1 (Actually Group2) Key Exchange using SHA1 + */ +static int +kex_method_diffie_hellman_group1_sha1_key_exchange(LIBSSH2_SESSION *session, + key_exchange_state_low_t + * key_state) +{ + static const unsigned char p_value[128] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + + int ret; + + if (key_state->state == libssh2_NB_state_idle) { + /* g == 2 */ + key_state->p = _libssh2_bn_init(); /* SSH2 defined value (p_value) */ + key_state->g = _libssh2_bn_init(); /* SSH2 defined value (2) */ + + /* Initialize P and G */ + _libssh2_bn_set_word(key_state->g, 2); + _libssh2_bn_from_bin(key_state->p, 128, p_value); + + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group1 Key Exchange"); + + key_state->state = libssh2_NB_state_created; + } + ret = diffie_hellman_sha1(session, key_state->g, key_state->p, 128, + SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, + NULL, 0, &key_state->exchange_state); + if (ret == LIBSSH2_ERROR_EAGAIN) { + return ret; + } + + _libssh2_bn_free(key_state->p); + key_state->p = NULL; + _libssh2_bn_free(key_state->g); + key_state->g = NULL; + key_state->state = libssh2_NB_state_idle; + + return ret; +} + + + +/* kex_method_diffie_hellman_group14_sha1_key_exchange + * Diffie-Hellman Group14 Key Exchange using SHA1 + */ +static int +kex_method_diffie_hellman_group14_sha1_key_exchange(LIBSSH2_SESSION *session, + key_exchange_state_low_t + * key_state) +{ + static const unsigned char p_value[256] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34, + 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, + 0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22, + 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, + 0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37, + 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, + 0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B, + 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED, + 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, + 0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6, + 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D, + 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, + 0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A, + 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F, + 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, + 0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB, + 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D, + 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, + 0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C, + 0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B, + 0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03, + 0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F, + 0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9, + 0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18, + 0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5, + 0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10, + 0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF + }; + int ret; + + if (key_state->state == libssh2_NB_state_idle) { + key_state->p = _libssh2_bn_init(); /* SSH2 defined value (p_value) */ + key_state->g = _libssh2_bn_init(); /* SSH2 defined value (2) */ + + /* g == 2 */ + /* Initialize P and G */ + _libssh2_bn_set_word(key_state->g, 2); + _libssh2_bn_from_bin(key_state->p, 256, p_value); + + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group14 Key Exchange"); + + key_state->state = libssh2_NB_state_created; + } + ret = diffie_hellman_sha1(session, key_state->g, key_state->p, + 256, SSH_MSG_KEXDH_INIT, SSH_MSG_KEXDH_REPLY, + NULL, 0, &key_state->exchange_state); + if (ret == LIBSSH2_ERROR_EAGAIN) { + return ret; + } + + key_state->state = libssh2_NB_state_idle; + _libssh2_bn_free(key_state->p); + key_state->p = NULL; + _libssh2_bn_free(key_state->g); + key_state->g = NULL; + + return ret; +} + + + +/* kex_method_diffie_hellman_group_exchange_sha1_key_exchange + * Diffie-Hellman Group Exchange Key Exchange using SHA1 + * Negotiates random(ish) group for secret derivation + */ +static int +kex_method_diffie_hellman_group_exchange_sha1_key_exchange +(LIBSSH2_SESSION * session, key_exchange_state_low_t * key_state) +{ + unsigned long p_len, g_len; + int ret = 0; + int rc; + + if (key_state->state == libssh2_NB_state_idle) { + key_state->p = _libssh2_bn_init(); + key_state->g = _libssh2_bn_init(); + /* Ask for a P and G pair */ +#ifdef LIBSSH2_DH_GEX_NEW + key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST; + _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_MINGROUP); + _libssh2_htonu32(key_state->request + 5, LIBSSH2_DH_GEX_OPTGROUP); + _libssh2_htonu32(key_state->request + 9, LIBSSH2_DH_GEX_MAXGROUP); + key_state->request_len = 13; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group-Exchange (New Method)"); +#else + key_state->request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD; + _libssh2_htonu32(key_state->request + 1, LIBSSH2_DH_GEX_OPTGROUP); + key_state->request_len = 5; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, + "Initiating Diffie-Hellman Group-Exchange (Old Method)"); +#endif + + key_state->state = libssh2_NB_state_created; + } + + if (key_state->state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, key_state->request, + key_state->request_len, NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + ret = _libssh2_error(session, rc, + "Unable to send Group Exchange Request"); + goto dh_gex_clean_exit; + } + + key_state->state = libssh2_NB_state_sent; + } + + if (key_state->state == libssh2_NB_state_sent) { + rc = _libssh2_packet_require(session, SSH_MSG_KEX_DH_GEX_GROUP, + &key_state->data, &key_state->data_len, + 0, NULL, 0, &key_state->req_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + ret = _libssh2_error(session, rc, + "Timeout waiting for GEX_GROUP reply"); + goto dh_gex_clean_exit; + } + + key_state->state = libssh2_NB_state_sent1; + } + + if (key_state->state == libssh2_NB_state_sent1) { + unsigned char *s = key_state->data + 1; + p_len = _libssh2_ntohu32(s); + s += 4; + _libssh2_bn_from_bin(key_state->p, p_len, s); + s += p_len; + + g_len = _libssh2_ntohu32(s); + s += 4; + _libssh2_bn_from_bin(key_state->g, g_len, s); + + ret = diffie_hellman_sha1(session, key_state->g, key_state->p, p_len, + SSH_MSG_KEX_DH_GEX_INIT, + SSH_MSG_KEX_DH_GEX_REPLY, + key_state->data + 1, + key_state->data_len - 1, + &key_state->exchange_state); + if (ret == LIBSSH2_ERROR_EAGAIN) { + return ret; + } + + LIBSSH2_FREE(session, key_state->data); + } + + dh_gex_clean_exit: + key_state->state = libssh2_NB_state_idle; + _libssh2_bn_free(key_state->g); + key_state->g = NULL; + _libssh2_bn_free(key_state->p); + key_state->p = NULL; + + return ret; +} + + + +#define LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY 0x0001 +#define LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY 0x0002 + +static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group1_sha1 = { + "diffie-hellman-group1-sha1", + kex_method_diffie_hellman_group1_sha1_key_exchange, + LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, +}; + +static const LIBSSH2_KEX_METHOD kex_method_diffie_helman_group14_sha1 = { + "diffie-hellman-group14-sha1", + kex_method_diffie_hellman_group14_sha1_key_exchange, + LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, +}; + +static const LIBSSH2_KEX_METHOD +kex_method_diffie_helman_group_exchange_sha1 = { + "diffie-hellman-group-exchange-sha1", + kex_method_diffie_hellman_group_exchange_sha1_key_exchange, + LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY, +}; + +static const LIBSSH2_KEX_METHOD *libssh2_kex_methods[] = { + &kex_method_diffie_helman_group14_sha1, + &kex_method_diffie_helman_group_exchange_sha1, + &kex_method_diffie_helman_group1_sha1, + NULL +}; + +typedef struct _LIBSSH2_COMMON_METHOD +{ + const char *name; +} LIBSSH2_COMMON_METHOD; + +/* kex_method_strlen + * Calculate the length of a particular method list's resulting string + * Includes SUM(strlen() of each individual method plus 1 (for coma)) - 1 (because the last coma isn't used) + * Another sign of bad coding practices gone mad. Pretend you don't see this. + */ +static size_t +kex_method_strlen(LIBSSH2_COMMON_METHOD ** method) +{ + size_t len = 0; + + if (!method || !*method) { + return 0; + } + + while (*method && (*method)->name) { + len += strlen((*method)->name) + 1; + method++; + } + + return len - 1; +} + + + +/* kex_method_list + * Generate formatted preference list in buf + */ +static size_t +kex_method_list(unsigned char *buf, size_t list_strlen, + LIBSSH2_COMMON_METHOD ** method) +{ + _libssh2_htonu32(buf, list_strlen); + buf += 4; + + if (!method || !*method) { + return 4; + } + + while (*method && (*method)->name) { + int mlen = strlen((*method)->name); + memcpy(buf, (*method)->name, mlen); + buf += mlen; + *(buf++) = ','; + method++; + } + + return list_strlen + 4; +} + + + +#define LIBSSH2_METHOD_PREFS_LEN(prefvar, defaultvar) \ + ((prefvar) ? strlen(prefvar) : \ + kex_method_strlen((LIBSSH2_COMMON_METHOD**)(defaultvar))) + +#define LIBSSH2_METHOD_PREFS_STR(buf, prefvarlen, prefvar, defaultvar) \ + if (prefvar) { \ + _libssh2_htonu32((buf), (prefvarlen)); \ + buf += 4; \ + memcpy((buf), (prefvar), (prefvarlen)); \ + buf += (prefvarlen); \ + } else { \ + buf += kex_method_list((buf), (prefvarlen), \ + (LIBSSH2_COMMON_METHOD**)(defaultvar)); \ + } + +/* kexinit + * Send SSH_MSG_KEXINIT packet + */ +static int kexinit(LIBSSH2_SESSION * session) +{ + /* 62 = packet_type(1) + cookie(16) + first_packet_follows(1) + + reserved(4) + length longs(40) */ + size_t data_len = 62; + size_t kex_len, hostkey_len = 0; + size_t crypt_cs_len, crypt_sc_len; + size_t comp_cs_len, comp_sc_len; + size_t mac_cs_len, mac_sc_len; + size_t lang_cs_len, lang_sc_len; + unsigned char *data, *s; + int rc; + + if (session->kexinit_state == libssh2_NB_state_idle) { + kex_len = + LIBSSH2_METHOD_PREFS_LEN(session->kex_prefs, libssh2_kex_methods); + hostkey_len = + LIBSSH2_METHOD_PREFS_LEN(session->hostkey_prefs, + libssh2_hostkey_methods()); + crypt_cs_len = + LIBSSH2_METHOD_PREFS_LEN(session->local.crypt_prefs, + libssh2_crypt_methods()); + crypt_sc_len = + LIBSSH2_METHOD_PREFS_LEN(session->remote.crypt_prefs, + libssh2_crypt_methods()); + mac_cs_len = + LIBSSH2_METHOD_PREFS_LEN(session->local.mac_prefs, + _libssh2_mac_methods()); + mac_sc_len = + LIBSSH2_METHOD_PREFS_LEN(session->remote.mac_prefs, + _libssh2_mac_methods()); + comp_cs_len = + LIBSSH2_METHOD_PREFS_LEN(session->local.comp_prefs, + _libssh2_comp_methods(session)); + comp_sc_len = + LIBSSH2_METHOD_PREFS_LEN(session->remote.comp_prefs, + _libssh2_comp_methods(session)); + lang_cs_len = + LIBSSH2_METHOD_PREFS_LEN(session->local.lang_prefs, NULL); + lang_sc_len = + LIBSSH2_METHOD_PREFS_LEN(session->remote.lang_prefs, NULL); + + data_len += kex_len + hostkey_len + crypt_cs_len + crypt_sc_len + + comp_cs_len + comp_sc_len + mac_cs_len + mac_sc_len + + lang_cs_len + lang_sc_len; + + s = data = LIBSSH2_ALLOC(session, data_len); + if (!data) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory"); + } + + *(s++) = SSH_MSG_KEXINIT; + + _libssh2_random(s, 16); + s += 16; + + /* Ennumerating through these lists twice is probably (certainly?) + inefficient from a CPU standpoint, but it saves multiple + malloc/realloc calls */ + LIBSSH2_METHOD_PREFS_STR(s, kex_len, session->kex_prefs, + libssh2_kex_methods); + LIBSSH2_METHOD_PREFS_STR(s, hostkey_len, session->hostkey_prefs, + libssh2_hostkey_methods()); + LIBSSH2_METHOD_PREFS_STR(s, crypt_cs_len, session->local.crypt_prefs, + libssh2_crypt_methods()); + LIBSSH2_METHOD_PREFS_STR(s, crypt_sc_len, session->remote.crypt_prefs, + libssh2_crypt_methods()); + LIBSSH2_METHOD_PREFS_STR(s, mac_cs_len, session->local.mac_prefs, + _libssh2_mac_methods()); + LIBSSH2_METHOD_PREFS_STR(s, mac_sc_len, session->remote.mac_prefs, + _libssh2_mac_methods()); + LIBSSH2_METHOD_PREFS_STR(s, comp_cs_len, session->local.comp_prefs, + _libssh2_comp_methods(session)); + LIBSSH2_METHOD_PREFS_STR(s, comp_sc_len, session->remote.comp_prefs, + _libssh2_comp_methods(session)); + LIBSSH2_METHOD_PREFS_STR(s, lang_cs_len, session->local.lang_prefs, + NULL); + LIBSSH2_METHOD_PREFS_STR(s, lang_sc_len, session->remote.lang_prefs, + NULL); + + /* No optimistic KEX packet follows */ + /* Deal with optimistic packets + * session->flags |= KEXINIT_OPTIMISTIC + * session->flags |= KEXINIT_METHODSMATCH + */ + *(s++) = 0; + + /* Reserved == 0 */ + _libssh2_htonu32(s, 0); + +#ifdef LIBSSH2DEBUG + { + /* Funnily enough, they'll all "appear" to be '\0' terminated */ + unsigned char *p = data + 21; /* type(1) + cookie(16) + len(4) */ + + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent KEX: %s", p); + p += kex_len + 4; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent HOSTKEY: %s", p); + p += hostkey_len + 4; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_CS: %s", p); + p += crypt_cs_len + 4; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent CRYPT_SC: %s", p); + p += crypt_sc_len + 4; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_CS: %s", p); + p += mac_cs_len + 4; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent MAC_SC: %s", p); + p += mac_sc_len + 4; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_CS: %s", p); + p += comp_cs_len + 4; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent COMP_SC: %s", p); + p += comp_sc_len + 4; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_CS: %s", p); + p += lang_cs_len + 4; + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Sent LANG_SC: %s", p); + p += lang_sc_len + 4; + } +#endif /* LIBSSH2DEBUG */ + + session->kexinit_state = libssh2_NB_state_created; + } else { + data = session->kexinit_data; + data_len = session->kexinit_data_len; + /* zap the variables to ensure there is NOT a double free later */ + session->kexinit_data = NULL; + session->kexinit_data_len = 0; + } + + rc = _libssh2_transport_send(session, data, data_len, NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + session->kexinit_data = data; + session->kexinit_data_len = data_len; + return rc; + } + else if (rc) { + LIBSSH2_FREE(session, data); + session->kexinit_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Unable to send KEXINIT packet to remote host"); + + } + + if (session->local.kexinit) { + LIBSSH2_FREE(session, session->local.kexinit); + } + + session->local.kexinit = data; + session->local.kexinit_len = data_len; + + session->kexinit_state = libssh2_NB_state_idle; + + return 0; +} + +/* kex_agree_instr + * Kex specific variant of strstr() + * Needle must be preceed by BOL or ',', and followed by ',' or EOL + */ +static unsigned char * +kex_agree_instr(unsigned char *haystack, unsigned long haystack_len, + const unsigned char *needle, unsigned long needle_len) +{ + unsigned char *s; + + /* Haystack too short to bother trying */ + if (haystack_len < needle_len) { + return NULL; + } + + /* Needle at start of haystack */ + if ((strncmp((char *) haystack, (char *) needle, needle_len) == 0) && + (needle_len == haystack_len || haystack[needle_len] == ',')) { + return haystack; + } + + s = haystack; + /* Search until we run out of comas or we run out of haystack, + whichever comes first */ + while ((s = (unsigned char *) strchr((char *) s, ',')) + && ((haystack_len - (s - haystack)) > needle_len)) { + s++; + /* Needle at X position */ + if ((strncmp((char *) s, (char *) needle, needle_len) == 0) && + (((s - haystack) + needle_len) == haystack_len + || s[needle_len] == ',')) { + return s; + } + } + + return NULL; +} + + + +/* kex_get_method_by_name + */ +static const LIBSSH2_COMMON_METHOD * +kex_get_method_by_name(const char *name, size_t name_len, + const LIBSSH2_COMMON_METHOD ** methodlist) +{ + while (*methodlist) { + if ((strlen((*methodlist)->name) == name_len) && + (strncmp((*methodlist)->name, name, name_len) == 0)) { + return *methodlist; + } + methodlist++; + } + return NULL; +} + + + +/* kex_agree_hostkey + * Agree on a Hostkey which works with this kex + */ +static int kex_agree_hostkey(LIBSSH2_SESSION * session, + unsigned long kex_flags, + unsigned char *hostkey, unsigned long hostkey_len) +{ + const LIBSSH2_HOSTKEY_METHOD **hostkeyp = libssh2_hostkey_methods(); + unsigned char *s; + + if (session->hostkey_prefs) { + s = (unsigned char *) session->hostkey_prefs; + + while (s && *s) { + unsigned char *p = (unsigned char *) strchr((char *) s, ','); + size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); + if (kex_agree_instr(hostkey, hostkey_len, s, method_len)) { + const LIBSSH2_HOSTKEY_METHOD *method = + (const LIBSSH2_HOSTKEY_METHOD *) + kex_get_method_by_name((char *) s, method_len, + (const LIBSSH2_COMMON_METHOD **) + hostkeyp); + + if (!method) { + /* Invalid method -- Should never be reached */ + return -1; + } + + /* So far so good, but does it suit our purposes? (Encrypting + vs Signing) */ + if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == + 0) || (method->encrypt)) { + /* Either this hostkey can do encryption or this kex just + doesn't require it */ + if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) + == 0) || (method->sig_verify)) { + /* Either this hostkey can do signing or this kex just + doesn't require it */ + session->hostkey = method; + return 0; + } + } + } + + s = p ? p + 1 : NULL; + } + return -1; + } + + while (hostkeyp && (*hostkeyp) && (*hostkeyp)->name) { + s = kex_agree_instr(hostkey, hostkey_len, + (unsigned char *) (*hostkeyp)->name, + strlen((*hostkeyp)->name)); + if (s) { + /* So far so good, but does it suit our purposes? (Encrypting vs + Signing) */ + if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_ENC_HOSTKEY) == 0) || + ((*hostkeyp)->encrypt)) { + /* Either this hostkey can do encryption or this kex just + doesn't require it */ + if (((kex_flags & LIBSSH2_KEX_METHOD_FLAG_REQ_SIGN_HOSTKEY) == + 0) || ((*hostkeyp)->sig_verify)) { + /* Either this hostkey can do signing or this kex just + doesn't require it */ + session->hostkey = *hostkeyp; + return 0; + } + } + } + hostkeyp++; + } + + return -1; +} + + + +/* kex_agree_kex_hostkey + * Agree on a Key Exchange method and a hostkey encoding type + */ +static int kex_agree_kex_hostkey(LIBSSH2_SESSION * session, unsigned char *kex, + unsigned long kex_len, unsigned char *hostkey, + unsigned long hostkey_len) +{ + const LIBSSH2_KEX_METHOD **kexp = libssh2_kex_methods; + unsigned char *s; + + if (session->kex_prefs) { + s = (unsigned char *) session->kex_prefs; + + while (s && *s) { + unsigned char *q, *p = (unsigned char *) strchr((char *) s, ','); + size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); + if ((q = kex_agree_instr(kex, kex_len, s, method_len))) { + const LIBSSH2_KEX_METHOD *method = (const LIBSSH2_KEX_METHOD *) + kex_get_method_by_name((char *) s, method_len, + (const LIBSSH2_COMMON_METHOD **) + kexp); + + if (!method) { + /* Invalid method -- Should never be reached */ + return -1; + } + + /* We've agreed on a key exchange method, + * Can we agree on a hostkey that works with this kex? + */ + if (kex_agree_hostkey(session, method->flags, hostkey, + hostkey_len) == 0) { + session->kex = method; + if (session->burn_optimistic_kexinit && (kex == q)) { + /* Server sent an optimistic packet, + * and client agrees with preference + * cancel burning the first KEX_INIT packet that comes in */ + session->burn_optimistic_kexinit = 0; + } + return 0; + } + } + + s = p ? p + 1 : NULL; + } + return -1; + } + + while (*kexp && (*kexp)->name) { + s = kex_agree_instr(kex, kex_len, + (unsigned char *) (*kexp)->name, + strlen((*kexp)->name)); + if (s) { + /* We've agreed on a key exchange method, + * Can we agree on a hostkey that works with this kex? + */ + if (kex_agree_hostkey(session, (*kexp)->flags, hostkey, + hostkey_len) == 0) { + session->kex = *kexp; + if (session->burn_optimistic_kexinit && (kex == s)) { + /* Server sent an optimistic packet, + * and client agrees with preference + * cancel burning the first KEX_INIT packet that comes in */ + session->burn_optimistic_kexinit = 0; + } + return 0; + } + } + kexp++; + } + return -1; +} + + + +/* kex_agree_crypt + * Agree on a cipher algo + */ +static int kex_agree_crypt(LIBSSH2_SESSION * session, + libssh2_endpoint_data *endpoint, + unsigned char *crypt, + unsigned long crypt_len) +{ + const LIBSSH2_CRYPT_METHOD **cryptp = libssh2_crypt_methods(); + unsigned char *s; + + (void) session; + + if (endpoint->crypt_prefs) { + s = (unsigned char *) endpoint->crypt_prefs; + + while (s && *s) { + unsigned char *p = (unsigned char *) strchr((char *) s, ','); + size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); + + if (kex_agree_instr(crypt, crypt_len, s, method_len)) { + const LIBSSH2_CRYPT_METHOD *method = + (const LIBSSH2_CRYPT_METHOD *) + kex_get_method_by_name((char *) s, method_len, + (const LIBSSH2_COMMON_METHOD **) + cryptp); + + if (!method) { + /* Invalid method -- Should never be reached */ + return -1; + } + + endpoint->crypt = method; + return 0; + } + + s = p ? p + 1 : NULL; + } + return -1; + } + + while (*cryptp && (*cryptp)->name) { + s = kex_agree_instr(crypt, crypt_len, + (unsigned char *) (*cryptp)->name, + strlen((*cryptp)->name)); + if (s) { + endpoint->crypt = *cryptp; + return 0; + } + cryptp++; + } + + return -1; +} + + + +/* kex_agree_mac + * Agree on a message authentication hash + */ +static int kex_agree_mac(LIBSSH2_SESSION * session, + libssh2_endpoint_data * endpoint, unsigned char *mac, + unsigned long mac_len) +{ + const LIBSSH2_MAC_METHOD **macp = _libssh2_mac_methods(); + unsigned char *s; + (void) session; + + if (endpoint->mac_prefs) { + s = (unsigned char *) endpoint->mac_prefs; + + while (s && *s) { + unsigned char *p = (unsigned char *) strchr((char *) s, ','); + size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); + + if (kex_agree_instr(mac, mac_len, s, method_len)) { + const LIBSSH2_MAC_METHOD *method = (const LIBSSH2_MAC_METHOD *) + kex_get_method_by_name((char *) s, method_len, + (const LIBSSH2_COMMON_METHOD **) + macp); + + if (!method) { + /* Invalid method -- Should never be reached */ + return -1; + } + + endpoint->mac = method; + return 0; + } + + s = p ? p + 1 : NULL; + } + return -1; + } + + while (*macp && (*macp)->name) { + s = kex_agree_instr(mac, mac_len, (unsigned char *) (*macp)->name, + strlen((*macp)->name)); + if (s) { + endpoint->mac = *macp; + return 0; + } + macp++; + } + + return -1; +} + + + +/* kex_agree_comp + * Agree on a compression scheme + */ +static int kex_agree_comp(LIBSSH2_SESSION *session, + libssh2_endpoint_data *endpoint, unsigned char *comp, + unsigned long comp_len) +{ + const LIBSSH2_COMP_METHOD **compp = _libssh2_comp_methods(session); + unsigned char *s; + (void) session; + + if (endpoint->comp_prefs) { + s = (unsigned char *) endpoint->comp_prefs; + + while (s && *s) { + unsigned char *p = (unsigned char *) strchr((char *) s, ','); + size_t method_len = (p ? (size_t)(p - s) : strlen((char *) s)); + + if (kex_agree_instr(comp, comp_len, s, method_len)) { + const LIBSSH2_COMP_METHOD *method = + (const LIBSSH2_COMP_METHOD *) + kex_get_method_by_name((char *) s, method_len, + (const LIBSSH2_COMMON_METHOD **) + compp); + + if (!method) { + /* Invalid method -- Should never be reached */ + return -1; + } + + endpoint->comp = method; + return 0; + } + + s = p ? p + 1 : NULL; + } + return -1; + } + + while (*compp && (*compp)->name) { + s = kex_agree_instr(comp, comp_len, (unsigned char *) (*compp)->name, + strlen((*compp)->name)); + if (s) { + endpoint->comp = *compp; + return 0; + } + compp++; + } + + return -1; +} + + + +/* TODO: When in server mode we need to turn this logic on its head + * The Client gets to make the final call on "agreed methods" + */ + +/* kex_agree_methods + * Decide which specific method to use of the methods offered by each party + */ +static int kex_agree_methods(LIBSSH2_SESSION * session, unsigned char *data, + unsigned data_len) +{ + unsigned char *kex, *hostkey, *crypt_cs, *crypt_sc, *comp_cs, *comp_sc, + *mac_cs, *mac_sc; + size_t kex_len, hostkey_len, crypt_cs_len, crypt_sc_len, comp_cs_len; + size_t comp_sc_len, mac_cs_len, mac_sc_len; + unsigned char *s = data; + + /* Skip packet_type, we know it already */ + s++; + + /* Skip cookie, don't worry, it's preserved in the kexinit field */ + s += 16; + + /* Locate each string */ + kex_len = _libssh2_ntohu32(s); + kex = s + 4; + s += 4 + kex_len; + hostkey_len = _libssh2_ntohu32(s); + hostkey = s + 4; + s += 4 + hostkey_len; + crypt_cs_len = _libssh2_ntohu32(s); + crypt_cs = s + 4; + s += 4 + crypt_cs_len; + crypt_sc_len = _libssh2_ntohu32(s); + crypt_sc = s + 4; + s += 4 + crypt_sc_len; + mac_cs_len = _libssh2_ntohu32(s); + mac_cs = s + 4; + s += 4 + mac_cs_len; + mac_sc_len = _libssh2_ntohu32(s); + mac_sc = s + 4; + s += 4 + mac_sc_len; + comp_cs_len = _libssh2_ntohu32(s); + comp_cs = s + 4; + s += 4 + comp_cs_len; + comp_sc_len = _libssh2_ntohu32(s); + comp_sc = s + 4; +#if 0 + s += 4 + comp_sc_len; + lang_cs_len = _libssh2_ntohu32(s); + lang_cs = s + 4; + s += 4 + lang_cs_len; + lang_sc_len = _libssh2_ntohu32(s); + lang_sc = s + 4; + s += 4 + lang_sc_len; +#endif + /* If the server sent an optimistic packet, assume that it guessed wrong. + * If the guess is determined to be right (by kex_agree_kex_hostkey) + * This flag will be reset to zero so that it's not ignored */ + session->burn_optimistic_kexinit = *(s++); + /* Next uint32 in packet is all zeros (reserved) */ + + if (data_len < (unsigned) (s - data)) + return -1; /* short packet */ + + if (kex_agree_kex_hostkey(session, kex, kex_len, hostkey, hostkey_len)) { + return -1; + } + + if (kex_agree_crypt(session, &session->local, crypt_cs, crypt_cs_len) + || kex_agree_crypt(session, &session->remote, crypt_sc, crypt_sc_len)) { + return -1; + } + + if (kex_agree_mac(session, &session->local, mac_cs, mac_cs_len) || + kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) { + return -1; + } + + if (kex_agree_comp(session, &session->local, comp_cs, comp_cs_len) || + kex_agree_comp(session, &session->remote, comp_sc, comp_sc_len)) { + return -1; + } + +#if 0 + if (libssh2_kex_agree_lang(session, &session->local, lang_cs, lang_cs_len) + || libssh2_kex_agree_lang(session, &session->remote, lang_sc, + lang_sc_len)) { + return -1; + } +#endif + + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on KEX method: %s", + session->kex->name); + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on HOSTKEY method: %s", + session->hostkey->name); + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_CS method: %s", + session->local.crypt->name); + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on CRYPT_SC method: %s", + session->remote.crypt->name); + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_CS method: %s", + session->local.mac->name); + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on MAC_SC method: %s", + session->remote.mac->name); + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on COMP_CS method: %s", + session->local.comp->name); + _libssh2_debug(session, LIBSSH2_TRACE_KEX, "Agreed on COMP_SC method: %s", + session->remote.comp->name); + + return 0; +} + + + +/* _libssh2_kex_exchange + * Exchange keys + * Returns 0 on success, non-zero on failure + * + * Returns some errors without _libssh2_error() + */ +int +_libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, + key_exchange_state_t * key_state) +{ + int rc = 0; + int retcode; + + session->state |= LIBSSH2_STATE_KEX_ACTIVE; + + if (key_state->state == libssh2_NB_state_idle) { + /* Prevent loop in packet_add() */ + session->state |= LIBSSH2_STATE_EXCHANGING_KEYS; + + if (reexchange) { + session->kex = NULL; + + if (session->hostkey && session->hostkey->dtor) { + session->hostkey->dtor(session, + &session->server_hostkey_abstract); + } + session->hostkey = NULL; + } + + key_state->state = libssh2_NB_state_created; + } + + if (!session->kex || !session->hostkey) { + if (key_state->state == libssh2_NB_state_created) { + /* Preserve in case of failure */ + key_state->oldlocal = session->local.kexinit; + key_state->oldlocal_len = session->local.kexinit_len; + + session->local.kexinit = NULL; + + key_state->state = libssh2_NB_state_sent; + } + + if (key_state->state == libssh2_NB_state_sent) { + retcode = kexinit(session); + if (retcode == LIBSSH2_ERROR_EAGAIN) { + session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; + return retcode; + } else if (retcode) { + session->local.kexinit = key_state->oldlocal; + session->local.kexinit_len = key_state->oldlocal_len; + key_state->state = libssh2_NB_state_idle; + session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; + session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; + return -1; + } + + key_state->state = libssh2_NB_state_sent1; + } + + if (key_state->state == libssh2_NB_state_sent1) { + retcode = + _libssh2_packet_require(session, SSH_MSG_KEXINIT, + &key_state->data, + &key_state->data_len, 0, NULL, 0, + &key_state->req_state); + if (retcode == LIBSSH2_ERROR_EAGAIN) { + session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; + return retcode; + } + else if (retcode) { + if (session->local.kexinit) { + LIBSSH2_FREE(session, session->local.kexinit); + } + session->local.kexinit = key_state->oldlocal; + session->local.kexinit_len = key_state->oldlocal_len; + key_state->state = libssh2_NB_state_idle; + session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; + session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; + return -1; + } + + if (session->remote.kexinit) { + LIBSSH2_FREE(session, session->remote.kexinit); + } + session->remote.kexinit = key_state->data; + session->remote.kexinit_len = key_state->data_len; + + if (kex_agree_methods(session, key_state->data, + key_state->data_len)) + rc = LIBSSH2_ERROR_KEX_FAILURE; + + key_state->state = libssh2_NB_state_sent2; + } + } else { + key_state->state = libssh2_NB_state_sent2; + } + + if (rc == 0) { + if (key_state->state == libssh2_NB_state_sent2) { + retcode = session->kex->exchange_keys(session, + &key_state->key_state_low); + if (retcode == LIBSSH2_ERROR_EAGAIN) { + session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; + return retcode; + } else if (retcode) { + rc = _libssh2_error(session, LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE, + "Unrecoverable error exchanging keys"); + } + } + } + + /* Done with kexinit buffers */ + if (session->local.kexinit) { + LIBSSH2_FREE(session, session->local.kexinit); + session->local.kexinit = NULL; + } + if (session->remote.kexinit) { + LIBSSH2_FREE(session, session->remote.kexinit); + session->remote.kexinit = NULL; + } + + session->state &= ~LIBSSH2_STATE_KEX_ACTIVE; + session->state &= ~LIBSSH2_STATE_EXCHANGING_KEYS; + + key_state->state = libssh2_NB_state_idle; + + return rc; +} + + + +/* libssh2_session_method_pref + * Set preferred method + */ +LIBSSH2_API int +libssh2_session_method_pref(LIBSSH2_SESSION * session, int method_type, + const char *prefs) +{ + char **prefvar, *s, *newprefs; + int prefs_len = strlen(prefs); + const LIBSSH2_COMMON_METHOD **mlist; + + switch (method_type) { + case LIBSSH2_METHOD_KEX: + prefvar = &session->kex_prefs; + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods; + break; + + case LIBSSH2_METHOD_HOSTKEY: + prefvar = &session->hostkey_prefs; + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods(); + break; + + case LIBSSH2_METHOD_CRYPT_CS: + prefvar = &session->local.crypt_prefs; + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); + break; + + case LIBSSH2_METHOD_CRYPT_SC: + prefvar = &session->remote.crypt_prefs; + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); + break; + + case LIBSSH2_METHOD_MAC_CS: + prefvar = &session->local.mac_prefs; + mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); + break; + + case LIBSSH2_METHOD_MAC_SC: + prefvar = &session->remote.mac_prefs; + mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); + break; + + case LIBSSH2_METHOD_COMP_CS: + prefvar = &session->local.comp_prefs; + mlist = (const LIBSSH2_COMMON_METHOD **) + _libssh2_comp_methods(session); + break; + + case LIBSSH2_METHOD_COMP_SC: + prefvar = &session->remote.comp_prefs; + mlist = (const LIBSSH2_COMMON_METHOD **) + _libssh2_comp_methods(session); + break; + + case LIBSSH2_METHOD_LANG_CS: + prefvar = &session->local.lang_prefs; + mlist = NULL; + break; + + case LIBSSH2_METHOD_LANG_SC: + prefvar = &session->remote.lang_prefs; + mlist = NULL; + break; + + default: + return _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "Invalid parameter specified for method_type"); + } + + s = newprefs = LIBSSH2_ALLOC(session, prefs_len + 1); + if (!newprefs) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Error allocated space for method preferences"); + } + memcpy(s, prefs, prefs_len + 1); + + while (s && *s) { + char *p = strchr(s, ','); + int method_len = p ? (p - s) : (int) strlen(s); + + if (!kex_get_method_by_name(s, method_len, mlist)) { + /* Strip out unsupported method */ + if (p) { + memcpy(s, p + 1, strlen(s) - method_len); + } else { + if (s > newprefs) { + *(--s) = '\0'; + } else { + *s = '\0'; + } + } + } + + s = p ? (p + 1) : NULL; + } + + if (strlen(newprefs) == 0) { + LIBSSH2_FREE(session, newprefs); + return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "The requested method(s) are not currently " + "supported"); + } + + if (*prefvar) { + LIBSSH2_FREE(session, *prefvar); + } + *prefvar = newprefs; + + return 0; +} + +/* + * libssh2_session_supported_algs() + * returns a number of returned algorithms (a positive number) on success, + * a negative number on failure + */ + +LIBSSH2_API int libssh2_session_supported_algs(LIBSSH2_SESSION* session, + int method_type, + const char*** algs) +{ + unsigned int i; + unsigned int j; + unsigned int ialg; + const LIBSSH2_COMMON_METHOD **mlist; + + /* to prevent coredumps due to dereferencing of NULL */ + if (NULL == algs) + return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, + "algs must not be NULL"); + + switch (method_type) { + case LIBSSH2_METHOD_KEX: + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_kex_methods; + break; + + case LIBSSH2_METHOD_HOSTKEY: + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_hostkey_methods(); + break; + + case LIBSSH2_METHOD_CRYPT_CS: + case LIBSSH2_METHOD_CRYPT_SC: + mlist = (const LIBSSH2_COMMON_METHOD **) libssh2_crypt_methods(); + break; + + case LIBSSH2_METHOD_MAC_CS: + case LIBSSH2_METHOD_MAC_SC: + mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_mac_methods(); + break; + + case LIBSSH2_METHOD_COMP_CS: + case LIBSSH2_METHOD_COMP_SC: + mlist = (const LIBSSH2_COMMON_METHOD **) _libssh2_comp_methods(session); + break; + + default: + return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Unknown method type"); + } /* switch */ + + /* weird situation */ + if (NULL==mlist) + return _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "No algorithm found"); + + /* + mlist is looped through twice. The first time to find the number od + supported algorithms (needed to allocate the proper size of array) and + the second time to actually copy the pointers. Typically this function + will not be called often (typically at the beginning of a session) and + the number of algorithms (i.e. niumber of iterations in one loop) will + not be high (typically it will not exceed 20) for quite a long time. + + So double looping really shouldn't be an issue and it is definitely a + better solution than reallocation several times. + */ + + /* count the number of supported algorithms */ + for ( i=0, ialg=0; NULL!=mlist[i]; i++) { + /* do not count fields with NULL name */ + if (mlist[i]->name) + ialg++; + } + + /* weird situation, no algorithm found */ + if (0==ialg) + return _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "No algorithm found"); + + /* allocate buffer */ + *algs = (const char**) LIBSSH2_ALLOC(session, ialg*sizeof(const char*)); + if ( NULL==*algs ) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Memory allocation failed"); + } + /* Past this point *algs must be deallocated in case of an error!! */ + + /* copy non-NULL pointers only */ + for ( i=0, j=0; NULL!=mlist[i] && jname ){ + /* maybe a weird situation but if it occurs, do not include NULL + pointers */ + continue; + } + + /* note that [] has higher priority than * (dereferencing) */ + (*algs)[j++] = mlist[i]->name; + } + + /* correct number of pointers copied? (test the code above) */ + if ( j!=ialg ) { + /* deallocate buffer */ + LIBSSH2_FREE(session, (void *)*algs); + *algs = NULL; + + return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, + "Internal error"); + } + + return ialg; +} diff --git a/vendor/libssh2-1.4.2/src/knownhost.c b/vendor/libssh2-1.4.2/src/knownhost.c new file mode 100644 index 0000000..c58dfbb --- /dev/null +++ b/vendor/libssh2-1.4.2/src/knownhost.c @@ -0,0 +1,1146 @@ +/* + * Copyright (c) 2009-2011 by Daniel Stenberg + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" +#include "misc.h" + +struct known_host { + struct list_node node; + char *name; /* points to the name or the hash (allocated) */ + size_t name_len; /* needed for hashed data */ + int port; /* if non-zero, a specific port this key is for on this + host */ + int typemask; /* plain, sha1, custom, ... */ + char *salt; /* points to binary salt (allocated) */ + size_t salt_len; /* size of salt */ + char *key; /* the (allocated) associated key. This is kept base64 + encoded in memory. */ + char *comment; /* the (allocated) optional comment text, may be NULL */ + + /* this is the struct we expose externally */ + struct libssh2_knownhost external; +}; + +struct _LIBSSH2_KNOWNHOSTS +{ + LIBSSH2_SESSION *session; /* the session this "belongs to" */ + struct list_head head; +}; + +static void free_host(LIBSSH2_SESSION *session, struct known_host *entry) +{ + if(entry) { + if(entry->comment) + LIBSSH2_FREE(session, entry->comment); + if(entry->key) + LIBSSH2_FREE(session, entry->key); + if(entry->salt) + LIBSSH2_FREE(session, entry->salt); + if(entry->name) + LIBSSH2_FREE(session, entry->name); + LIBSSH2_FREE(session, entry); + } +} + +/* + * libssh2_knownhost_init + * + * Init a collection of known hosts. Returns the pointer to a collection. + * + */ +LIBSSH2_API LIBSSH2_KNOWNHOSTS * +libssh2_knownhost_init(LIBSSH2_SESSION *session) +{ + LIBSSH2_KNOWNHOSTS *knh = + LIBSSH2_ALLOC(session, sizeof(struct _LIBSSH2_KNOWNHOSTS)); + + if(!knh) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for known-hosts " + "collection"); + return NULL; + } + + knh->session = session; + + _libssh2_list_init(&knh->head); + + return knh; +} + +#define KNOWNHOST_MAGIC 0xdeadcafe +/* + * knownhost_to_external() + * + * Copies data from the internal to the external representation struct. + * + */ +static struct libssh2_knownhost *knownhost_to_external(struct known_host *node) +{ + struct libssh2_knownhost *ext = &node->external; + + ext->magic = KNOWNHOST_MAGIC; + ext->node = node; + ext->name = ((node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) == + LIBSSH2_KNOWNHOST_TYPE_PLAIN)? node->name:NULL; + ext->key = node->key; + ext->typemask = node->typemask; + + return ext; +} + +static int +knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, + const char *host, const char *salt, + const char *key, size_t keylen, + const char *comment, size_t commentlen, + int typemask, struct libssh2_knownhost **store) +{ + struct known_host *entry; + size_t hostlen = strlen(host); + int rc; + char *ptr; + unsigned int ptrlen; + + /* make sure we have a key type set */ + if(!(typemask & LIBSSH2_KNOWNHOST_KEY_MASK)) + return _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL, + "No key type set"); + + if(!(entry = LIBSSH2_ALLOC(hosts->session, sizeof(struct known_host)))) + return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for known host " + "entry"); + + memset(entry, 0, sizeof(struct known_host)); + + entry->typemask = typemask; + + switch(entry->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) { + case LIBSSH2_KNOWNHOST_TYPE_PLAIN: + case LIBSSH2_KNOWNHOST_TYPE_CUSTOM: + entry->name = LIBSSH2_ALLOC(hosts->session, hostlen+1); + if(!entry->name) { + rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for host name"); + goto error; + } + memcpy(entry->name, host, hostlen+1); + break; + case LIBSSH2_KNOWNHOST_TYPE_SHA1: + rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen, + host, hostlen); + if(rc) + goto error; + entry->name = ptr; + entry->name_len = ptrlen; + + rc = libssh2_base64_decode(hosts->session, &ptr, &ptrlen, + salt, strlen(salt)); + if(rc) + goto error; + entry->salt = ptr; + entry->salt_len = ptrlen; + break; + default: + rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Unknown host name type"); + goto error; + } + + if(typemask & LIBSSH2_KNOWNHOST_KEYENC_BASE64) { + /* the provided key is base64 encoded already */ + if(!keylen) + keylen = strlen(key); + entry->key = LIBSSH2_ALLOC(hosts->session, keylen+1); + if(!entry->key) { + rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for key"); + goto error; + } + memcpy(entry->key, key, keylen+1); + entry->key[keylen]=0; /* force a terminating zero trailer */ + } + else { + /* key is raw, we base64 encode it and store it as such */ + size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen, + &ptr); + if(!nlen) { + rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "base64-encoded key"); + goto error; + } + + entry->key = ptr; + } + + if (comment) { + entry->comment = LIBSSH2_ALLOC(hosts->session, commentlen+1); + if(!entry->comment) { + rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for comment"); + goto error; + } + memcpy(entry->comment, comment, commentlen+1); + entry->comment[commentlen]=0; /* force a terminating zero trailer */ + } + else { + entry->comment = NULL; + } + + /* add this new host to the big list of known hosts */ + _libssh2_list_add(&hosts->head, &entry->node); + + if(store) + *store = knownhost_to_external(entry); + + return LIBSSH2_ERROR_NONE; + error: + free_host(hosts->session, entry); + return rc; +} + +/* + * libssh2_knownhost_add + * + * Add a host and its associated key to the collection of known hosts. + * + * The 'type' argument specifies on what format the given host and keys are: + * + * plain - ascii "hostname.domain.tld" + * sha1 - SHA1( ) base64-encoded! + * custom - another hash + * + * If 'sha1' is selected as type, the salt must be provided to the salt + * argument. This too base64 encoded. + * + * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If + * a custom type is used, salt is ignored and you must provide the host + * pre-hashed when checking for it in the libssh2_knownhost_check() function. + * + * The keylen parameter may be omitted (zero) if the key is provided as a + * NULL-terminated base64-encoded string. + */ + +LIBSSH2_API int +libssh2_knownhost_add(LIBSSH2_KNOWNHOSTS *hosts, + const char *host, const char *salt, + const char *key, size_t keylen, + int typemask, struct libssh2_knownhost **store) +{ + return knownhost_add(hosts, host, salt, key, keylen, NULL, 0, typemask, + store); +} + + +/* + * libssh2_knownhost_addc + * + * Add a host and its associated key to the collection of known hosts. + * + * Takes a comment argument that may be NULL. A NULL comment indicates + * there is no comment and the entry will end directly after the key + * when written out to a file. An empty string "" comment will indicate an + * empty comment which will cause a single space to be written after the key. + * + * The 'type' argument specifies on what format the given host and keys are: + * + * plain - ascii "hostname.domain.tld" + * sha1 - SHA1( ) base64-encoded! + * custom - another hash + * + * If 'sha1' is selected as type, the salt must be provided to the salt + * argument. This too base64 encoded. + * + * The SHA-1 hash is what OpenSSH can be told to use in known_hosts files. If + * a custom type is used, salt is ignored and you must provide the host + * pre-hashed when checking for it in the libssh2_knownhost_check() function. + * + * The keylen parameter may be omitted (zero) if the key is provided as a + * NULL-terminated base64-encoded string. + */ + +LIBSSH2_API int +libssh2_knownhost_addc(LIBSSH2_KNOWNHOSTS *hosts, + const char *host, const char *salt, + const char *key, size_t keylen, + const char *comment, size_t commentlen, + int typemask, struct libssh2_knownhost **store) +{ + return knownhost_add(hosts, host, salt, key, keylen, comment, commentlen, + typemask, store); +} + +/* + * knownhost_check + * + * Check a host and its associated key against the collection of known hosts. + * + * The typemask is the type/format of the given host name and key + * + * plain - ascii "hostname.domain.tld" + * sha1 - NOT SUPPORTED AS INPUT + * custom - prehashed base64 encoded. Note that this cannot use any salts. + * + * Returns: + * + * LIBSSH2_KNOWNHOST_CHECK_FAILURE + * LIBSSH2_KNOWNHOST_CHECK_NOTFOUND + * LIBSSH2_KNOWNHOST_CHECK_MATCH + * LIBSSH2_KNOWNHOST_CHECK_MISMATCH + */ +static int +knownhost_check(LIBSSH2_KNOWNHOSTS *hosts, + const char *hostp, int port, + const char *key, size_t keylen, + int typemask, + struct libssh2_knownhost **ext) +{ + struct known_host *node; + struct known_host *badkey = NULL; + int type = typemask & LIBSSH2_KNOWNHOST_TYPE_MASK; + char *keyalloc = NULL; + int rc = LIBSSH2_KNOWNHOST_CHECK_NOTFOUND; + char hostbuff[270]; /* most host names can't be longer than like 256 */ + const char *host; + int numcheck; /* number of host combos to check */ + int match = 0; + + if(type == LIBSSH2_KNOWNHOST_TYPE_SHA1) + /* we can't work with a sha1 as given input */ + return LIBSSH2_KNOWNHOST_CHECK_MISMATCH; + + if(!(typemask & LIBSSH2_KNOWNHOST_KEYENC_BASE64)) { + /* we got a raw key input, convert it to base64 for the checks below */ + size_t nlen = _libssh2_base64_encode(hosts->session, key, keylen, + &keyalloc); + if(!nlen) { + _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for base64-encoded " + "key"); + return LIBSSH2_KNOWNHOST_CHECK_FAILURE; + } + + /* make the key point to this */ + key = keyalloc; + } + + /* if a port number is given, check for a '[host]:port' first before the + plain 'host' */ + if(port >= 0) { + snprintf(hostbuff, sizeof(hostbuff), "[%s]:%d", hostp, port); + host = hostbuff; + numcheck = 2; /* check both combos, start with this */ + } + else { + host = hostp; + numcheck = 1; /* only check this host version */ + } + + do { + node = _libssh2_list_first(&hosts->head); + while (node) { + switch(node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) { + case LIBSSH2_KNOWNHOST_TYPE_PLAIN: + if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN) + match = !strcmp(host, node->name); + break; + case LIBSSH2_KNOWNHOST_TYPE_CUSTOM: + if(type == LIBSSH2_KNOWNHOST_TYPE_CUSTOM) + match = !strcmp(host, node->name); + break; + case LIBSSH2_KNOWNHOST_TYPE_SHA1: + if(type == LIBSSH2_KNOWNHOST_TYPE_PLAIN) { + /* when we have the sha1 version stored, we can use a + plain input to produce a hash to compare with the + stored hash. + */ + libssh2_hmac_ctx ctx; + unsigned char hash[SHA_DIGEST_LENGTH]; + + if(SHA_DIGEST_LENGTH != node->name_len) { + /* the name hash length must be the sha1 size or + we can't match it */ + break; + } + libssh2_hmac_sha1_init(&ctx, node->salt, node->salt_len); + libssh2_hmac_update(ctx, (unsigned char *)host, + strlen(host)); + libssh2_hmac_final(ctx, hash); + libssh2_hmac_cleanup(&ctx); + + if(!memcmp(hash, node->name, SHA_DIGEST_LENGTH)) + /* this is a node we're interested in */ + match = 1; + } + break; + default: /* unsupported type */ + break; + } + if(match) { + /* host name match, now compare the keys */ + if(!strcmp(key, node->key)) { + /* they match! */ + if (ext) + *ext = knownhost_to_external(node); + badkey = NULL; + rc = LIBSSH2_KNOWNHOST_CHECK_MATCH; + break; + } + else { + /* remember the first node that had a host match but a + failed key match since we continue our search from + here */ + if(!badkey) + badkey = node; + match = 0; /* don't count this as a match anymore */ + } + } + node= _libssh2_list_next(&node->node); + } + host = hostp; + } while(!match && --numcheck); + + if(badkey) { + /* key mismatch */ + if (ext) + *ext = knownhost_to_external(badkey); + rc = LIBSSH2_KNOWNHOST_CHECK_MISMATCH; + } + + if(keyalloc) + LIBSSH2_FREE(hosts->session, keyalloc); + + return rc; +} + +/* + * libssh2_knownhost_check + * + * Check a host and its associated key against the collection of known hosts. + * + * The typemask is the type/format of the given host name and key + * + * plain - ascii "hostname.domain.tld" + * sha1 - NOT SUPPORTED AS INPUT + * custom - prehashed base64 encoded. Note that this cannot use any salts. + * + * Returns: + * + * LIBSSH2_KNOWNHOST_CHECK_FAILURE + * LIBSSH2_KNOWNHOST_CHECK_NOTFOUND + * LIBSSH2_KNOWNHOST_CHECK_MATCH + * LIBSSH2_KNOWNHOST_CHECK_MISMATCH + */ +LIBSSH2_API int +libssh2_knownhost_check(LIBSSH2_KNOWNHOSTS *hosts, + const char *hostp, const char *key, size_t keylen, + int typemask, + struct libssh2_knownhost **ext) +{ + return knownhost_check(hosts, hostp, -1, key, keylen, + typemask, ext); +} + +/* + * libssh2_knownhost_checkp + * + * Check a host+port and its associated key against the collection of known + * hosts. + * + * Note that if 'port' is specified as greater than zero, the check function + * will be able to check for a dedicated key for this particular host+port + * combo, and if 'port' is negative it only checks for the generic host key. + * + * The typemask is the type/format of the given host name and key + * + * plain - ascii "hostname.domain.tld" + * sha1 - NOT SUPPORTED AS INPUT + * custom - prehashed base64 encoded. Note that this cannot use any salts. + * + * Returns: + * + * LIBSSH2_KNOWNHOST_CHECK_FAILURE + * LIBSSH2_KNOWNHOST_CHECK_NOTFOUND + * LIBSSH2_KNOWNHOST_CHECK_MATCH + * LIBSSH2_KNOWNHOST_CHECK_MISMATCH + */ +LIBSSH2_API int +libssh2_knownhost_checkp(LIBSSH2_KNOWNHOSTS *hosts, + const char *hostp, int port, + const char *key, size_t keylen, + int typemask, + struct libssh2_knownhost **ext) +{ + return knownhost_check(hosts, hostp, port, key, keylen, + typemask, ext); +} + + +/* + * libssh2_knownhost_del + * + * Remove a host from the collection of known hosts. + * + */ +LIBSSH2_API int +libssh2_knownhost_del(LIBSSH2_KNOWNHOSTS *hosts, + struct libssh2_knownhost *entry) +{ + struct known_host *node; + + /* check that this was retrieved the right way or get out */ + if(!entry || (entry->magic != KNOWNHOST_MAGIC)) + return _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL, + "Invalid host information"); + + /* get the internal node pointer */ + node = entry->node; + + /* unlink from the list of all hosts */ + _libssh2_list_remove(&node->node); + + /* clear the struct now since the memory in which it is allocated is + about to be freed! */ + memset(entry, 0, sizeof(struct libssh2_knownhost)); + + /* free all resources */ + free_host(hosts->session, node); + + return 0; +} + +/* + * libssh2_knownhost_free + * + * Free an entire collection of known hosts. + * + */ +LIBSSH2_API void +libssh2_knownhost_free(LIBSSH2_KNOWNHOSTS *hosts) +{ + struct known_host *node; + struct known_host *next; + + for(node = _libssh2_list_first(&hosts->head); node; node = next) { + next = _libssh2_list_next(&node->node); + free_host(hosts->session, node); + } + LIBSSH2_FREE(hosts->session, hosts); +} + + +/* old style plain text: [name]([,][name])* + + for the sake of simplicity, we add them as separate hosts with the same + key +*/ +static int oldstyle_hostline(LIBSSH2_KNOWNHOSTS *hosts, + const char *host, size_t hostlen, + const char *key, size_t keylen, int key_type, + const char *comment, size_t commentlen) +{ + int rc = 0; + size_t namelen = 0; + const char *name = host + hostlen; + + if(hostlen < 1) + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Failed to parse known_hosts line " + "(no host names)"); + + while(name > host) { + --name; + ++namelen; + + /* when we get the the start or see a comma coming up, add the host + name to the collection */ + if((name == host) || (*(name-1) == ',')) { + + char hostbuf[256]; + + /* make sure we don't overflow the buffer */ + if(namelen >= sizeof(hostbuf)-1) + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Failed to parse known_hosts line " + "(unexpected length)"); + + /* copy host name to the temp buffer and zero terminate */ + memcpy(hostbuf, name, namelen); + hostbuf[namelen]=0; + + rc = knownhost_add(hosts, hostbuf, NULL, key, keylen, + comment, commentlen, + key_type | LIBSSH2_KNOWNHOST_TYPE_PLAIN | + LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL); + if(rc) + return rc; + + if(name > host) { + namelen = 0; + --name; /* skip comma */ + } + } + } + + return rc; +} + +/* |1|[salt]|[hash] */ +static int hashed_hostline(LIBSSH2_KNOWNHOSTS *hosts, + const char *host, size_t hostlen, + const char *key, size_t keylen, int key_type, + const char *comment, size_t commentlen) +{ + const char *p; + char saltbuf[32]; + char hostbuf[256]; + + const char *salt = &host[3]; /* skip the magic marker */ + hostlen -= 3; /* deduct the marker */ + + /* this is where the salt starts, find the end of it */ + for(p = salt; *p && (*p != '|'); p++) + ; + + if(*p=='|') { + const char *hash = NULL; + size_t saltlen = p - salt; + if(saltlen >= (sizeof(saltbuf)-1)) /* weird length */ + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Failed to parse known_hosts line " + "(unexpectedly long salt)"); + + memcpy(saltbuf, salt, saltlen); + saltbuf[saltlen] = 0; /* zero terminate */ + salt = saltbuf; /* point to the stack based buffer */ + + hash = p+1; /* the host hash is after the separator */ + + /* now make the host point to the hash */ + host = hash; + hostlen -= saltlen+1; /* deduct the salt and separator */ + + /* check that the lengths seem sensible */ + if(hostlen >= sizeof(hostbuf)-1) + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Failed to parse known_hosts line " + "(unexpected length)"); + + memcpy(hostbuf, host, hostlen); + hostbuf[hostlen]=0; + + return knownhost_add(hosts, hostbuf, salt, key, keylen, comment, + commentlen, + key_type | LIBSSH2_KNOWNHOST_TYPE_SHA1 | + LIBSSH2_KNOWNHOST_KEYENC_BASE64, NULL); + } + else + return 0; /* XXX: This should be an error, shouldn't it? */ +} + +/* + * hostline() + * + * Parse a single known_host line pre-split into host and key. + * + * The key part may include an optional comment which will be parsed here + * for ssh-rsa and ssh-dsa keys. Comments in other key types aren't handled. + * + * The function assumes new-lines have already been removed from the arguments. + */ +static int hostline(LIBSSH2_KNOWNHOSTS *hosts, + const char *host, size_t hostlen, + const char *key, size_t keylen) +{ + const char *comment = NULL; + size_t commentlen = 0; + int key_type; + + /* make some checks that the lengths seem sensible */ + if(keylen < 20) + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Failed to parse known_hosts line " + "(key too short)"); + + switch(key[0]) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + key_type = LIBSSH2_KNOWNHOST_KEY_RSA1; + + /* Note that the old-style keys (RSA1) aren't truly base64, but we + * claim it is for now since we can get away with strcmp()ing the + * entire anything anyway! We need to check and fix these to make them + * work properly. + */ + break; + + case 's': /* ssh-dss or ssh-rsa */ + if(!strncmp(key, "ssh-dss", 7)) + key_type = LIBSSH2_KNOWNHOST_KEY_SSHDSS; + else if(!strncmp(key, "ssh-rsa", 7)) + key_type = LIBSSH2_KNOWNHOST_KEY_SSHRSA; + else + /* unknown key type */ + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Unknown key type"); + + key += 7; + keylen -= 7; + + /* skip whitespaces */ + while((*key ==' ') || (*key == '\t')) { + key++; + keylen--; + } + + comment = key; + commentlen = keylen; + + /* move over key */ + while(commentlen && *comment && + (*comment != ' ') && (*comment != '\t')) { + comment++; + commentlen--; + } + + /* reduce key by comment length */ + keylen -= commentlen; + + /* Distinguish empty comment (a space) from no comment (no space) */ + if (commentlen == 0) + comment = NULL; + + /* skip whitespaces */ + while(commentlen && *comment && + ((*comment ==' ') || (*comment == '\t'))) { + comment++; + commentlen--; + } + break; + + default: /* unknown key format */ + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Unknown key format"); + } + + /* Figure out host format */ + if((hostlen >2) && memcmp(host, "|1|", 3)) { + /* old style plain text: [name]([,][name])* + + for the sake of simplicity, we add them as separate hosts with the + same key + */ + return oldstyle_hostline(hosts, host, hostlen, key, keylen, key_type, + comment, commentlen); + } + else { + /* |1|[salt]|[hash] */ + return hashed_hostline(hosts, host, hostlen, key, keylen, key_type, + comment, commentlen); + } +} + +/* + * libssh2_knownhost_readline() + * + * Pass in a line of a file of 'type'. + * + * LIBSSH2_KNOWNHOST_FILE_OPENSSH is the only supported type. + * + * OpenSSH line format: + * + * + * + * Where the two parts can be created like: + * + * can be either + * or + * + * consists of + * [name] optionally followed by [,name] one or more times + * + * consists of + * |1||hash + * + * can be one of: + * [RSA bits] [e] [n as a decimal number] + * 'ssh-dss' [base64-encoded-key] + * 'ssh-rsa' [base64-encoded-key] + * + */ +LIBSSH2_API int +libssh2_knownhost_readline(LIBSSH2_KNOWNHOSTS *hosts, + const char *line, size_t len, int type) +{ + const char *cp; + const char *hostp; + const char *keyp; + size_t hostlen; + size_t keylen; + int rc; + + if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Unsupported type of known-host information " + "store"); + + cp = line; + + /* skip leading whitespaces */ + while(len && ((*cp==' ') || (*cp == '\t'))) { + cp++; + len--; + } + + if(!len || !*cp || (*cp == '#') || (*cp == '\n')) + /* comment or empty line */ + return LIBSSH2_ERROR_NONE; + + /* the host part starts here */ + hostp = cp; + + /* move over the host to the separator */ + while(len && *cp && (*cp!=' ') && (*cp != '\t')) { + cp++; + len--; + } + + hostlen = cp - hostp; + + /* the key starts after the whitespaces */ + while(len && *cp && ((*cp==' ') || (*cp == '\t'))) { + cp++; + len--; + } + + if(!*cp || !len) /* illegal line */ + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Failed to parse known_hosts line"); + + keyp = cp; /* the key starts here */ + keylen = len; + + /* check if the line (key) ends with a newline and if so kill it */ + while(len && *cp && (*cp != '\n')) { + cp++; + len--; + } + + /* zero terminate where the newline is */ + if(*cp == '\n') + keylen--; /* don't include this in the count */ + + /* deal with this one host+key line */ + rc = hostline(hosts, hostp, hostlen, keyp, keylen); + if(rc) + return rc; /* failed */ + + return LIBSSH2_ERROR_NONE; /* success */ +} + +/* + * libssh2_knownhost_readfile + * + * Read hosts+key pairs from a given file. + * + * Returns a negative value for error or number of successfully added hosts. + * + */ + +LIBSSH2_API int +libssh2_knownhost_readfile(LIBSSH2_KNOWNHOSTS *hosts, + const char *filename, int type) +{ + FILE *file; + int num = 0; + char buf[2048]; + + if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Unsupported type of known-host information " + "store"); + + file = fopen(filename, "r"); + if(file) { + while(fgets(buf, sizeof(buf), file)) { + if(libssh2_knownhost_readline(hosts, buf, strlen(buf), type)) + break; + num++; + } + fclose(file); + } + else + return _libssh2_error(hosts->session, LIBSSH2_ERROR_FILE, + "Failed to open file"); + + return num; +} + +/* + * knownhost_writeline() + * + * Ask libssh2 to convert a known host to an output line for storage. + * + * Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given + * output buffer is too small to hold the desired output. The 'outlen' field + * will then contain the size libssh2 wanted to store, which then is the + * smallest sufficient buffer it would require. + * + */ +static int +knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, + struct known_host *node, + char *buf, size_t buflen, + size_t *outlen, int type) +{ + int rc = LIBSSH2_ERROR_NONE; + int tindex; + const char *keytypes[4]={ + "", /* not used */ + "", /* this type has no name in the file */ + " ssh-rsa", + " ssh-dss" + }; + const char *keytype; + size_t nlen; + size_t commentlen = 0; + + /* we only support this single file type for now, bail out on all other + attempts */ + if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Unsupported type of known-host information " + "store"); + + tindex = (node->typemask & LIBSSH2_KNOWNHOST_KEY_MASK) >> + LIBSSH2_KNOWNHOST_KEY_SHIFT; + + /* set the string used in the file */ + keytype = keytypes[tindex]; + + /* calculate extra space needed for comment */ + if(node->comment) + commentlen = strlen(node->comment) + 1; + + if((node->typemask & LIBSSH2_KNOWNHOST_TYPE_MASK) == + LIBSSH2_KNOWNHOST_TYPE_SHA1) { + char *namealloc; + char *saltalloc; + nlen = _libssh2_base64_encode(hosts->session, node->name, + node->name_len, &namealloc); + if(!nlen) + return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "base64-encoded host name"); + + nlen = _libssh2_base64_encode(hosts->session, + node->salt, node->salt_len, + &saltalloc); + if(!nlen) { + free(namealloc); + return _libssh2_error(hosts->session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "base64-encoded salt"); + } + + nlen = strlen(saltalloc) + strlen(namealloc) + strlen(keytype) + + strlen(node->key) + commentlen + 7; + /* |1| + | + ' ' + \n + \0 = 7 */ + + if(nlen <= buflen) + if(node->comment) + snprintf(buf, buflen, "|1|%s|%s%s %s %s\n", saltalloc, namealloc, + keytype, node->key, node->comment); + else + snprintf(buf, buflen, "|1|%s|%s%s %s\n", saltalloc, namealloc, + keytype, node->key); + else + rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Known-host write buffer too small"); + + free(namealloc); + free(saltalloc); + } + else { + nlen = strlen(node->name) + strlen(keytype) + strlen(node->key) + + commentlen + 3; + /* ' ' + '\n' + \0 = 3 */ + if(nlen <= buflen) + /* these types have the plain name */ + if(node->comment) + snprintf(buf, buflen, "%s%s %s %s\n", node->name, keytype, node->key, + node->comment); + else + snprintf(buf, buflen, "%s%s %s\n", node->name, keytype, node->key); + else + rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Known-host write buffer too small"); + } + + /* we report the full length of the data with the trailing zero excluded */ + *outlen = nlen-1; + + return rc; +} + +/* + * libssh2_knownhost_writeline() + * + * Ask libssh2 to convert a known host to an output line for storage. + * + * Note that this function returns LIBSSH2_ERROR_BUFFER_TOO_SMALL if the given + * output buffer is too small to hold the desired output. + */ +LIBSSH2_API int +libssh2_knownhost_writeline(LIBSSH2_KNOWNHOSTS *hosts, + struct libssh2_knownhost *known, + char *buffer, size_t buflen, + size_t *outlen, /* the amount of written data */ + int type) +{ + struct known_host *node; + + if(known->magic != KNOWNHOST_MAGIC) + return _libssh2_error(hosts->session, LIBSSH2_ERROR_INVAL, + "Invalid host information"); + + node = known->node; + + return knownhost_writeline(hosts, node, buffer, buflen, outlen, type); +} + +/* + * libssh2_knownhost_writefile() + * + * Write hosts+key pairs to the given file. + */ +LIBSSH2_API int +libssh2_knownhost_writefile(LIBSSH2_KNOWNHOSTS *hosts, + const char *filename, int type) +{ + struct known_host *node; + FILE *file; + int rc = LIBSSH2_ERROR_NONE; + char buffer[2048]; + + /* we only support this single file type for now, bail out on all other + attempts */ + if(type != LIBSSH2_KNOWNHOST_FILE_OPENSSH) + return _libssh2_error(hosts->session, + LIBSSH2_ERROR_METHOD_NOT_SUPPORTED, + "Unsupported type of known-host information " + "store"); + + file = fopen(filename, "w"); + if(!file) + return _libssh2_error(hosts->session, LIBSSH2_ERROR_FILE, + "Failed to open file"); + + for(node = _libssh2_list_first(&hosts->head); + node; + node= _libssh2_list_next(&node->node) ) { + size_t wrote; + size_t nwrote; + rc = knownhost_writeline(hosts, node, buffer, sizeof(buffer), &wrote, + type); + if(rc) + break; + + nwrote = fwrite(buffer, 1, wrote, file); + if(nwrote != wrote) { + /* failed to write the whole thing, bail out */ + rc = _libssh2_error(hosts->session, LIBSSH2_ERROR_FILE, + "Write failed"); + break; + } + } + fclose(file); + + return rc; +} + + +/* + * libssh2_knownhost_get() + * + * Traverse the internal list of known hosts. Pass NULL to 'prev' to get + * the first one. + * + * Returns: + * 0 if a fine host was stored in 'store' + * 1 if end of hosts + * [negative] on errors + */ +LIBSSH2_API int +libssh2_knownhost_get(LIBSSH2_KNOWNHOSTS *hosts, + struct libssh2_knownhost **ext, + struct libssh2_knownhost *oprev) +{ + struct known_host *node; + if(oprev && oprev->node) { + /* we have a starting point */ + struct known_host *prev = oprev->node; + + /* get the next node in the list */ + node = _libssh2_list_next(&prev->node); + + } + else + node = _libssh2_list_first(&hosts->head); + + if(!node) + /* no (more) node */ + return 1; + + *ext = knownhost_to_external(node); + + return 0; +} diff --git a/vendor/libssh2-1.4.2/src/libgcrypt.c b/vendor/libssh2-1.4.2/src/libgcrypt.c new file mode 100644 index 0000000..5c2787b --- /dev/null +++ b/vendor/libssh2-1.4.2/src/libgcrypt.c @@ -0,0 +1,593 @@ +/* Copyright (C) 2008, 2009, Simon Josefsson + * Copyright (C) 2006, 2007, The Written Word, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" + +#ifdef LIBSSH2_LIBGCRYPT /* compile only if we build with libgcrypt */ + +#include + +int +_libssh2_rsa_new(libssh2_rsa_ctx ** rsa, + const unsigned char *edata, + unsigned long elen, + const unsigned char *ndata, + unsigned long nlen, + const unsigned char *ddata, + unsigned long dlen, + const unsigned char *pdata, + unsigned long plen, + const unsigned char *qdata, + unsigned long qlen, + const unsigned char *e1data, + unsigned long e1len, + const unsigned char *e2data, + unsigned long e2len, + const unsigned char *coeffdata, unsigned long coefflen) +{ + int rc; + (void) e1data; + (void) e1len; + (void) e2data; + (void) e2len; + + if (ddata) { + rc = gcry_sexp_build + (rsa, NULL, + "(private-key(rsa(n%b)(e%b)(d%b)(q%b)(p%b)(u%b)))", + nlen, ndata, elen, edata, dlen, ddata, plen, pdata, + qlen, qdata, coefflen, coeffdata); + } else { + rc = gcry_sexp_build(rsa, NULL, "(public-key(rsa(n%b)(e%b)))", + nlen, ndata, elen, edata); + } + if (rc) { + *rsa = NULL; + return -1; + } + + return 0; +} + +int +_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsa, + const unsigned char *sig, + unsigned long sig_len, + const unsigned char *m, unsigned long m_len) +{ + unsigned char hash[SHA_DIGEST_LENGTH]; + gcry_sexp_t s_sig, s_hash; + int rc = -1; + + libssh2_sha1(m, m_len, hash); + + rc = gcry_sexp_build(&s_hash, NULL, + "(data (flags pkcs1) (hash sha1 %b))", + SHA_DIGEST_LENGTH, hash); + if (rc != 0) { + return -1; + } + + rc = gcry_sexp_build(&s_sig, NULL, "(sig-val(rsa(s %b)))", sig_len, sig); + if (rc != 0) { + gcry_sexp_release(s_hash); + return -1; + } + + rc = gcry_pk_verify(s_sig, s_hash, rsa); + gcry_sexp_release(s_sig); + gcry_sexp_release(s_hash); + + return (rc == 0) ? 0 : -1; +} + +int +_libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, + const unsigned char *p, + unsigned long p_len, + const unsigned char *q, + unsigned long q_len, + const unsigned char *g, + unsigned long g_len, + const unsigned char *y, + unsigned long y_len, + const unsigned char *x, unsigned long x_len) +{ + int rc; + + if (x_len) { + rc = gcry_sexp_build + (dsactx, NULL, + "(private-key(dsa(p%b)(q%b)(g%b)(y%b)(x%b)))", + p_len, p, q_len, q, g_len, g, y_len, y, x_len, x); + } else { + rc = gcry_sexp_build(dsactx, NULL, + "(public-key(dsa(p%b)(q%b)(g%b)(y%b)))", + p_len, p, q_len, q, g_len, g, y_len, y); + } + + if (rc) { + *dsactx = NULL; + return -1; + } + + return 0; +} + +int +_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, + LIBSSH2_SESSION * session, + const char *filename, unsigned const char *passphrase) +{ + FILE *fp; + unsigned char *data, *save_data; + unsigned int datalen; + int ret; + unsigned char *n, *e, *d, *p, *q, *e1, *e2, *coeff; + unsigned int nlen, elen, dlen, plen, qlen, e1len, e2len, coefflen; + + (void) passphrase; + + fp = fopen(filename, "r"); + if (!fp) { + return -1; + } + + ret = _libssh2_pem_parse(session, + "-----BEGIN RSA PRIVATE KEY-----", + "-----END RSA PRIVATE KEY-----", + fp, &data, &datalen); + fclose(fp); + if (ret) { + return -1; + } + + save_data = data; + + if (_libssh2_pem_decode_sequence(&data, &datalen)) { + ret = -1; + goto fail; + } +/* First read Version field (should be 0). */ + ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen); + if (ret != 0 || (nlen != 1 && *n != '\0')) { + ret = -1; + goto fail; + } + + ret = _libssh2_pem_decode_integer(&data, &datalen, &n, &nlen); + if (ret != 0) { + ret = -1; + goto fail; + } + + ret = _libssh2_pem_decode_integer(&data, &datalen, &e, &elen); + if (ret != 0) { + ret = -1; + goto fail; + } + + ret = _libssh2_pem_decode_integer(&data, &datalen, &d, &dlen); + if (ret != 0) { + ret = -1; + goto fail; + } + + ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); + if (ret != 0) { + ret = -1; + goto fail; + } + + ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen); + if (ret != 0) { + ret = -1; + goto fail; + } + + ret = _libssh2_pem_decode_integer(&data, &datalen, &e1, &e1len); + if (ret != 0) { + ret = -1; + goto fail; + } + + ret = _libssh2_pem_decode_integer(&data, &datalen, &e2, &e2len); + if (ret != 0) { + ret = -1; + goto fail; + } + + ret = _libssh2_pem_decode_integer(&data, &datalen, &coeff, &coefflen); + if (ret != 0) { + ret = -1; + goto fail; + } + + if (_libssh2_rsa_new(rsa, e, elen, n, nlen, d, dlen, p, plen, + q, qlen, e1, e1len, e2, e2len, coeff, coefflen)) { + ret = -1; + goto fail; + } + + ret = 0; + + fail: + LIBSSH2_FREE(session, save_data); + return ret; +} + +int +_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, + LIBSSH2_SESSION * session, + const char *filename, unsigned const char *passphrase) +{ + FILE *fp; + unsigned char *data, *save_data; + unsigned int datalen; + int ret; + unsigned char *p, *q, *g, *y, *x; + unsigned int plen, qlen, glen, ylen, xlen; + + (void) passphrase; + + fp = fopen(filename, "r"); + if (!fp) { + return -1; + } + + ret = _libssh2_pem_parse(session, + "-----BEGIN DSA PRIVATE KEY-----", + "-----END DSA PRIVATE KEY-----", + fp, &data, &datalen); + fclose(fp); + if (ret) { + return -1; + } + + save_data = data; + + if (_libssh2_pem_decode_sequence(&data, &datalen)) { + ret = -1; + goto fail; + } + +/* First read Version field (should be 0). */ + ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); + if (ret != 0 || (plen != 1 && *p != '\0')) { + ret = -1; + goto fail; + } + + ret = _libssh2_pem_decode_integer(&data, &datalen, &p, &plen); + if (ret != 0) { + ret = -1; + goto fail; + } + + ret = _libssh2_pem_decode_integer(&data, &datalen, &q, &qlen); + if (ret != 0) { + ret = -1; + goto fail; + } + + ret = _libssh2_pem_decode_integer(&data, &datalen, &g, &glen); + if (ret != 0) { + ret = -1; + goto fail; + } + + ret = _libssh2_pem_decode_integer(&data, &datalen, &y, &ylen); + if (ret != 0) { + ret = -1; + goto fail; + } + + ret = _libssh2_pem_decode_integer(&data, &datalen, &x, &xlen); + if (ret != 0) { + ret = -1; + goto fail; + } + + if (datalen != 0) { + ret = -1; + goto fail; + } + + if (_libssh2_dsa_new(dsa, p, plen, q, qlen, g, glen, y, ylen, x, xlen)) { + ret = -1; + goto fail; + } + + ret = 0; + + fail: + LIBSSH2_FREE(session, save_data); + return ret; +} + +int +_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, + libssh2_dsa_ctx * rsactx, + const unsigned char *hash, + size_t hash_len, + unsigned char **signature, size_t *signature_len) +{ + gcry_sexp_t sig_sexp; + gcry_sexp_t data; + int rc; + const char *tmp; + size_t size; + + if (hash_len != SHA_DIGEST_LENGTH) { + return -1; + } + + if (gcry_sexp_build(&data, NULL, + "(data (flags pkcs1) (hash sha1 %b))", + hash_len, hash)) { + return -1; + } + + rc = gcry_pk_sign(&sig_sexp, data, rsactx); + + gcry_sexp_release(data); + + if (rc != 0) { + return -1; + } + + data = gcry_sexp_find_token(sig_sexp, "s", 0); + if (!data) { + return -1; + } + + tmp = gcry_sexp_nth_data(data, 1, &size); + if (!tmp) { + return -1; + } + + if (tmp[0] == '\0') { + tmp++; + size--; + } + + *signature = LIBSSH2_ALLOC(session, size); + memcpy(*signature, tmp, size); + *signature_len = size; + + return rc; +} + +int +_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, + const unsigned char *hash, + unsigned long hash_len, unsigned char *sig) +{ + unsigned char zhash[SHA_DIGEST_LENGTH + 1]; + gcry_sexp_t sig_sexp; + gcry_sexp_t data; + int ret; + const char *tmp; + size_t size; + + if (hash_len != SHA_DIGEST_LENGTH) { + return -1; + } + + memcpy(zhash + 1, hash, hash_len); + zhash[0] = 0; + + if (gcry_sexp_build(&data, NULL, "(data (value %b))", hash_len + 1, zhash)) { + return -1; + } + + ret = gcry_pk_sign(&sig_sexp, data, dsactx); + + gcry_sexp_release(data); + + if (ret != 0) { + return -1; + } + + memset(sig, 0, 40); + +/* Extract R. */ + + data = gcry_sexp_find_token(sig_sexp, "r", 0); + if (!data) + goto err; + + tmp = gcry_sexp_nth_data(data, 1, &size); + if (!tmp) + goto err; + + if (tmp[0] == '\0') { + tmp++; + size--; + } + + if (size < 1 || size > 20) + goto err; + + memcpy(sig + (20 - size), tmp, size); + + gcry_sexp_release(data); + +/* Extract S. */ + + data = gcry_sexp_find_token(sig_sexp, "s", 0); + if (!data) + goto err; + + tmp = gcry_sexp_nth_data(data, 1, &size); + if (!tmp) + goto err; + + if (tmp[0] == '\0') { + tmp++; + size--; + } + + if (size < 1 || size > 20) + goto err; + + memcpy(sig + 20 + (20 - size), tmp, size); + goto out; + + err: + ret = -1; + + out: + if (sig_sexp) { + gcry_sexp_release(sig_sexp); + } + if (data) { + gcry_sexp_release(data); + } + return ret; +} + +int +_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, + const unsigned char *sig, + const unsigned char *m, unsigned long m_len) +{ + unsigned char hash[SHA_DIGEST_LENGTH + 1]; + gcry_sexp_t s_sig, s_hash; + int rc = -1; + + libssh2_sha1(m, m_len, hash + 1); + hash[0] = 0; + + if (gcry_sexp_build(&s_hash, NULL, "(data(flags raw)(value %b))", + SHA_DIGEST_LENGTH + 1, hash)) { + return -1; + } + + if (gcry_sexp_build(&s_sig, NULL, "(sig-val(dsa(r %b)(s %b)))", + 20, sig, 20, sig + 20)) { + gcry_sexp_release(s_hash); + return -1; + } + + rc = gcry_pk_verify(s_sig, s_hash, dsactx); + gcry_sexp_release(s_sig); + gcry_sexp_release(s_hash); + + return (rc == 0) ? 0 : -1; +} + +int +_libssh2_cipher_init(_libssh2_cipher_ctx * h, + _libssh2_cipher_type(algo), + unsigned char *iv, unsigned char *secret, int encrypt) +{ + int ret; + int cipher = _libssh2_gcry_cipher (algo); + int mode = _libssh2_gcry_mode (algo); + int keylen = gcry_cipher_get_algo_keylen(cipher); + + (void) encrypt; + + ret = gcry_cipher_open(h, cipher, mode, 0); + if (ret) { + return -1; + } + + ret = gcry_cipher_setkey(*h, secret, keylen); + if (ret) { + gcry_cipher_close(*h); + return -1; + } + + if (mode != GCRY_CIPHER_MODE_STREAM) { + int blklen = gcry_cipher_get_algo_blklen(cipher); + if (mode == GCRY_CIPHER_MODE_CTR) + ret = gcry_cipher_setctr(*h, iv, blklen); + else + ret = gcry_cipher_setiv(*h, iv, blklen); + if (ret) { + gcry_cipher_close(*h); + return -1; + } + } + + return 0; +} + +int +_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, + _libssh2_cipher_type(algo), + int encrypt, unsigned char *block) +{ + int cipher = _libssh2_gcry_cipher (algo); + size_t blklen = gcry_cipher_get_algo_blklen(cipher); + int ret; + + if (blklen == 1) { +/* Hack for arcfour. */ + blklen = 8; + } + + if (encrypt) { + ret = gcry_cipher_encrypt(*ctx, block, blklen, block, blklen); + } else { + ret = gcry_cipher_decrypt(*ctx, block, blklen, block, blklen); + } + return ret; +} + +int +_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + const char *privatekey, + const char *passphrase) +{ + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to extract public key from private key file: " + "Method unimplemented in libgcrypt backend"); +} + +void _libssh2_init_aes_ctr(void) +{ + /* no implementation */ +} +#endif /* LIBSSH2_LIBGCRYPT */ diff --git a/vendor/libssh2-1.4.2/src/libgcrypt.h b/vendor/libssh2-1.4.2/src/libgcrypt.h new file mode 100644 index 0000000..04516e5 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/libgcrypt.h @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2008, 2009, 2010 Simon Josefsson + * Copyright (C) 2006, 2007, The Written Word, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include + +#define LIBSSH2_MD5 1 + +#define LIBSSH2_HMAC_RIPEMD 1 + +#define LIBSSH2_AES 1 +#define LIBSSH2_AES_CTR 1 +#define LIBSSH2_BLOWFISH 1 +#define LIBSSH2_RC4 1 +#define LIBSSH2_CAST 1 +#define LIBSSH2_3DES 1 + +#define LIBSSH2_RSA 1 +#define LIBSSH2_DSA 1 + +#define MD5_DIGEST_LENGTH 16 +#define SHA_DIGEST_LENGTH 20 + +#define _libssh2_random(buf, len) \ + (gcry_randomize ((buf), (len), GCRY_STRONG_RANDOM), 1) + +#define libssh2_sha1_ctx gcry_md_hd_t +#define libssh2_sha1_init(ctx) gcry_md_open (ctx, GCRY_MD_SHA1, 0); +#define libssh2_sha1_update(ctx, data, len) gcry_md_write (ctx, data, len) +#define libssh2_sha1_final(ctx, out) \ + memcpy (out, gcry_md_read (ctx, 0), SHA_DIGEST_LENGTH), gcry_md_close (ctx) +#define libssh2_sha1(message, len, out) \ + gcry_md_hash_buffer (GCRY_MD_SHA1, out, message, len) + +#define libssh2_md5_ctx gcry_md_hd_t +#define libssh2_md5_init(ctx) gcry_md_open (ctx, GCRY_MD_MD5, 0); +#define libssh2_md5_update(ctx, data, len) gcry_md_write (ctx, data, len) +#define libssh2_md5_final(ctx, out) \ + memcpy (out, gcry_md_read (ctx, 0), MD5_DIGEST_LENGTH), gcry_md_close (ctx) +#define libssh2_md5(message, len, out) \ + gcry_md_hash_buffer (GCRY_MD_MD5, out, message, len) + +#define libssh2_hmac_ctx gcry_md_hd_t +#define libssh2_hmac_sha1_init(ctx, key, keylen) \ + gcry_md_open (ctx, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC), \ + gcry_md_setkey (*ctx, key, keylen) +#define libssh2_hmac_md5_init(ctx, key, keylen) \ + gcry_md_open (ctx, GCRY_MD_MD5, GCRY_MD_FLAG_HMAC), \ + gcry_md_setkey (*ctx, key, keylen) +#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \ + gcry_md_open (ctx, GCRY_MD_RMD160, GCRY_MD_FLAG_HMAC), \ + gcry_md_setkey (*ctx, key, keylen) +#define libssh2_hmac_update(ctx, data, datalen) \ + gcry_md_write (ctx, data, datalen) +#define libssh2_hmac_final(ctx, data) \ + memcpy (data, gcry_md_read (ctx, 0), \ + gcry_md_get_algo_dlen (gcry_md_get_algo (ctx))) +#define libssh2_hmac_cleanup(ctx) gcry_md_close (*ctx); + +#define libssh2_crypto_init() gcry_control (GCRYCTL_DISABLE_SECMEM) +#define libssh2_crypto_exit() + +#define libssh2_rsa_ctx struct gcry_sexp + +#define _libssh2_rsa_free(rsactx) gcry_sexp_release (rsactx) + +#define libssh2_dsa_ctx struct gcry_sexp + +#define _libssh2_dsa_free(dsactx) gcry_sexp_release (dsactx) + +#define _libssh2_cipher_type(name) int name +#define _libssh2_cipher_ctx gcry_cipher_hd_t + +#define _libssh2_gcry_ciphermode(c,m) ((c << 8) | m) +#define _libssh2_gcry_cipher(c) (c >> 8) +#define _libssh2_gcry_mode(m) (m & 0xFF) + +#define _libssh2_cipher_aes256ctr \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR) +#define _libssh2_cipher_aes192ctr \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR) +#define _libssh2_cipher_aes128ctr \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR) +#define _libssh2_cipher_aes256 \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC) +#define _libssh2_cipher_aes192 \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC) +#define _libssh2_cipher_aes128 \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC) +#define _libssh2_cipher_blowfish \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC) +#define _libssh2_cipher_arcfour \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM) +#define _libssh2_cipher_cast5 \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC) +#define _libssh2_cipher_3des \ + _libssh2_gcry_ciphermode(GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC) + + +#define _libssh2_cipher_dtor(ctx) gcry_cipher_close(*(ctx)) + +#define _libssh2_bn struct gcry_mpi +#define _libssh2_bn_ctx int +#define _libssh2_bn_ctx_new() 0 +#define _libssh2_bn_ctx_free(bnctx) ((void)0) +#define _libssh2_bn_init() gcry_mpi_new(0) +#define _libssh2_bn_rand(bn, bits, top, bottom) gcry_mpi_randomize (bn, bits, GCRY_WEAK_RANDOM) +#define _libssh2_bn_mod_exp(r, a, p, m, ctx) gcry_mpi_powm (r, a, p, m) +#define _libssh2_bn_set_word(bn, val) gcry_mpi_set_ui(bn, val) +#define _libssh2_bn_from_bin(bn, len, val) gcry_mpi_scan(&((bn)), GCRYMPI_FMT_USG, val, len, NULL) +#define _libssh2_bn_to_bin(bn, val) gcry_mpi_print (GCRYMPI_FMT_USG, val, _libssh2_bn_bytes(bn), NULL, bn) +#define _libssh2_bn_bytes(bn) (gcry_mpi_get_nbits (bn) / 8 + ((gcry_mpi_get_nbits (bn) % 8 == 0) ? 0 : 1)) +#define _libssh2_bn_bits(bn) gcry_mpi_get_nbits (bn) +#define _libssh2_bn_free(bn) gcry_mpi_release(bn) + diff --git a/vendor/libssh2-1.4.2/src/libssh2_config.h b/vendor/libssh2-1.4.2/src/libssh2_config.h new file mode 100644 index 0000000..4591f5f --- /dev/null +++ b/vendor/libssh2-1.4.2/src/libssh2_config.h @@ -0,0 +1,5 @@ +#ifdef WIN32 + #include "libssh2_config_win.h" +#else + #include "libssh2_config_osx.h" +#endif diff --git a/vendor/libssh2-1.4.2/src/libssh2_config_osx.h b/vendor/libssh2-1.4.2/src/libssh2_config_osx.h new file mode 100644 index 0000000..d8917c2 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/libssh2_config_osx.h @@ -0,0 +1,224 @@ +/* src/libssh2_config.h. Generated from libssh2_config.h.in by configure. */ +/* src/libssh2_config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +/* #undef AC_APPLE_UNIVERSAL_BUILD */ + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +/* #undef CRAY_STACKSEG_END */ + +/* Define to 1 if using `alloca.c'. */ +/* #undef C_ALLOCA */ + +/* Define to 1 if you have `alloca', as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define to 1 if you have and it should be used (not on Ultrix). + */ +#define HAVE_ALLOCA_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* disabled non-blocking sockets */ +/* #undef HAVE_DISABLED_NONBLOCKING */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `EVP_aes_128_ctr' function. */ +/* #undef HAVE_EVP_AES_128_CTR */ + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* use FIONBIO for non-blocking sockets */ +/* #undef HAVE_FIONBIO */ + +/* Define to 1 if you have the `gettimeofday' function. */ +#define HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* use ioctlsocket() for non-blocking sockets */ +/* #undef HAVE_IOCTLSOCKET */ + +/* use Ioctlsocket() for non-blocking sockets */ +/* #undef HAVE_IOCTLSOCKET_CASE */ + +/* Define if you have the gcrypt library. */ +/* #undef HAVE_LIBGCRYPT */ + +/* Define if you have the ssl library. */ +#define HAVE_LIBSSL 1 + +/* Define if you have the z library. */ +#define HAVE_LIBZ 1 + +/* Define to 1 if the compiler supports the 'long long' data type. */ +#define HAVE_LONGLONG 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* use O_NONBLOCK for non-blocking sockets */ +#define HAVE_O_NONBLOCK 1 + +/* Define to 1 if you have the `poll' function. */ +/* #undef HAVE_POLL */ + +/* Define to 1 if you have the select function. */ +#define HAVE_SELECT 1 + +/* use SO_NONBLOCK for non-blocking sockets */ +/* #undef HAVE_SO_NONBLOCK */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strtoll' function. */ +#define HAVE_STRTOLL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINDOWS_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WINSOCK2_H */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_WS2TCPIP_H */ + +/* to make a symbol visible */ +/* #undef LIBSSH2_API */ + +/* Enable "none" cipher -- NOT RECOMMENDED */ +/* #undef LIBSSH2_CRYPT_NONE */ + +/* Enable newer diffie-hellman-group-exchange-sha1 syntax */ +#define LIBSSH2_DH_GEX_NEW 1 + +/* Compile in zlib support */ +#define LIBSSH2_HAVE_ZLIB 1 + +/* Use libgcrypt */ +/* #undef LIBSSH2_LIBGCRYPT */ + +/* Enable "none" MAC -- NOT RECOMMENDED */ +/* #undef LIBSSH2_MAC_NONE */ + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#define LT_OBJDIR ".libs/" + +/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */ +/* #undef NEED_REENTRANT */ + +/* Name of package */ +#define PACKAGE "libssh2" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "libssh2-devel@cool.haxx.se" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libssh2" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libssh2 -" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libssh2" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "-" + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +/* #undef STACK_DIRECTION */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "-" + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +/* # undef WORDS_BIGENDIAN */ +# endif +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif diff --git a/vendor/libssh2-1.4.2/src/libssh2_config_win.h b/vendor/libssh2-1.4.2/src/libssh2_config_win.h new file mode 100644 index 0000000..39e438f --- /dev/null +++ b/vendor/libssh2-1.4.2/src/libssh2_config_win.h @@ -0,0 +1,41 @@ +#ifndef LIBSSH2_CONFIG_H +#define LIBSSH2_CONFIG_H + +#ifndef WIN32 +#define WIN32 +#endif +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif /* _CRT_SECURE_NO_DEPRECATE */ +#include +#include +#include + +#ifdef __MINGW32__ +#define HAVE_UNISTD_H +#define HAVE_INTTYPES_H +#define HAVE_SYS_TIME_H +#endif + +#define HAVE_WINSOCK2_H +#define HAVE_IOCTLSOCKET +#define HAVE_SELECT + +#ifdef _MSC_VER +#define snprintf _snprintf +#if _MSC_VER < 1500 +#define vsnprintf _vsnprintf +#endif +#define strdup _strdup +#define strncasecmp _strnicmp +#define strcasecmp _stricmp +#else +#define strncasecmp strnicmp +#define strcasecmp stricmp +#endif /* _MSC_VER */ + +/* Enable newer diffie-hellman-group-exchange-sha1 syntax */ +#define LIBSSH2_DH_GEX_NEW 1 + +#endif /* LIBSSH2_CONFIG_H */ + diff --git a/vendor/libssh2-1.4.2/src/libssh2_priv.h b/vendor/libssh2-1.4.2/src/libssh2_priv.h new file mode 100644 index 0000000..c670a16 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/libssh2_priv.h @@ -0,0 +1,1038 @@ +/* Copyright (c) 2004-2008, 2010, Sara Golemon + * Copyright (c) 2009-2011 by Daniel Stenberg + * Copyright (c) 2010 Simon Josefsson + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#ifndef LIBSSH2_PRIV_H +#define LIBSSH2_PRIV_H 1 + +#define LIBSSH2_LIBRARY +#include "libssh2_config.h" + +#ifdef HAVE_WINDOWS_H +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#undef WIN32_LEAN_AND_MEAN +#endif + +#ifdef HAVE_WS2TCPIP_H +#include +#endif + +#include +#include + +/* The following CPP block should really only be in session.c and + packet.c. However, AIX have #define's for 'events' and 'revents' + and we are using those names in libssh2.h, so we need to include + the AIX headers first, to make sure all code is compiled with + consistent names of these fields. While arguable the best would to + change libssh2.h to use other names, that would break backwards + compatibility. For more information, see: + http://www.mail-archive.com/libssh2-devel%40lists.sourceforge.net/msg00003.html + http://www.mail-archive.com/libssh2-devel%40lists.sourceforge.net/msg00224.html +*/ +#ifdef HAVE_POLL +# include +#else +# if defined(HAVE_SELECT) && !defined(WIN32) +# ifdef HAVE_SYS_SELECT_H +# include +# else +# include +# include +# endif +# endif +#endif + +/* Needed for struct iovec on some platforms */ +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +# include +#endif +#ifdef HAVE_SYS_IOCTL_H +# include +#endif +#ifdef HAVE_INTTYPES_H +#include +#endif + +#include "libssh2.h" +#include "libssh2_publickey.h" +#include "libssh2_sftp.h" +#include "misc.h" /* for the linked list stuff */ + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif + +/* Provide iovec / writev on WIN32 platform. */ +#ifdef WIN32 + +struct iovec { + size_t iov_len; + void * iov_base; +}; + +#define inline __inline + +static inline int writev(int sock, struct iovec *iov, int nvecs) +{ + DWORD ret; + if (WSASend(sock, (LPWSABUF)iov, nvecs, &ret, 0, NULL, NULL) == 0) { + return ret; + } + return -1; +} + +#endif /* WIN32 */ + +#include "crypto.h" + +#ifdef HAVE_WINSOCK2_H + +#include +#include +#include + +#ifdef _MSC_VER +/* "inline" keyword is valid only with C++ engine! */ +#define inline __inline +#endif + +#endif + +/* RFC4253 section 6.1 Maximum Packet Length says: + * + * "All implementations MUST be able to process packets with + * uncompressed payload length of 32768 bytes or less and + * total packet size of 35000 bytes or less (including length, + * padding length, payload, padding, and MAC.)." + */ +#define MAX_SSH_PACKET_LEN 35000 + +#define LIBSSH2_ALLOC(session, count) \ + session->alloc((count), &(session)->abstract) +#define LIBSSH2_REALLOC(session, ptr, count) \ + ((ptr) ? session->realloc((ptr), (count), &(session)->abstract) : \ + session->alloc((count), &(session)->abstract)) +#define LIBSSH2_FREE(session, ptr) \ + session->free((ptr), &(session)->abstract) +#define LIBSSH2_IGNORE(session, data, datalen) \ + session->ssh_msg_ignore((session), (data), (datalen), &(session)->abstract) +#define LIBSSH2_DEBUG(session, always_display, message, message_len, \ + language, language_len) \ + session->ssh_msg_debug((session), (always_display), (message), \ + (message_len), (language), (language_len), \ + &(session)->abstract) +#define LIBSSH2_DISCONNECT(session, reason, message, message_len, \ + language, language_len) \ + session->ssh_msg_disconnect((session), (reason), (message), \ + (message_len), (language), (language_len), \ + &(session)->abstract) + +#define LIBSSH2_MACERROR(session, data, datalen) \ + session->macerror((session), (data), (datalen), &(session)->abstract) +#define LIBSSH2_X11_OPEN(channel, shost, sport) \ + channel->session->x11(((channel)->session), (channel), \ + (shost), (sport), (&(channel)->session->abstract)) + +#define LIBSSH2_CHANNEL_CLOSE(session, channel) \ + channel->close_cb((session), &(session)->abstract, \ + (channel), &(channel)->abstract) + +#define LIBSSH2_SEND_FD(session, fd, buffer, length, flags) \ + session->send(fd, buffer, length, flags, &session->abstract) +#define LIBSSH2_RECV_FD(session, fd, buffer, length, flags) \ + session->recv(fd, buffer, length, flags, &session->abstract) + +#define LIBSSH2_SEND(session, buffer, length, flags) \ + LIBSSH2_SEND_FD(session, session->socket_fd, buffer, length, flags) +#define LIBSSH2_RECV(session, buffer, length, flags) \ + LIBSSH2_RECV_FD(session, session->socket_fd, buffer, length, flags) + +typedef struct _LIBSSH2_KEX_METHOD LIBSSH2_KEX_METHOD; +typedef struct _LIBSSH2_HOSTKEY_METHOD LIBSSH2_HOSTKEY_METHOD; +typedef struct _LIBSSH2_CRYPT_METHOD LIBSSH2_CRYPT_METHOD; +typedef struct _LIBSSH2_COMP_METHOD LIBSSH2_COMP_METHOD; + +typedef struct _LIBSSH2_PACKET LIBSSH2_PACKET; + +typedef enum +{ + libssh2_NB_state_idle = 0, + libssh2_NB_state_allocated, + libssh2_NB_state_created, + libssh2_NB_state_sent, + libssh2_NB_state_sent1, + libssh2_NB_state_sent2, + libssh2_NB_state_sent3, + libssh2_NB_state_sent4, + libssh2_NB_state_sent5, + libssh2_NB_state_sent6, + libssh2_NB_state_sent7, + libssh2_NB_state_jump1, + libssh2_NB_state_jump2, + libssh2_NB_state_jump3, + libssh2_NB_state_jump4, + libssh2_NB_state_jump5 +} libssh2_nonblocking_states; + +typedef struct packet_require_state_t +{ + libssh2_nonblocking_states state; + time_t start; +} packet_require_state_t; + +typedef struct packet_requirev_state_t +{ + time_t start; +} packet_requirev_state_t; + +typedef struct kmdhgGPsha1kex_state_t +{ + libssh2_nonblocking_states state; + unsigned char *e_packet; + unsigned char *s_packet; + unsigned char *tmp; + unsigned char h_sig_comp[SHA_DIGEST_LENGTH]; + unsigned char c; + size_t e_packet_len; + size_t s_packet_len; + size_t tmp_len; + _libssh2_bn_ctx *ctx; + _libssh2_bn *x; + _libssh2_bn *e; + _libssh2_bn *f; + _libssh2_bn *k; + unsigned char *s; + unsigned char *f_value; + unsigned char *k_value; + unsigned char *h_sig; + size_t f_value_len; + size_t k_value_len; + size_t h_sig_len; + libssh2_sha1_ctx exchange_hash; + packet_require_state_t req_state; + libssh2_nonblocking_states burn_state; +} kmdhgGPsha1kex_state_t; + +typedef struct key_exchange_state_low_t +{ + libssh2_nonblocking_states state; + packet_require_state_t req_state; + kmdhgGPsha1kex_state_t exchange_state; + _libssh2_bn *p; /* SSH2 defined value (p_value) */ + _libssh2_bn *g; /* SSH2 defined value (2) */ + unsigned char request[13]; + unsigned char *data; + size_t request_len; + size_t data_len; +} key_exchange_state_low_t; + +typedef struct key_exchange_state_t +{ + libssh2_nonblocking_states state; + packet_require_state_t req_state; + key_exchange_state_low_t key_state_low; + unsigned char *data; + size_t data_len; + unsigned char *oldlocal; + size_t oldlocal_len; +} key_exchange_state_t; + +#define FwdNotReq "Forward not requested" + +typedef struct packet_queue_listener_state_t +{ + libssh2_nonblocking_states state; + unsigned char packet[17 + (sizeof(FwdNotReq) - 1)]; + unsigned char *host; + unsigned char *shost; + uint32_t sender_channel; + uint32_t initial_window_size; + uint32_t packet_size; + uint32_t port; + uint32_t sport; + uint32_t host_len; + uint32_t shost_len; + LIBSSH2_CHANNEL *channel; +} packet_queue_listener_state_t; + +#define X11FwdUnAvil "X11 Forward Unavailable" + +typedef struct packet_x11_open_state_t +{ + libssh2_nonblocking_states state; + unsigned char packet[17 + (sizeof(X11FwdUnAvil) - 1)]; + unsigned char *shost; + uint32_t sender_channel; + uint32_t initial_window_size; + uint32_t packet_size; + uint32_t sport; + uint32_t shost_len; + LIBSSH2_CHANNEL *channel; +} packet_x11_open_state_t; + +struct _LIBSSH2_PACKET +{ + struct list_node node; /* linked list header */ + + /* the raw unencrypted payload */ + unsigned char *data; + size_t data_len; + + /* Where to start reading data from, + * used for channel data that's been partially consumed */ + size_t data_head; +}; + +typedef struct _libssh2_channel_data +{ + /* Identifier */ + uint32_t id; + + /* Limits and restrictions */ + uint32_t window_size_initial, window_size, packet_size; + + /* Set to 1 when CHANNEL_CLOSE / CHANNEL_EOF sent/received */ + char close, eof, extended_data_ignore_mode; +} libssh2_channel_data; + +struct _LIBSSH2_CHANNEL +{ + struct list_node node; + + unsigned char *channel_type; + unsigned channel_type_len; + + /* channel's program exit status */ + int exit_status; + + /* channel's program exit signal (without the SIG prefix) */ + char *exit_signal; + + libssh2_channel_data local, remote; + /* Amount of bytes to be refunded to receive window (but not yet sent) */ + uint32_t adjust_queue; + + LIBSSH2_SESSION *session; + + void *abstract; + LIBSSH2_CHANNEL_CLOSE_FUNC((*close_cb)); + + /* State variables used in libssh2_channel_setenv_ex() */ + libssh2_nonblocking_states setenv_state; + unsigned char *setenv_packet; + size_t setenv_packet_len; + unsigned char setenv_local_channel[4]; + packet_requirev_state_t setenv_packet_requirev_state; + + /* State variables used in libssh2_channel_request_pty_ex() + libssh2_channel_request_pty_size_ex() */ + libssh2_nonblocking_states reqPTY_state; + unsigned char reqPTY_packet[41 + 256]; + size_t reqPTY_packet_len; + unsigned char reqPTY_local_channel[4]; + packet_requirev_state_t reqPTY_packet_requirev_state; + + /* State variables used in libssh2_channel_x11_req_ex() */ + libssh2_nonblocking_states reqX11_state; + unsigned char *reqX11_packet; + size_t reqX11_packet_len; + unsigned char reqX11_local_channel[4]; + packet_requirev_state_t reqX11_packet_requirev_state; + + /* State variables used in libssh2_channel_process_startup() */ + libssh2_nonblocking_states process_state; + unsigned char *process_packet; + size_t process_packet_len; + unsigned char process_local_channel[4]; + packet_requirev_state_t process_packet_requirev_state; + + /* State variables used in libssh2_channel_flush_ex() */ + libssh2_nonblocking_states flush_state; + size_t flush_refund_bytes; + size_t flush_flush_bytes; + + /* State variables used in libssh2_channel_receive_window_adjust() */ + libssh2_nonblocking_states adjust_state; + unsigned char adjust_adjust[9]; /* packet_type(1) + channel(4) + adjustment(4) */ + + /* State variables used in libssh2_channel_read_ex() */ + libssh2_nonblocking_states read_state; + + uint32_t read_local_id; + + /* State variables used in libssh2_channel_write_ex() */ + libssh2_nonblocking_states write_state; + unsigned char write_packet[13]; + size_t write_packet_len; + size_t write_bufwrite; + + /* State variables used in libssh2_channel_close() */ + libssh2_nonblocking_states close_state; + unsigned char close_packet[5]; + + /* State variables used in libssh2_channel_wait_closedeof() */ + libssh2_nonblocking_states wait_eof_state; + + /* State variables used in libssh2_channel_wait_closed() */ + libssh2_nonblocking_states wait_closed_state; + + /* State variables used in libssh2_channel_free() */ + libssh2_nonblocking_states free_state; + + /* State variables used in libssh2_channel_handle_extended_data2() */ + libssh2_nonblocking_states extData2_state; + +}; + +struct _LIBSSH2_LISTENER +{ + struct list_node node; /* linked list header */ + + LIBSSH2_SESSION *session; + + char *host; + int port; + + /* a list of CHANNELs for this listener */ + struct list_head queue; + + int queue_size; + int queue_maxsize; + + /* State variables used in libssh2_channel_forward_cancel() */ + libssh2_nonblocking_states chanFwdCncl_state; + unsigned char *chanFwdCncl_data; + size_t chanFwdCncl_data_len; +}; + +typedef struct _libssh2_endpoint_data +{ + unsigned char *banner; + + unsigned char *kexinit; + size_t kexinit_len; + + const LIBSSH2_CRYPT_METHOD *crypt; + void *crypt_abstract; + + const struct _LIBSSH2_MAC_METHOD *mac; + uint32_t seqno; + void *mac_abstract; + + const LIBSSH2_COMP_METHOD *comp; + void *comp_abstract; + + /* Method Preferences -- NULL yields "load order" */ + char *crypt_prefs; + char *mac_prefs; + char *comp_prefs; + char *lang_prefs; +} libssh2_endpoint_data; + +#define PACKETBUFSIZE (1024*16) + +struct transportpacket +{ + /* ------------- for incoming data --------------- */ + unsigned char buf[PACKETBUFSIZE]; + unsigned char init[5]; /* first 5 bytes of the incoming data stream, + still encrypted */ + size_t writeidx; /* at what array index we do the next write into + the buffer */ + size_t readidx; /* at what array index we do the next read from + the buffer */ + uint32_t packet_length; /* the most recent packet_length as read from the + network data */ + uint8_t padding_length; /* the most recent padding_length as read from the + network data */ + size_t data_num; /* How much of the total package that has been read + so far. */ + size_t total_num; /* How much a total package is supposed to be, in + number of bytes. A full package is + packet_length + padding_length + 4 + + mac_length. */ + unsigned char *payload; /* this is a pointer to a LIBSSH2_ALLOC() + area to which we write decrypted data */ + unsigned char *wptr; /* write pointer into the payload to where we + are currently writing decrypted data */ + + /* ------------- for outgoing data --------------- */ + unsigned char outbuf[MAX_SSH_PACKET_LEN]; /* area for the outgoing data */ + + int ototal_num; /* size of outbuf in number of bytes */ + const unsigned char *odata; /* original pointer to the data */ + size_t olen; /* original size of the data we stored in + outbuf */ + size_t osent; /* number of bytes already sent */ +}; + +struct _LIBSSH2_PUBLICKEY +{ + LIBSSH2_CHANNEL *channel; + uint32_t version; + + /* State variables used in libssh2_publickey_packet_receive() */ + libssh2_nonblocking_states receive_state; + unsigned char *receive_packet; + size_t receive_packet_len; + + /* State variables used in libssh2_publickey_add_ex() */ + libssh2_nonblocking_states add_state; + unsigned char *add_packet; + unsigned char *add_s; + + /* State variables used in libssh2_publickey_remove_ex() */ + libssh2_nonblocking_states remove_state; + unsigned char *remove_packet; + unsigned char *remove_s; + + /* State variables used in libssh2_publickey_list_fetch() */ + libssh2_nonblocking_states listFetch_state; + unsigned char *listFetch_s; + unsigned char listFetch_buffer[12]; + unsigned char *listFetch_data; + size_t listFetch_data_len; +}; + +#define LIBSSH2_SCP_RESPONSE_BUFLEN 256 + +struct flags { + int sigpipe; /* LIBSSH2_FLAG_SIGPIPE */ + int compress; /* LIBSSH2_FLAG_COMPRESS */ +}; + +struct _LIBSSH2_SESSION +{ + /* Memory management callbacks */ + void *abstract; + LIBSSH2_ALLOC_FUNC((*alloc)); + LIBSSH2_REALLOC_FUNC((*realloc)); + LIBSSH2_FREE_FUNC((*free)); + + /* Other callbacks */ + LIBSSH2_IGNORE_FUNC((*ssh_msg_ignore)); + LIBSSH2_DEBUG_FUNC((*ssh_msg_debug)); + LIBSSH2_DISCONNECT_FUNC((*ssh_msg_disconnect)); + LIBSSH2_MACERROR_FUNC((*macerror)); + LIBSSH2_X11_OPEN_FUNC((*x11)); + LIBSSH2_SEND_FUNC((*send)); + LIBSSH2_RECV_FUNC((*recv)); + + /* Method preferences -- NULL yields "load order" */ + char *kex_prefs; + char *hostkey_prefs; + + int state; + + /* Flag options */ + struct flags flag; + + /* Agreed Key Exchange Method */ + const LIBSSH2_KEX_METHOD *kex; + int burn_optimistic_kexinit:1; + + unsigned char *session_id; + uint32_t session_id_len; + + /* this is set to TRUE if a blocking API behavior is requested */ + int api_block_mode; + + /* Timeout used when blocking API behavior is active */ + long api_timeout; + + /* Server's public key */ + const LIBSSH2_HOSTKEY_METHOD *hostkey; + void *server_hostkey_abstract; + + /* Either set with libssh2_session_hostkey() (for server mode) + * Or read from server in (eg) KEXDH_INIT (for client mode) + */ + unsigned char *server_hostkey; + uint32_t server_hostkey_len; +#if LIBSSH2_MD5 + unsigned char server_hostkey_md5[MD5_DIGEST_LENGTH]; +#endif /* ! LIBSSH2_MD5 */ + unsigned char server_hostkey_sha1[SHA_DIGEST_LENGTH]; + + /* (remote as source of data -- packet_read ) */ + libssh2_endpoint_data remote; + + /* (local as source of data -- packet_write ) */ + libssh2_endpoint_data local; + + /* Inbound Data linked list -- Sometimes the packet that comes in isn't the + packet we're ready for */ + struct list_head packets; + + /* Active connection channels */ + struct list_head channels; + + uint32_t next_channel; + + struct list_head listeners; /* list of LIBSSH2_LISTENER structs */ + + /* Actual I/O socket */ + libssh2_socket_t socket_fd; + int socket_state; + int socket_block_directions; + int socket_prev_blockstate; /* stores the state of the socket blockiness + when libssh2_session_startup() is called */ + + /* Error tracking */ + const char *err_msg; + int err_code; + + /* struct members for packet-level reading */ + struct transportpacket packet; +#ifdef LIBSSH2DEBUG + int showmask; /* what debug/trace messages to display */ + libssh2_trace_handler_func tracehandler; /* callback to display trace messages */ + void* tracehandler_context; /* context for the trace handler */ +#endif + + /* State variables used in libssh2_banner_send() */ + libssh2_nonblocking_states banner_TxRx_state; + char banner_TxRx_banner[256]; + ssize_t banner_TxRx_total_send; + + /* State variables used in libssh2_kexinit() */ + libssh2_nonblocking_states kexinit_state; + unsigned char *kexinit_data; + size_t kexinit_data_len; + + /* State variables used in libssh2_session_startup() */ + libssh2_nonblocking_states startup_state; + unsigned char *startup_data; + size_t startup_data_len; + unsigned char startup_service[sizeof("ssh-userauth") + 5 - 1]; + size_t startup_service_length; + packet_require_state_t startup_req_state; + key_exchange_state_t startup_key_state; + + /* State variables used in libssh2_session_free() */ + libssh2_nonblocking_states free_state; + + /* State variables used in libssh2_session_disconnect_ex() */ + libssh2_nonblocking_states disconnect_state; + unsigned char disconnect_data[256 + 13]; + size_t disconnect_data_len; + + /* State variables used in libssh2_packet_read() */ + libssh2_nonblocking_states readPack_state; + int readPack_encrypted; + + /* State variables used in libssh2_userauth_list() */ + libssh2_nonblocking_states userauth_list_state; + unsigned char *userauth_list_data; + size_t userauth_list_data_len; + packet_requirev_state_t userauth_list_packet_requirev_state; + + /* State variables used in libssh2_userauth_password_ex() */ + libssh2_nonblocking_states userauth_pswd_state; + unsigned char *userauth_pswd_data; + unsigned char userauth_pswd_data0; + size_t userauth_pswd_data_len; + char *userauth_pswd_newpw; + int userauth_pswd_newpw_len; + packet_requirev_state_t userauth_pswd_packet_requirev_state; + + /* State variables used in libssh2_userauth_hostbased_fromfile_ex() */ + libssh2_nonblocking_states userauth_host_state; + unsigned char *userauth_host_data; + size_t userauth_host_data_len; + unsigned char *userauth_host_packet; + size_t userauth_host_packet_len; + unsigned char *userauth_host_method; + size_t userauth_host_method_len; + unsigned char *userauth_host_s; + packet_requirev_state_t userauth_host_packet_requirev_state; + + /* State variables used in libssh2_userauth_publickey_fromfile_ex() */ + libssh2_nonblocking_states userauth_pblc_state; + unsigned char *userauth_pblc_data; + size_t userauth_pblc_data_len; + unsigned char *userauth_pblc_packet; + size_t userauth_pblc_packet_len; + unsigned char *userauth_pblc_method; + size_t userauth_pblc_method_len; + unsigned char *userauth_pblc_s; + unsigned char *userauth_pblc_b; + packet_requirev_state_t userauth_pblc_packet_requirev_state; + + /* State variables used in libssh2_userauth_keyboard_interactive_ex() */ + libssh2_nonblocking_states userauth_kybd_state; + unsigned char *userauth_kybd_data; + size_t userauth_kybd_data_len; + unsigned char *userauth_kybd_packet; + size_t userauth_kybd_packet_len; + unsigned int userauth_kybd_auth_name_len; + char *userauth_kybd_auth_name; + unsigned userauth_kybd_auth_instruction_len; + char *userauth_kybd_auth_instruction; + unsigned int userauth_kybd_num_prompts; + int userauth_kybd_auth_failure; + LIBSSH2_USERAUTH_KBDINT_PROMPT *userauth_kybd_prompts; + LIBSSH2_USERAUTH_KBDINT_RESPONSE *userauth_kybd_responses; + packet_requirev_state_t userauth_kybd_packet_requirev_state; + + /* State variables used in libssh2_channel_open_ex() */ + libssh2_nonblocking_states open_state; + packet_requirev_state_t open_packet_requirev_state; + LIBSSH2_CHANNEL *open_channel; + unsigned char *open_packet; + size_t open_packet_len; + unsigned char *open_data; + size_t open_data_len; + uint32_t open_local_channel; + + /* State variables used in libssh2_channel_direct_tcpip_ex() */ + libssh2_nonblocking_states direct_state; + unsigned char *direct_message; + size_t direct_host_len; + size_t direct_shost_len; + size_t direct_message_len; + + /* State variables used in libssh2_channel_forward_listen_ex() */ + libssh2_nonblocking_states fwdLstn_state; + unsigned char *fwdLstn_packet; + uint32_t fwdLstn_host_len; + uint32_t fwdLstn_packet_len; + packet_requirev_state_t fwdLstn_packet_requirev_state; + + /* State variables used in libssh2_publickey_init() */ + libssh2_nonblocking_states pkeyInit_state; + LIBSSH2_PUBLICKEY *pkeyInit_pkey; + LIBSSH2_CHANNEL *pkeyInit_channel; + unsigned char *pkeyInit_data; + size_t pkeyInit_data_len; + /* 19 = packet_len(4) + version_len(4) + "version"(7) + version_num(4) */ + unsigned char pkeyInit_buffer[19]; + size_t pkeyInit_buffer_sent; /* how much of buffer that has been sent */ + + /* State variables used in libssh2_packet_add() */ + libssh2_nonblocking_states packAdd_state; + LIBSSH2_CHANNEL *packAdd_channelp; /* keeper of the channel during EAGAIN + states */ + packet_queue_listener_state_t packAdd_Qlstn_state; + packet_x11_open_state_t packAdd_x11open_state; + + /* State variables used in fullpacket() */ + libssh2_nonblocking_states fullpacket_state; + int fullpacket_macstate; + size_t fullpacket_payload_len; + int fullpacket_packet_type; + + /* State variables used in libssh2_sftp_init() */ + libssh2_nonblocking_states sftpInit_state; + LIBSSH2_SFTP *sftpInit_sftp; + LIBSSH2_CHANNEL *sftpInit_channel; + unsigned char sftpInit_buffer[9]; /* sftp_header(5){excludes request_id} + + version_id(4) */ + int sftpInit_sent; /* number of bytes from the buffer that have been + sent */ + + /* State variables used in libssh2_scp_recv() */ + libssh2_nonblocking_states scpRecv_state; + unsigned char *scpRecv_command; + size_t scpRecv_command_len; + unsigned char scpRecv_response[LIBSSH2_SCP_RESPONSE_BUFLEN]; + size_t scpRecv_response_len; + long scpRecv_mode; +#if defined(HAVE_LONGLONG) && defined(HAVE_STRTOLL) + /* we have the type and we can parse such numbers */ + long long scpRecv_size; +#define scpsize_strtol strtoll +#else + long scpRecv_size; +#define scpsize_strtol strtol +#endif + long scpRecv_mtime; + long scpRecv_atime; + LIBSSH2_CHANNEL *scpRecv_channel; + + /* State variables used in libssh2_scp_send_ex() */ + libssh2_nonblocking_states scpSend_state; + unsigned char *scpSend_command; + size_t scpSend_command_len; + unsigned char scpSend_response[LIBSSH2_SCP_RESPONSE_BUFLEN]; + size_t scpSend_response_len; + LIBSSH2_CHANNEL *scpSend_channel; + + /* Keepalive variables used by keepalive.c. */ + int keepalive_interval; + int keepalive_want_reply; + time_t keepalive_last_sent; +}; + +/* session.state bits */ +#define LIBSSH2_STATE_EXCHANGING_KEYS 0x00000001 +#define LIBSSH2_STATE_NEWKEYS 0x00000002 +#define LIBSSH2_STATE_AUTHENTICATED 0x00000004 +#define LIBSSH2_STATE_KEX_ACTIVE 0x00000008 + +/* session.flag helpers */ +#ifdef MSG_NOSIGNAL +#define LIBSSH2_SOCKET_SEND_FLAGS(session) \ + (((session)->flag.sigpipe) ? 0 : MSG_NOSIGNAL) +#define LIBSSH2_SOCKET_RECV_FLAGS(session) \ + (((session)->flag.sigpipe) ? 0 : MSG_NOSIGNAL) +#else +/* If MSG_NOSIGNAL isn't defined we're SOL on blocking SIGPIPE */ +#define LIBSSH2_SOCKET_SEND_FLAGS(session) 0 +#define LIBSSH2_SOCKET_RECV_FLAGS(session) 0 +#endif + +/* --------- */ + +/* libssh2 extensible ssh api, ultimately I'd like to allow loading additional + methods via .so/.dll */ + +struct _LIBSSH2_KEX_METHOD +{ + const char *name; + + /* Key exchange, populates session->* and returns 0 on success, non-0 on error */ + int (*exchange_keys) (LIBSSH2_SESSION * session, + key_exchange_state_low_t * key_state); + + long flags; +}; + +struct _LIBSSH2_HOSTKEY_METHOD +{ + const char *name; + unsigned long hash_len; + + int (*init) (LIBSSH2_SESSION * session, const unsigned char *hostkey_data, + size_t hostkey_data_len, void **abstract); + int (*initPEM) (LIBSSH2_SESSION * session, const char *privkeyfile, + unsigned const char *passphrase, void **abstract); + int (*sig_verify) (LIBSSH2_SESSION * session, const unsigned char *sig, + size_t sig_len, const unsigned char *m, + size_t m_len, void **abstract); + int (*signv) (LIBSSH2_SESSION * session, unsigned char **signature, + size_t *signature_len, int veccount, + const struct iovec datavec[], void **abstract); + int (*encrypt) (LIBSSH2_SESSION * session, unsigned char **dst, + size_t *dst_len, const unsigned char *src, + size_t src_len, void **abstract); + int (*dtor) (LIBSSH2_SESSION * session, void **abstract); +}; + +struct _LIBSSH2_CRYPT_METHOD +{ + const char *name; + + int blocksize; + + /* iv and key sizes (-1 for variable length) */ + int iv_len; + int secret_len; + + long flags; + + int (*init) (LIBSSH2_SESSION * session, + const LIBSSH2_CRYPT_METHOD * method, unsigned char *iv, + int *free_iv, unsigned char *secret, int *free_secret, + int encrypt, void **abstract); + int (*crypt) (LIBSSH2_SESSION * session, unsigned char *block, + void **abstract); + int (*dtor) (LIBSSH2_SESSION * session, void **abstract); + + _libssh2_cipher_type(algo); +}; + +struct _LIBSSH2_COMP_METHOD +{ + const char *name; + int compress; /* 1 if it does compress, 0 if it doesn't */ + int (*init) (LIBSSH2_SESSION *session, int compress, void **abstract); + int (*comp) (LIBSSH2_SESSION *session, + unsigned char *dest, + size_t *dest_len, + const unsigned char *src, + size_t src_len, + void **abstract); + int (*decomp) (LIBSSH2_SESSION *session, + unsigned char **dest, + size_t *dest_len, + size_t payload_limit, + const unsigned char *src, + size_t src_len, + void **abstract); + int (*dtor) (LIBSSH2_SESSION * session, int compress, void **abstract); +}; + +#ifdef LIBSSH2DEBUG +void _libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, + ...); +#else +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || defined(__GNUC__) +/* C99 supported and also by older GCC */ +#define _libssh2_debug(x,y,z,...) do {} while (0) +#else +/* no gcc and not C99, do static and hopefully inline */ +static inline void +_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) +{ +} +#endif +#endif + +#define LIBSSH2_SOCKET_UNKNOWN 1 +#define LIBSSH2_SOCKET_CONNECTED 0 +#define LIBSSH2_SOCKET_DISCONNECTED -1 + +/* Initial packet state, prior to MAC check */ +#define LIBSSH2_MAC_UNCONFIRMED 1 +/* When MAC type is "none" (proto initiation phase) all packets are deemed "confirmed" */ +#define LIBSSH2_MAC_CONFIRMED 0 +/* Something very bad is going on */ +#define LIBSSH2_MAC_INVALID -1 + +/* SSH Packet Types -- Defined by internet draft */ +/* Transport Layer */ +#define SSH_MSG_DISCONNECT 1 +#define SSH_MSG_IGNORE 2 +#define SSH_MSG_UNIMPLEMENTED 3 +#define SSH_MSG_DEBUG 4 +#define SSH_MSG_SERVICE_REQUEST 5 +#define SSH_MSG_SERVICE_ACCEPT 6 + +#define SSH_MSG_KEXINIT 20 +#define SSH_MSG_NEWKEYS 21 + +/* diffie-hellman-group1-sha1 */ +#define SSH_MSG_KEXDH_INIT 30 +#define SSH_MSG_KEXDH_REPLY 31 + +/* diffie-hellman-group-exchange-sha1 */ +#define SSH_MSG_KEX_DH_GEX_REQUEST_OLD 30 +#define SSH_MSG_KEX_DH_GEX_REQUEST 34 +#define SSH_MSG_KEX_DH_GEX_GROUP 31 +#define SSH_MSG_KEX_DH_GEX_INIT 32 +#define SSH_MSG_KEX_DH_GEX_REPLY 33 + +/* User Authentication */ +#define SSH_MSG_USERAUTH_REQUEST 50 +#define SSH_MSG_USERAUTH_FAILURE 51 +#define SSH_MSG_USERAUTH_SUCCESS 52 +#define SSH_MSG_USERAUTH_BANNER 53 + +/* "public key" method */ +#define SSH_MSG_USERAUTH_PK_OK 60 +/* "password" method */ +#define SSH_MSG_USERAUTH_PASSWD_CHANGEREQ 60 +/* "keyboard-interactive" method */ +#define SSH_MSG_USERAUTH_INFO_REQUEST 60 +#define SSH_MSG_USERAUTH_INFO_RESPONSE 61 + +/* Channels */ +#define SSH_MSG_GLOBAL_REQUEST 80 +#define SSH_MSG_REQUEST_SUCCESS 81 +#define SSH_MSG_REQUEST_FAILURE 82 + +#define SSH_MSG_CHANNEL_OPEN 90 +#define SSH_MSG_CHANNEL_OPEN_CONFIRMATION 91 +#define SSH_MSG_CHANNEL_OPEN_FAILURE 92 +#define SSH_MSG_CHANNEL_WINDOW_ADJUST 93 +#define SSH_MSG_CHANNEL_DATA 94 +#define SSH_MSG_CHANNEL_EXTENDED_DATA 95 +#define SSH_MSG_CHANNEL_EOF 96 +#define SSH_MSG_CHANNEL_CLOSE 97 +#define SSH_MSG_CHANNEL_REQUEST 98 +#define SSH_MSG_CHANNEL_SUCCESS 99 +#define SSH_MSG_CHANNEL_FAILURE 100 + +/* Error codes returned in SSH_MSG_CHANNEL_OPEN_FAILURE message + (see RFC4254) */ +#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1 +#define SSH_OPEN_CONNECT_FAILED 2 +#define SSH_OPEN_UNKNOWN_CHANNELTYPE 3 +#define SSH_OPEN_RESOURCE_SHORTAGE 4 + +ssize_t _libssh2_recv(libssh2_socket_t socket, void *buffer, + size_t length, int flags, void **abstract); +ssize_t _libssh2_send(libssh2_socket_t socket, const void *buffer, + size_t length, int flags, void **abstract); + +#define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when + waiting for more data to arrive */ + + +int _libssh2_kex_exchange(LIBSSH2_SESSION * session, int reexchange, + key_exchange_state_t * state); + +/* Let crypt.c/hostkey.c expose their method structs */ +const LIBSSH2_CRYPT_METHOD **libssh2_crypt_methods(void); +const LIBSSH2_HOSTKEY_METHOD **libssh2_hostkey_methods(void); + +/* pem.c */ +int _libssh2_pem_parse(LIBSSH2_SESSION * session, + const char *headerbegin, + const char *headerend, + FILE * fp, unsigned char **data, unsigned int *datalen); +int _libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen); +int _libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, + unsigned char **i, unsigned int *ilen); + +/* global.c */ +void _libssh2_init_if_needed (void); + + +#define ARRAY_SIZE(a) (sizeof ((a)) / sizeof ((a)[0])) + +/* define to output the libssh2_int64_t type in a *printf() */ +#if defined( __BORLANDC__ ) || defined( _MSC_VER ) || defined( __MINGW32__ ) +#define LIBSSH2_INT64_T_FORMAT "I64" +#else +#define LIBSSH2_INT64_T_FORMAT "ll" +#endif + +#endif /* LIBSSH2_H */ diff --git a/vendor/libssh2-1.4.2/src/mac.c b/vendor/libssh2-1.4.2/src/mac.c new file mode 100644 index 0000000..76894fc --- /dev/null +++ b/vendor/libssh2-1.4.2/src/mac.c @@ -0,0 +1,314 @@ +/* Copyright (c) 2004-2007, Sara Golemon + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" +#include "mac.h" + +#ifdef LIBSSH2_MAC_NONE +/* mac_none_MAC + * Minimalist MAC: No MAC + */ +static int +mac_none_MAC(LIBSSH2_SESSION * session, unsigned char *buf, + uint32_t seqno, const unsigned char *packet, + uint32_t packet_len, const unsigned char *addtl, + uint32_t addtl_len, void **abstract) +{ + return 0; +} + + + + +static LIBSSH2_MAC_METHOD mac_method_none = { + "none", + 0, + 0, + NULL, + mac_none_MAC, + NULL +}; +#endif /* LIBSSH2_MAC_NONE */ + +/* mac_method_common_init + * Initialize simple mac methods + */ +static int +mac_method_common_init(LIBSSH2_SESSION * session, unsigned char *key, + int *free_key, void **abstract) +{ + *abstract = key; + *free_key = 0; + (void) session; + + return 0; +} + + + +/* mac_method_common_dtor + * Cleanup simple mac methods + */ +static int +mac_method_common_dtor(LIBSSH2_SESSION * session, void **abstract) +{ + if (*abstract) { + LIBSSH2_FREE(session, *abstract); + } + *abstract = NULL; + + return 0; +} + + + +/* mac_method_hmac_sha1_hash + * Calculate hash using full sha1 value + */ +static int +mac_method_hmac_sha1_hash(LIBSSH2_SESSION * session, + unsigned char *buf, uint32_t seqno, + const unsigned char *packet, + uint32_t packet_len, + const unsigned char *addtl, + uint32_t addtl_len, void **abstract) +{ + libssh2_hmac_ctx ctx; + unsigned char seqno_buf[4]; + (void) session; + + _libssh2_htonu32(seqno_buf, seqno); + + libssh2_hmac_sha1_init(&ctx, *abstract, 20); + libssh2_hmac_update(ctx, seqno_buf, 4); + libssh2_hmac_update(ctx, packet, packet_len); + if (addtl && addtl_len) { + libssh2_hmac_update(ctx, addtl, addtl_len); + } + libssh2_hmac_final(ctx, buf); + libssh2_hmac_cleanup(&ctx); + + return 0; +} + + + +static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1 = { + "hmac-sha1", + 20, + 20, + mac_method_common_init, + mac_method_hmac_sha1_hash, + mac_method_common_dtor, +}; + +/* mac_method_hmac_sha1_96_hash + * Calculate hash using first 96 bits of sha1 value + */ +static int +mac_method_hmac_sha1_96_hash(LIBSSH2_SESSION * session, + unsigned char *buf, uint32_t seqno, + const unsigned char *packet, + uint32_t packet_len, + const unsigned char *addtl, + uint32_t addtl_len, void **abstract) +{ + unsigned char temp[SHA_DIGEST_LENGTH]; + + mac_method_hmac_sha1_hash(session, temp, seqno, packet, packet_len, + addtl, addtl_len, abstract); + memcpy(buf, (char *) temp, 96 / 8); + + return 0; +} + + + +static const LIBSSH2_MAC_METHOD mac_method_hmac_sha1_96 = { + "hmac-sha1-96", + 12, + 20, + mac_method_common_init, + mac_method_hmac_sha1_96_hash, + mac_method_common_dtor, +}; + +#if LIBSSH2_MD5 +/* mac_method_hmac_md5_hash + * Calculate hash using full md5 value + */ +static int +mac_method_hmac_md5_hash(LIBSSH2_SESSION * session, unsigned char *buf, + uint32_t seqno, + const unsigned char *packet, + uint32_t packet_len, + const unsigned char *addtl, + uint32_t addtl_len, void **abstract) +{ + libssh2_hmac_ctx ctx; + unsigned char seqno_buf[4]; + (void) session; + + _libssh2_htonu32(seqno_buf, seqno); + + libssh2_hmac_md5_init(&ctx, *abstract, 16); + libssh2_hmac_update(ctx, seqno_buf, 4); + libssh2_hmac_update(ctx, packet, packet_len); + if (addtl && addtl_len) { + libssh2_hmac_update(ctx, addtl, addtl_len); + } + libssh2_hmac_final(ctx, buf); + libssh2_hmac_cleanup(&ctx); + + return 0; +} + + + +static const LIBSSH2_MAC_METHOD mac_method_hmac_md5 = { + "hmac-md5", + 16, + 16, + mac_method_common_init, + mac_method_hmac_md5_hash, + mac_method_common_dtor, +}; + +/* mac_method_hmac_md5_96_hash + * Calculate hash using first 96 bits of md5 value + */ +static int +mac_method_hmac_md5_96_hash(LIBSSH2_SESSION * session, + unsigned char *buf, uint32_t seqno, + const unsigned char *packet, + uint32_t packet_len, + const unsigned char *addtl, + uint32_t addtl_len, void **abstract) +{ + unsigned char temp[MD5_DIGEST_LENGTH]; + mac_method_hmac_md5_hash(session, temp, seqno, packet, packet_len, + addtl, addtl_len, abstract); + memcpy(buf, (char *) temp, 96 / 8); + return 0; +} + + + +static const LIBSSH2_MAC_METHOD mac_method_hmac_md5_96 = { + "hmac-md5-96", + 12, + 16, + mac_method_common_init, + mac_method_hmac_md5_96_hash, + mac_method_common_dtor, +}; +#endif /* LIBSSH2_MD5 */ + +#if LIBSSH2_HMAC_RIPEMD +/* mac_method_hmac_ripemd160_hash + * Calculate hash using ripemd160 value + */ +static int +mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION * session, + unsigned char *buf, uint32_t seqno, + const unsigned char *packet, + uint32_t packet_len, + const unsigned char *addtl, + uint32_t addtl_len, + void **abstract) +{ + libssh2_hmac_ctx ctx; + unsigned char seqno_buf[4]; + (void) session; + + _libssh2_htonu32(seqno_buf, seqno); + + libssh2_hmac_ripemd160_init(&ctx, *abstract, 20); + libssh2_hmac_update(ctx, seqno_buf, 4); + libssh2_hmac_update(ctx, packet, packet_len); + if (addtl && addtl_len) { + libssh2_hmac_update(ctx, addtl, addtl_len); + } + libssh2_hmac_final(ctx, buf); + libssh2_hmac_cleanup(&ctx); + + return 0; +} + + + +static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160 = { + "hmac-ripemd160", + 20, + 20, + mac_method_common_init, + mac_method_hmac_ripemd160_hash, + mac_method_common_dtor, +}; + +static const LIBSSH2_MAC_METHOD mac_method_hmac_ripemd160_openssh_com = { + "hmac-ripemd160@openssh.com", + 20, + 20, + mac_method_common_init, + mac_method_hmac_ripemd160_hash, + mac_method_common_dtor, +}; +#endif /* LIBSSH2_HMAC_RIPEMD */ + +static const LIBSSH2_MAC_METHOD *mac_methods[] = { + &mac_method_hmac_sha1, + &mac_method_hmac_sha1_96, +#if LIBSSH2_MD5 + &mac_method_hmac_md5, + &mac_method_hmac_md5_96, +#endif +#if LIBSSH2_HMAC_RIPEMD + &mac_method_hmac_ripemd160, + &mac_method_hmac_ripemd160_openssh_com, +#endif /* LIBSSH2_HMAC_RIPEMD */ +#ifdef LIBSSH2_MAC_NONE + &mac_method_none, +#endif /* LIBSSH2_MAC_NONE */ + NULL +}; + +const LIBSSH2_MAC_METHOD ** +_libssh2_mac_methods(void) +{ + return mac_methods; +} diff --git a/vendor/libssh2-1.4.2/src/mac.h b/vendor/libssh2-1.4.2/src/mac.h new file mode 100644 index 0000000..66d3e61 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/mac.h @@ -0,0 +1,67 @@ +#ifndef __LIBSSH2_MAC_H +#define __LIBSSH2_MAC_H + +/* Copyright (C) 2009-2010 by Daniel Stenberg + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +#include "libssh2_priv.h" + +struct _LIBSSH2_MAC_METHOD +{ + const char *name; + + /* The length of a given MAC packet */ + int mac_len; + + /* integrity key length */ + int key_len; + + /* Message Authentication Code Hashing algo */ + int (*init) (LIBSSH2_SESSION * session, unsigned char *key, int *free_key, + void **abstract); + int (*hash) (LIBSSH2_SESSION * session, unsigned char *buf, + uint32_t seqno, const unsigned char *packet, + uint32_t packet_len, const unsigned char *addtl, + uint32_t addtl_len, void **abstract); + int (*dtor) (LIBSSH2_SESSION * session, void **abstract); +}; + +typedef struct _LIBSSH2_MAC_METHOD LIBSSH2_MAC_METHOD; + +const LIBSSH2_MAC_METHOD **_libssh2_mac_methods(void); + +#endif /* __LIBSSH2_MAC_H */ diff --git a/vendor/libssh2-1.4.2/src/misc.c b/vendor/libssh2-1.4.2/src/misc.c new file mode 100644 index 0000000..a9f423a --- /dev/null +++ b/vendor/libssh2-1.4.2/src/misc.c @@ -0,0 +1,612 @@ +/* Copyright (c) 2004-2007 Sara Golemon + * Copyright (c) 2009-2010 by Daniel Stenberg + * Copyright (c) 2010 Simon Josefsson + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" +#include "misc.h" + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include +#include + +int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char* errmsg) +{ + session->err_msg = errmsg; + session->err_code = errcode; +#ifdef LIBSSH2DEBUG + if((errcode == LIBSSH2_ERROR_EAGAIN) && !session->api_block_mode) + /* if this is EAGAIN and we're in non-blocking mode, don't generate + a debug output for this */ + return errcode; + _libssh2_debug(session, LIBSSH2_TRACE_ERROR, "%d - %s", session->err_code, + session->err_msg); +#endif + + return errcode; +} + +#ifdef WIN32 +static int wsa2errno(void) +{ + switch (WSAGetLastError()) { + case WSAEWOULDBLOCK: + return EAGAIN; + + case WSAENOTSOCK: + return EBADF; + + case WSAEINTR: + return EINTR; + + default: + /* It is most important to ensure errno does not stay at EAGAIN + * when a different error occurs so just set errno to a generic + * error */ + return EIO; + } +} +#endif + +/* _libssh2_recv + * + * Replacement for the standard recv, return -errno on failure. + */ +ssize_t +_libssh2_recv(libssh2_socket_t sock, void *buffer, size_t length, int flags, void **abstract) +{ + ssize_t rc = recv(sock, buffer, length, flags); +#ifdef WIN32 + if (rc < 0 ) + return -wsa2errno(); +#elif defined(__VMS) + if (rc < 0 ){ + if ( errno == EWOULDBLOCK ) + return -EAGAIN; + else + return -errno; + } +#else + if (rc < 0 ){ + /* Sometimes the first recv() function call sets errno to ENOENT on + Solaris and HP-UX */ + if ( errno == ENOENT ) + return -EAGAIN; + else + return -errno; + } +#endif + return rc; +} + +/* _libssh2_send + * + * Replacement for the standard send, return -errno on failure. + */ +ssize_t +_libssh2_send(libssh2_socket_t sock, const void *buffer, size_t length, + int flags, void **abstract) +{ + ssize_t rc = send(sock, buffer, length, flags); +#ifdef WIN32 + if (rc < 0 ) + return -wsa2errno(); +#elif defined(__VMS) + if (rc < 0 ) { + if ( errno == EWOULDBLOCK ) + return -EAGAIN; + else + return -errno; + } +#else + if (rc < 0 ) + return -errno; +#endif + return rc; +} + +/* libssh2_ntohu32 + */ +unsigned int +_libssh2_ntohu32(const unsigned char *buf) +{ + return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; +} + + +/* _libssh2_ntohu64 + */ +libssh2_uint64_t +_libssh2_ntohu64(const unsigned char *buf) +{ + unsigned long msl, lsl; + + msl = ((libssh2_uint64_t)buf[0] << 24) | ((libssh2_uint64_t)buf[1] << 16) + | ((libssh2_uint64_t)buf[2] << 8) | (libssh2_uint64_t)buf[3]; + lsl = ((libssh2_uint64_t)buf[4] << 24) | ((libssh2_uint64_t)buf[5] << 16) + | ((libssh2_uint64_t)buf[6] << 8) | (libssh2_uint64_t)buf[7]; + + return ((libssh2_uint64_t)msl <<32) | lsl; +} + +/* _libssh2_htonu32 + */ +void +_libssh2_htonu32(unsigned char *buf, uint32_t value) +{ + buf[0] = (value >> 24) & 0xFF; + buf[1] = (value >> 16) & 0xFF; + buf[2] = (value >> 8) & 0xFF; + buf[3] = value & 0xFF; +} + +/* _libssh2_store_u32 + */ +void _libssh2_store_u32(unsigned char **buf, uint32_t value) +{ + _libssh2_htonu32(*buf, value); + *buf += sizeof(uint32_t); +} + +/* _libssh2_store_str + */ +void _libssh2_store_str(unsigned char **buf, const char *str, size_t len) +{ + _libssh2_store_u32(buf, (uint32_t)len); + if(len) { + memcpy(*buf, str, len); + *buf += len; + } +} + +/* Base64 Conversion */ + +static const char base64_table[] = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0' +}; + +static const char base64_pad = '='; + +static const short base64_reverse_table[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +/* libssh2_base64_decode + * + * Decode a base64 chunk and store it into a newly alloc'd buffer + */ +LIBSSH2_API int +libssh2_base64_decode(LIBSSH2_SESSION *session, char **data, + unsigned int *datalen, const char *src, + unsigned int src_len) +{ + unsigned char *s, *d; + short v; + int i = 0, len = 0; + + *data = LIBSSH2_ALLOC(session, (3 * src_len / 4) + 1); + d = (unsigned char *) *data; + if (!d) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for base64 decoding"); + } + + for(s = (unsigned char *) src; ((char *) s) < (src + src_len); s++) { + if ((v = base64_reverse_table[*s]) < 0) + continue; + switch (i % 4) { + case 0: + d[len] = v << 2; + break; + case 1: + d[len++] |= v >> 4; + d[len] = v << 4; + break; + case 2: + d[len++] |= v >> 2; + d[len] = v << 6; + break; + case 3: + d[len++] |= v; + break; + } + i++; + } + if ((i % 4) == 1) { + /* Invalid -- We have a byte which belongs exclusively to a partial + octet */ + LIBSSH2_FREE(session, *data); + return _libssh2_error(session, LIBSSH2_ERROR_INVAL, "Invalid base64"); + } + + *datalen = len; + return 0; +} + +/* ---- Base64 Encoding/Decoding Table --- */ +static const char table64[]= + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* + * _libssh2_base64_encode() + * + * Returns the length of the newly created base64 string. The third argument + * is a pointer to an allocated area holding the base64 data. If something + * went wrong, 0 is returned. + * + */ +size_t _libssh2_base64_encode(LIBSSH2_SESSION *session, + const char *inp, size_t insize, char **outptr) +{ + unsigned char ibuf[3]; + unsigned char obuf[4]; + int i; + int inputparts; + char *output; + char *base64data; + const char *indata = inp; + + *outptr = NULL; /* set to NULL in case of failure before we reach the end */ + + if(0 == insize) + insize = strlen(indata); + + base64data = output = LIBSSH2_ALLOC(session, insize*4/3+4); + if(NULL == output) + return 0; + + while(insize > 0) { + for (i = inputparts = 0; i < 3; i++) { + if(insize > 0) { + inputparts++; + ibuf[i] = *indata; + indata++; + insize--; + } + else + ibuf[i] = 0; + } + + obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2); + obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \ + ((ibuf[1] & 0xF0) >> 4)); + obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \ + ((ibuf[2] & 0xC0) >> 6)); + obuf[3] = (unsigned char) (ibuf[2] & 0x3F); + + switch(inputparts) { + case 1: /* only one byte read */ + snprintf(output, 5, "%c%c==", + table64[obuf[0]], + table64[obuf[1]]); + break; + case 2: /* two bytes read */ + snprintf(output, 5, "%c%c%c=", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]]); + break; + default: + snprintf(output, 5, "%c%c%c%c", + table64[obuf[0]], + table64[obuf[1]], + table64[obuf[2]], + table64[obuf[3]] ); + break; + } + output += 4; + } + *output=0; + *outptr = base64data; /* make it return the actual data memory */ + + return strlen(base64data); /* return the length of the new data */ +} +/* ---- End of Base64 Encoding ---- */ + +LIBSSH2_API void +libssh2_free(LIBSSH2_SESSION *session, void *ptr) +{ + LIBSSH2_FREE(session, ptr); +} + +#ifdef LIBSSH2DEBUG +LIBSSH2_API int +libssh2_trace(LIBSSH2_SESSION * session, int bitmask) +{ + session->showmask = bitmask; + return 0; +} + +LIBSSH2_API int +libssh2_trace_sethandler(LIBSSH2_SESSION *session, void* handler_context, + libssh2_trace_handler_func callback) +{ + session->tracehandler = callback; + session->tracehandler_context = handler_context; + return 0; +} + +void +_libssh2_debug(LIBSSH2_SESSION * session, int context, const char *format, ...) +{ + char buffer[1536]; + int len, msglen, buflen = sizeof(buffer); + va_list vargs; + struct timeval now; + static int firstsec; + static const char *const contexts[] = { + "Unknown", + "Transport", + "Key Ex", + "Userauth", + "Conn", + "SCP", + "SFTP", + "Failure Event", + "Publickey", + "Socket", + }; + const char* contexttext = contexts[0]; + unsigned int contextindex; + + if (!(session->showmask & context)) { + /* no such output asked for */ + return; + } + + /* Find the first matching context string for this message */ + for (contextindex = 0; contextindex < ARRAY_SIZE(contexts); + contextindex++) { + if ((context & (1 << contextindex)) != 0) { + contexttext = contexts[contextindex]; + break; + } + } + + _libssh2_gettimeofday(&now, NULL); + if(!firstsec) { + firstsec = now.tv_sec; + } + now.tv_sec -= firstsec; + + len = snprintf(buffer, buflen, "[libssh2] %d.%06d %s: ", + (int)now.tv_sec, (int)now.tv_usec, contexttext); + + if (len >= buflen) + msglen = buflen - 1; + else { + buflen -= len; + msglen = len; + va_start(vargs, format); + len = vsnprintf(buffer + msglen, buflen, format, vargs); + va_end(vargs); + msglen += len < buflen ? len : buflen - 1; + } + + if (session->tracehandler) + (session->tracehandler)(session, session->tracehandler_context, buffer, + msglen); + else + fprintf(stderr, "%s\n", buffer); +} + +#else +LIBSSH2_API int +libssh2_trace(LIBSSH2_SESSION * session, int bitmask) +{ + (void) session; + (void) bitmask; + return 0; +} + +LIBSSH2_API int +libssh2_trace_sethandler(LIBSSH2_SESSION *session, void* handler_context, + libssh2_trace_handler_func callback) +{ + (void) session; + (void) handler_context; + (void) callback; + return 0; +} +#endif + +/* init the list head */ +void _libssh2_list_init(struct list_head *head) +{ + head->first = head->last = NULL; +} + +/* add a node to the list */ +void _libssh2_list_add(struct list_head *head, + struct list_node *entry) +{ + /* store a pointer to the head */ + entry->head = head; + + /* we add this entry at the "top" so it has no next */ + entry->next = NULL; + + /* make our prev point to what the head thinks is last */ + entry->prev = head->last; + + /* and make head's last be us now */ + head->last = entry; + + /* make sure our 'prev' node points to us next */ + if(entry->prev) + entry->prev->next = entry; + else + head->first = entry; +} + +/* return the "first" node in the list this head points to */ +void *_libssh2_list_first(struct list_head *head) +{ + return head->first; +} + +/* return the next node in the list */ +void *_libssh2_list_next(struct list_node *node) +{ + return node->next; +} + +/* return the prev node in the list */ +void *_libssh2_list_prev(struct list_node *node) +{ + return node->prev; +} + +/* remove this node from the list */ +void _libssh2_list_remove(struct list_node *entry) +{ + if(entry->prev) + entry->prev->next = entry->next; + else + entry->head->first = entry->next; + + if(entry->next) + entry->next->prev = entry->prev; + else + entry->head->last = entry->prev; +} + +#if 0 +/* insert a node before the given 'after' entry */ +void _libssh2_list_insert(struct list_node *after, /* insert before this */ + struct list_node *entry) +{ + /* 'after' is next to 'entry' */ + bentry->next = after; + + /* entry's prev is then made to be the prev after current has */ + entry->prev = after->prev; + + /* the node that is now before 'entry' was previously before 'after' + and must be made to point to 'entry' correctly */ + if(entry->prev) + entry->prev->next = entry; + else + /* there was no node before this, so we make sure we point the head + pointer to this node */ + after->head->first = entry; + + /* after's prev entry points back to entry */ + after->prev = entry; + + /* after's next entry is still the same as before */ + + /* entry's head is the same as after's */ + entry->head = after->head; +} + +#endif + +/* this define is defined in misc.h for the correct platforms */ +#ifdef LIBSSH2_GETTIMEOFDAY_WIN32 +/* + * gettimeofday + * Implementation according to: + * The Open Group Base Specifications Issue 6 + * IEEE Std 1003.1, 2004 Edition + */ + +/* + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Contributed by: + * Danny Smith + */ + +/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */ +#define _W32_FT_OFFSET (116444736000000000) + +int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp) + { + union { + unsigned __int64 ns100; /*time since 1 Jan 1601 in 100ns units */ + FILETIME ft; + } _now; + + if(tp) + { + GetSystemTimeAsFileTime (&_now.ft); + tp->tv_usec=(long)((_now.ns100 / 10) % 1000000 ); + tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000); + } + /* Always return 0 as per Open Group Base Specifications Issue 6. + Do not set errno on error. */ + return 0; +} + + +#endif diff --git a/vendor/libssh2-1.4.2/src/misc.h b/vendor/libssh2-1.4.2/src/misc.h new file mode 100644 index 0000000..e25248d --- /dev/null +++ b/vendor/libssh2-1.4.2/src/misc.h @@ -0,0 +1,94 @@ +#ifndef __LIBSSH2_MISC_H +#define __LIBSSH2_MISC_H +/* Copyright (c) 2009-2011 by Daniel Stenberg + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +struct list_head { + struct list_node *last; + struct list_node *first; +}; + +struct list_node { + struct list_node *next; + struct list_node *prev; + struct list_head *head; +}; + +int _libssh2_error(LIBSSH2_SESSION* session, int errcode, const char* errmsg); + +void _libssh2_list_init(struct list_head *head); + +/* add a node last in the list */ +void _libssh2_list_add(struct list_head *head, + struct list_node *entry); + +/* return the "first" node in the list this head points to */ +void *_libssh2_list_first(struct list_head *head); + +/* return the next node in the list */ +void *_libssh2_list_next(struct list_node *node); + +/* return the prev node in the list */ +void *_libssh2_list_prev(struct list_node *node); + +/* remove this node from the list */ +void _libssh2_list_remove(struct list_node *entry); + +size_t _libssh2_base64_encode(struct _LIBSSH2_SESSION *session, + const char *inp, size_t insize, char **outptr); + +unsigned int _libssh2_ntohu32(const unsigned char *buf); +libssh2_uint64_t _libssh2_ntohu64(const unsigned char *buf); +void _libssh2_htonu32(unsigned char *buf, uint32_t val); +void _libssh2_store_u32(unsigned char **buf, uint32_t value); +void _libssh2_store_str(unsigned char **buf, const char *str, size_t len); + +#if defined(LIBSSH2_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) +/* provide a private one */ +#undef HAVE_GETTIMEOFDAY +int __cdecl _libssh2_gettimeofday(struct timeval *tp, void *tzp); +#define HAVE_LIBSSH2_GETTIMEOFDAY +#define LIBSSH2_GETTIMEOFDAY_WIN32 /* enable the win32 implementation */ +#else +#ifdef HAVE_GETTIMEOFDAY +#define _libssh2_gettimeofday(x,y) gettimeofday(x,y) +#define HAVE_LIBSSH2_GETTIMEOFDAY +#endif +#endif + +#endif /* _LIBSSH2_MISC_H */ diff --git a/vendor/libssh2-1.4.2/src/openssl.c b/vendor/libssh2-1.4.2/src/openssl.c new file mode 100644 index 0000000..481982c --- /dev/null +++ b/vendor/libssh2-1.4.2/src/openssl.c @@ -0,0 +1,804 @@ +/* Copyright (C) 2009, 2010 Simon Josefsson + * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. + * Copyright (c) 2004-2006, Sara Golemon + * + * Author: Simon Josefsson + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" + +#ifndef LIBSSH2_LIBGCRYPT /* compile only if we build with OpenSSL */ + +#include + +#ifndef EVP_MAX_BLOCK_LENGTH +#define EVP_MAX_BLOCK_LENGTH 32 +#endif + +int +_libssh2_rsa_new(libssh2_rsa_ctx ** rsa, + const unsigned char *edata, + unsigned long elen, + const unsigned char *ndata, + unsigned long nlen, + const unsigned char *ddata, + unsigned long dlen, + const unsigned char *pdata, + unsigned long plen, + const unsigned char *qdata, + unsigned long qlen, + const unsigned char *e1data, + unsigned long e1len, + const unsigned char *e2data, + unsigned long e2len, + const unsigned char *coeffdata, unsigned long coefflen) +{ + *rsa = RSA_new(); + + (*rsa)->e = BN_new(); + BN_bin2bn(edata, elen, (*rsa)->e); + + (*rsa)->n = BN_new(); + BN_bin2bn(ndata, nlen, (*rsa)->n); + + if (ddata) { + (*rsa)->d = BN_new(); + BN_bin2bn(ddata, dlen, (*rsa)->d); + + (*rsa)->p = BN_new(); + BN_bin2bn(pdata, plen, (*rsa)->p); + + (*rsa)->q = BN_new(); + BN_bin2bn(qdata, qlen, (*rsa)->q); + + (*rsa)->dmp1 = BN_new(); + BN_bin2bn(e1data, e1len, (*rsa)->dmp1); + + (*rsa)->dmq1 = BN_new(); + BN_bin2bn(e2data, e2len, (*rsa)->dmq1); + + (*rsa)->iqmp = BN_new(); + BN_bin2bn(coeffdata, coefflen, (*rsa)->iqmp); + } + return 0; +} + +int +_libssh2_rsa_sha1_verify(libssh2_rsa_ctx * rsactx, + const unsigned char *sig, + unsigned long sig_len, + const unsigned char *m, unsigned long m_len) +{ + unsigned char hash[SHA_DIGEST_LENGTH]; + int ret; + + libssh2_sha1(m, m_len, hash); + ret = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH, + (unsigned char *) sig, sig_len, rsactx); + return (ret == 1) ? 0 : -1; +} + +#if LIBSSH2_DSA +int +_libssh2_dsa_new(libssh2_dsa_ctx ** dsactx, + const unsigned char *p, + unsigned long p_len, + const unsigned char *q, + unsigned long q_len, + const unsigned char *g, + unsigned long g_len, + const unsigned char *y, + unsigned long y_len, + const unsigned char *x, unsigned long x_len) +{ + *dsactx = DSA_new(); + + (*dsactx)->p = BN_new(); + BN_bin2bn(p, p_len, (*dsactx)->p); + + (*dsactx)->q = BN_new(); + BN_bin2bn(q, q_len, (*dsactx)->q); + + (*dsactx)->g = BN_new(); + BN_bin2bn(g, g_len, (*dsactx)->g); + + (*dsactx)->pub_key = BN_new(); + BN_bin2bn(y, y_len, (*dsactx)->pub_key); + + if (x_len) { + (*dsactx)->priv_key = BN_new(); + BN_bin2bn(x, x_len, (*dsactx)->priv_key); + } + + return 0; +} + +int +_libssh2_dsa_sha1_verify(libssh2_dsa_ctx * dsactx, + const unsigned char *sig, + const unsigned char *m, unsigned long m_len) +{ + unsigned char hash[SHA_DIGEST_LENGTH]; + DSA_SIG dsasig; + int ret; + + dsasig.r = BN_new(); + BN_bin2bn(sig, 20, dsasig.r); + dsasig.s = BN_new(); + BN_bin2bn(sig + 20, 20, dsasig.s); + + libssh2_sha1(m, m_len, hash); + ret = DSA_do_verify(hash, SHA_DIGEST_LENGTH, &dsasig, dsactx); + BN_clear_free(dsasig.s); + BN_clear_free(dsasig.r); + + return (ret == 1) ? 0 : -1; +} +#endif /* LIBSSH_DSA */ + +int +_libssh2_cipher_init(_libssh2_cipher_ctx * h, + _libssh2_cipher_type(algo), + unsigned char *iv, unsigned char *secret, int encrypt) +{ + EVP_CIPHER_CTX_init(h); + EVP_CipherInit(h, algo(), secret, iv, encrypt); + return 0; +} + +int +_libssh2_cipher_crypt(_libssh2_cipher_ctx * ctx, + _libssh2_cipher_type(algo), + int encrypt, unsigned char *block) +{ + int blocksize = ctx->cipher->block_size; + unsigned char buf[EVP_MAX_BLOCK_LENGTH]; + int ret; + (void) algo; + (void) encrypt; + + if (blocksize == 1) { +/* Hack for arcfour. */ + blocksize = 8; + } + ret = EVP_Cipher(ctx, buf, block, blocksize); + if (ret == 1) { + memcpy(block, buf, blocksize); + } + return ret == 1 ? 0 : 1; +} + +#if LIBSSH2_AES_CTR + +#include +#include + +typedef struct +{ + AES_KEY key; + EVP_CIPHER_CTX *aes_ctx; + unsigned char ctr[AES_BLOCK_SIZE]; +} aes_ctr_ctx; + +static int +aes_ctr_init(EVP_CIPHER_CTX *ctx, const unsigned char *key, + const unsigned char *iv, int enc) /* init key */ +{ + /* + * variable "c" is leaked from this scope, but is later freed + * in aes_ctr_cleanup + */ + aes_ctr_ctx *c = malloc(sizeof(*c)); + const EVP_CIPHER *aes_cipher; + (void) enc; + + if (c == NULL) + return 0; + + switch (ctx->key_len) { + case 16: + aes_cipher = EVP_aes_128_ecb(); + break; + case 24: + aes_cipher = EVP_aes_192_ecb(); + break; + case 32: + aes_cipher = EVP_aes_256_ecb(); + break; + default: + return 0; + } + c->aes_ctx = malloc(sizeof(EVP_CIPHER_CTX)); + if (c->aes_ctx == NULL) + return 0; + + if (EVP_EncryptInit(c->aes_ctx, aes_cipher, key, NULL) != 1) { + return 0; + } + + EVP_CIPHER_CTX_set_padding(c->aes_ctx, 0); + + memcpy(c->ctr, iv, AES_BLOCK_SIZE); + + EVP_CIPHER_CTX_set_app_data(ctx, c); + + return 1; +} + +static int +aes_ctr_do_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, + const unsigned char *in, + size_t inl) /* encrypt/decrypt data */ +{ + aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx); + unsigned char b1[AES_BLOCK_SIZE]; + size_t i = 0; + int outlen = 0; + + if (inl != 16) /* libssh2 only ever encrypt one block */ + return 0; + + if (c == NULL) { + return 0; + } + +/* + To encrypt a packet P=P1||P2||...||Pn (where P1, P2, ..., Pn are each + blocks of length L), the encryptor first encrypts with + to obtain a block B1. The block B1 is then XORed with P1 to generate + the ciphertext block C1. The counter X is then incremented +*/ + + if (EVP_EncryptUpdate(c->aes_ctx, b1, &outlen, c->ctr, AES_BLOCK_SIZE) != 1) { + return 0; + } + + for (i = 0; i < 16; i++) + *out++ = *in++ ^ b1[i]; + + i = 15; + while (c->ctr[i]++ == 0xFF) { + if (i == 0) + break; + i--; + } + + return 1; +} + +static int +aes_ctr_cleanup(EVP_CIPHER_CTX *ctx) /* cleanup ctx */ +{ + aes_ctr_ctx *c = EVP_CIPHER_CTX_get_app_data(ctx); + + if (c == NULL) { + return 1; + } + + if (c->aes_ctx != NULL) { + _libssh2_cipher_dtor(c->aes_ctx); + free(c->aes_ctx); + } + + free(c); + + return 1; +} + +static const EVP_CIPHER * +make_ctr_evp (size_t keylen, EVP_CIPHER *aes_ctr_cipher) +{ + aes_ctr_cipher->block_size = 16; + aes_ctr_cipher->key_len = keylen; + aes_ctr_cipher->iv_len = 16; + aes_ctr_cipher->init = aes_ctr_init; + aes_ctr_cipher->do_cipher = aes_ctr_do_cipher; + aes_ctr_cipher->cleanup = aes_ctr_cleanup; + + return aes_ctr_cipher; +} + +const EVP_CIPHER * +_libssh2_EVP_aes_128_ctr(void) +{ + static EVP_CIPHER aes_ctr_cipher; + return !aes_ctr_cipher.key_len? + make_ctr_evp (16, &aes_ctr_cipher) : &aes_ctr_cipher; +} + +const EVP_CIPHER * +_libssh2_EVP_aes_192_ctr(void) +{ + static EVP_CIPHER aes_ctr_cipher; + return !aes_ctr_cipher.key_len? + make_ctr_evp (24, &aes_ctr_cipher) : &aes_ctr_cipher; +} + +const EVP_CIPHER * +_libssh2_EVP_aes_256_ctr(void) +{ + static EVP_CIPHER aes_ctr_cipher; + return !aes_ctr_cipher.key_len? + make_ctr_evp (32, &aes_ctr_cipher) : &aes_ctr_cipher; +} + +void _libssh2_init_aes_ctr(void) +{ + _libssh2_EVP_aes_128_ctr(); + _libssh2_EVP_aes_192_ctr(); + _libssh2_EVP_aes_256_ctr(); +} + +#else +void _libssh2_init_aes_ctr(void) {} +#endif /* LIBSSH2_AES_CTR */ + +/* TODO: Optionally call a passphrase callback specified by the + * calling program + */ +static int +passphrase_cb(char *buf, int size, int rwflag, char *passphrase) +{ + int passphrase_len = strlen(passphrase); + (void) rwflag; + + if (passphrase_len > (size - 1)) { + passphrase_len = size - 1; + } + memcpy(buf, passphrase, passphrase_len); + buf[passphrase_len] = '\0'; + + return passphrase_len; +} + +typedef void * (*pem_read_bio_func)(BIO *, void **, pem_password_cb *, + void * u); + +static int +read_private_key_from_file(void ** key_ctx, + pem_read_bio_func read_private_key, + const char * filename, + unsigned const char *passphrase) +{ + BIO * bp; + + *key_ctx = NULL; + + bp = BIO_new_file(filename, "r"); + if (!bp) { + return -1; + } + + *key_ctx = read_private_key(bp, NULL, (pem_password_cb *) passphrase_cb, + (void *) passphrase); + + BIO_free(bp); + return (*key_ctx) ? 0 : -1; +} + +int +_libssh2_rsa_new_private(libssh2_rsa_ctx ** rsa, + LIBSSH2_SESSION * session, + const char *filename, unsigned const char *passphrase) +{ + pem_read_bio_func read_rsa = + (pem_read_bio_func) &PEM_read_bio_RSAPrivateKey; + (void) session; + + _libssh2_init_if_needed (); + + return read_private_key_from_file((void **) rsa, read_rsa, + filename, passphrase); +} + +#if LIBSSH2_DSA +int +_libssh2_dsa_new_private(libssh2_dsa_ctx ** dsa, + LIBSSH2_SESSION * session, + const char *filename, unsigned const char *passphrase) +{ + pem_read_bio_func read_dsa = + (pem_read_bio_func) &PEM_read_bio_DSAPrivateKey; + (void) session; + + _libssh2_init_if_needed (); + + return read_private_key_from_file((void **) dsa, read_dsa, + filename, passphrase); +} +#endif /* LIBSSH_DSA */ + +int +_libssh2_rsa_sha1_sign(LIBSSH2_SESSION * session, + libssh2_rsa_ctx * rsactx, + const unsigned char *hash, + size_t hash_len, + unsigned char **signature, size_t *signature_len) +{ + int ret; + unsigned char *sig; + unsigned int sig_len; + + sig_len = RSA_size(rsactx); + sig = LIBSSH2_ALLOC(session, sig_len); + + if (!sig) { + return -1; + } + + ret = RSA_sign(NID_sha1, hash, hash_len, sig, &sig_len, rsactx); + + if (!ret) { + LIBSSH2_FREE(session, sig); + return -1; + } + + *signature = sig; + *signature_len = sig_len; + + return 0; +} + +#if LIBSSH2_DSA +int +_libssh2_dsa_sha1_sign(libssh2_dsa_ctx * dsactx, + const unsigned char *hash, + unsigned long hash_len, unsigned char *signature) +{ + DSA_SIG *sig; + int r_len, s_len; + (void) hash_len; + + sig = DSA_do_sign(hash, SHA_DIGEST_LENGTH, dsactx); + if (!sig) { + return -1; + } + + r_len = BN_num_bytes(sig->r); + if (r_len < 1 || r_len > 20) { + DSA_SIG_free(sig); + return -1; + } + s_len = BN_num_bytes(sig->s); + if (s_len < 1 || s_len > 20) { + DSA_SIG_free(sig); + return -1; + } + + memset(signature, 0, 40); + + BN_bn2bin(sig->r, signature + (20 - r_len)); + BN_bn2bin(sig->s, signature + 20 + (20 - s_len)); + + DSA_SIG_free(sig); + + return 0; +} +#endif /* LIBSSH_DSA */ + +void +libssh2_sha1(const unsigned char *message, unsigned long len, + unsigned char *out) +{ + EVP_MD_CTX ctx; + + EVP_DigestInit(&ctx, EVP_get_digestbyname("sha1")); + EVP_DigestUpdate(&ctx, message, len); + EVP_DigestFinal(&ctx, out, NULL); +} + +void +libssh2_md5(const unsigned char *message, unsigned long len, + unsigned char *out) +{ + EVP_MD_CTX ctx; + + EVP_DigestInit(&ctx, EVP_get_digestbyname("md5")); + EVP_DigestUpdate(&ctx, message, len); + EVP_DigestFinal(&ctx, out, NULL); +} + +static unsigned char * +write_bn(unsigned char *buf, const BIGNUM *bn, int bn_bytes) +{ + unsigned char *p = buf; + + /* Left space for bn size which will be written below. */ + p += 4; + + *p = 0; + BN_bn2bin(bn, p + 1); + if (!(*(p + 1) & 0x80)) { + memmove(p, p + 1, --bn_bytes); + } + _libssh2_htonu32(p - 4, bn_bytes); /* Post write bn size. */ + + return p + bn_bytes; +} + +static unsigned char * +gen_publickey_from_rsa(LIBSSH2_SESSION *session, RSA *rsa, + size_t *key_len) +{ + int e_bytes, n_bytes; + unsigned long len; + unsigned char* key; + unsigned char* p; + + e_bytes = BN_num_bytes(rsa->e) + 1; + n_bytes = BN_num_bytes(rsa->n) + 1; + + /* Key form is "ssh-rsa" + e + n. */ + len = 4 + 7 + 4 + e_bytes + 4 + n_bytes; + + key = LIBSSH2_ALLOC(session, len); + if (key == NULL) { + return NULL; + } + + /* Process key encoding. */ + p = key; + + _libssh2_htonu32(p, 7); /* Key type. */ + p += 4; + memcpy(p, "ssh-rsa", 7); + p += 7; + + p = write_bn(p, rsa->e, e_bytes); + p = write_bn(p, rsa->n, n_bytes); + + *key_len = (size_t)(p - key); + return key; +} + +static unsigned char * +gen_publickey_from_dsa(LIBSSH2_SESSION* session, DSA *dsa, + size_t *key_len) +{ + int p_bytes, q_bytes, g_bytes, k_bytes; + unsigned long len; + unsigned char* key; + unsigned char* p; + + p_bytes = BN_num_bytes(dsa->p) + 1; + q_bytes = BN_num_bytes(dsa->q) + 1; + g_bytes = BN_num_bytes(dsa->g) + 1; + k_bytes = BN_num_bytes(dsa->pub_key) + 1; + + /* Key form is "ssh-dss" + p + q + g + pub_key. */ + len = 4 + 7 + 4 + p_bytes + 4 + q_bytes + 4 + g_bytes + 4 + k_bytes; + + key = LIBSSH2_ALLOC(session, len); + if (key == NULL) { + return NULL; + } + + /* Process key encoding. */ + p = key; + + _libssh2_htonu32(p, 7); /* Key type. */ + p += 4; + memcpy(p, "ssh-dss", 7); + p += 7; + + p = write_bn(p, dsa->p, p_bytes); + p = write_bn(p, dsa->q, q_bytes); + p = write_bn(p, dsa->g, g_bytes); + p = write_bn(p, dsa->pub_key, k_bytes); + + *key_len = (size_t)(p - key); + return key; +} + +static int +gen_publickey_from_rsa_evp(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + EVP_PKEY *pk) +{ + RSA* rsa = NULL; + unsigned char* key; + unsigned char* method_buf = NULL; + size_t key_len; + + _libssh2_debug(session, + LIBSSH2_TRACE_AUTH, + "Computing public key from RSA private key envelop"); + + rsa = EVP_PKEY_get1_RSA(pk); + if (rsa == NULL) { + /* Assume memory allocation error... what else could it be ? */ + goto __alloc_error; + } + + method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-rsa. */ + if (method_buf == NULL) { + goto __alloc_error; + } + + key = gen_publickey_from_rsa(session, rsa, &key_len); + if (key == NULL) { + goto __alloc_error; + } + RSA_free(rsa); + + memcpy(method_buf, "ssh-rsa", 7); + *method = method_buf; + *method_len = 7; + *pubkeydata = key; + *pubkeydata_len = key_len; + return 0; + + __alloc_error: + if (rsa != NULL) { + RSA_free(rsa); + } + if (method_buf != NULL) { + LIBSSH2_FREE(session, method_buf); + } + + return _libssh2_error(session, + LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for private key data"); +} + +static int +gen_publickey_from_dsa_evp(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + EVP_PKEY *pk) +{ + DSA* dsa = NULL; + unsigned char* key; + unsigned char* method_buf = NULL; + size_t key_len; + + _libssh2_debug(session, + LIBSSH2_TRACE_AUTH, + "Computing public key from DSA private key envelop"); + + dsa = EVP_PKEY_get1_DSA(pk); + if (dsa == NULL) { + /* Assume memory allocation error... what else could it be ? */ + goto __alloc_error; + } + + method_buf = LIBSSH2_ALLOC(session, 7); /* ssh-dss. */ + if (method_buf == NULL) { + goto __alloc_error; + } + + key = gen_publickey_from_dsa(session, dsa, &key_len); + if (key == NULL) { + goto __alloc_error; + } + DSA_free(dsa); + + memcpy(method_buf, "ssh-dss", 7); + *method = method_buf; + *method_len = 7; + *pubkeydata = key; + *pubkeydata_len = key_len; + return 0; + + __alloc_error: + if (dsa != NULL) { + DSA_free(dsa); + } + if (method_buf != NULL) { + LIBSSH2_FREE(session, method_buf); + } + + return _libssh2_error(session, + LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for private key data"); +} + +int +_libssh2_pub_priv_keyfile(LIBSSH2_SESSION *session, + unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + const char *privatekey, + const char *passphrase) +{ + int st; + BIO* bp; + EVP_PKEY* pk; + + _libssh2_debug(session, + LIBSSH2_TRACE_AUTH, + "Computing public key from private key file: %s", + privatekey); + + bp = BIO_new_file(privatekey, "r"); + if (bp == NULL) { + return _libssh2_error(session, + LIBSSH2_ERROR_FILE, + "Unable to extract public key from private key " + "file: Unable to open private key file"); + } + if (!EVP_get_cipherbyname("des")) { + /* If this cipher isn't loaded it's a pretty good indication that none + * are. I have *NO DOUBT* that there's a better way to deal with this + * ($#&%#$(%$#( Someone buy me an OpenSSL manual and I'll read up on + * it. + */ + OpenSSL_add_all_ciphers(); + } + BIO_reset(bp); + pk = PEM_read_bio_PrivateKey(bp, NULL, NULL, (void*)passphrase); + BIO_free(bp); + + if (pk == NULL) { + return _libssh2_error(session, + LIBSSH2_ERROR_FILE, + "Unable to extract public key " + "from private key file: " + "Wrong passphrase or invalid/unrecognized " + "private key file format"); + } + + switch (pk->type) { + case EVP_PKEY_RSA : + st = gen_publickey_from_rsa_evp( + session, method, method_len, pubkeydata, pubkeydata_len, pk); + break; + + case EVP_PKEY_DSA : + st = gen_publickey_from_dsa_evp( + session, method, method_len, pubkeydata, pubkeydata_len, pk); + break; + + default : + st = _libssh2_error(session, + LIBSSH2_ERROR_FILE, + "Unable to extract public key " + "from private key file: " + "Unsupported private key file format"); + break; + } + + EVP_PKEY_free(pk); + return st; +} + +#endif /* !LIBSSH2_LIBGCRYPT */ diff --git a/vendor/libssh2-1.4.2/src/openssl.h b/vendor/libssh2-1.4.2/src/openssl.h new file mode 100644 index 0000000..6d2aeed --- /dev/null +++ b/vendor/libssh2-1.4.2/src/openssl.h @@ -0,0 +1,178 @@ +/* Copyright (C) 2009, 2010 Simon Josefsson + * Copyright (C) 2006, 2007 The Written Word, Inc. All rights reserved. + * + * Author: Simon Josefsson + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include +#include +#ifndef OPENSSL_NO_MD5 +#include +#endif +#include +#include +#include +#include +#include + +#ifdef OPENSSL_NO_RSA +# define LIBSSH2_RSA 0 +#else +# define LIBSSH2_RSA 1 +#endif + +#ifdef OPENSSL_NO_DSA +# define LIBSSH2_DSA 0 +#else +# define LIBSSH2_DSA 1 +#endif + +#ifdef OPENSSL_NO_MD5 +# define LIBSSH2_MD5 0 +#else +# define LIBSSH2_MD5 1 +#endif + +#ifdef OPENSSL_NO_RIPEMD +# define LIBSSH2_HMAC_RIPEMD 0 +#else +# define LIBSSH2_HMAC_RIPEMD 1 +#endif + +#if OPENSSL_VERSION_NUMBER >= 0x00907000L && !defined(OPENSSL_NO_AES) +# define LIBSSH2_AES_CTR 1 +# define LIBSSH2_AES 1 +#else +# define LIBSSH2_AES_CTR 0 +# define LIBSSH2_AES 0 +#endif + +#ifdef OPENSSL_NO_BLOWFISH +# define LIBSSH2_BLOWFISH 0 +#else +# define LIBSSH2_BLOWFISH 1 +#endif + +#ifdef OPENSSL_NO_RC4 +# define LIBSSH2_RC4 0 +#else +# define LIBSSH2_RC4 1 +#endif + +#ifdef OPENSSL_NO_CAST +# define LIBSSH2_CAST 0 +#else +# define LIBSSH2_CAST 1 +#endif + +#ifdef OPENSSL_NO_DES +# define LIBSSH2_3DES 0 +#else +# define LIBSSH2_3DES 1 +#endif + +#define _libssh2_random(buf, len) RAND_bytes ((buf), (len)) + +#define libssh2_sha1_ctx EVP_MD_CTX +#define libssh2_sha1_init(ctx) EVP_DigestInit(ctx, EVP_get_digestbyname("sha1")) +#define libssh2_sha1_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len) +#define libssh2_sha1_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) +void libssh2_sha1(const unsigned char *message, unsigned long len, unsigned char *out); + +#define libssh2_md5_ctx EVP_MD_CTX +#define libssh2_md5_init(ctx) EVP_DigestInit(ctx, EVP_get_digestbyname("md5")) +#define libssh2_md5_update(ctx, data, len) EVP_DigestUpdate(&(ctx), data, len) +#define libssh2_md5_final(ctx, out) EVP_DigestFinal(&(ctx), out, NULL) +void libssh2_md5(const unsigned char *message, unsigned long len, unsigned char *out); + +#define libssh2_hmac_ctx HMAC_CTX +#define libssh2_hmac_sha1_init(ctx, key, keylen) \ + HMAC_Init(ctx, key, keylen, EVP_sha1()) +#define libssh2_hmac_md5_init(ctx, key, keylen) \ + HMAC_Init(ctx, key, keylen, EVP_md5()) +#define libssh2_hmac_ripemd160_init(ctx, key, keylen) \ + HMAC_Init(ctx, key, keylen, EVP_ripemd160()) +#define libssh2_hmac_update(ctx, data, datalen) \ + HMAC_Update(&(ctx), data, datalen) +#define libssh2_hmac_final(ctx, data) HMAC_Final(&(ctx), data, NULL) +#define libssh2_hmac_cleanup(ctx) HMAC_cleanup(ctx) + +#define libssh2_crypto_init() OpenSSL_add_all_algorithms() +#define libssh2_crypto_exit() + +#define libssh2_rsa_ctx RSA + +#define _libssh2_rsa_free(rsactx) RSA_free(rsactx) + +#define libssh2_dsa_ctx DSA + + +#define _libssh2_dsa_free(dsactx) DSA_free(dsactx) + +#define _libssh2_cipher_type(name) const EVP_CIPHER *(*name)(void) +#define _libssh2_cipher_ctx EVP_CIPHER_CTX + +#define _libssh2_cipher_aes256 EVP_aes_256_cbc +#define _libssh2_cipher_aes192 EVP_aes_192_cbc +#define _libssh2_cipher_aes128 EVP_aes_128_cbc +#define _libssh2_cipher_aes128ctr _libssh2_EVP_aes_128_ctr +#define _libssh2_cipher_aes192ctr _libssh2_EVP_aes_192_ctr +#define _libssh2_cipher_aes256ctr _libssh2_EVP_aes_256_ctr +#define _libssh2_cipher_blowfish EVP_bf_cbc +#define _libssh2_cipher_arcfour EVP_rc4 +#define _libssh2_cipher_cast5 EVP_cast5_cbc +#define _libssh2_cipher_3des EVP_des_ede3_cbc + +#define _libssh2_cipher_dtor(ctx) EVP_CIPHER_CTX_cleanup(ctx) + +#define _libssh2_bn BIGNUM +#define _libssh2_bn_ctx BN_CTX +#define _libssh2_bn_ctx_new() BN_CTX_new() +#define _libssh2_bn_ctx_free(bnctx) BN_CTX_free(bnctx) +#define _libssh2_bn_init() BN_new() +#define _libssh2_bn_rand(bn, bits, top, bottom) BN_rand(bn, bits, top, bottom) +#define _libssh2_bn_mod_exp(r, a, p, m, ctx) BN_mod_exp(r, a, p, m, ctx) +#define _libssh2_bn_set_word(bn, val) BN_set_word(bn, val) +#define _libssh2_bn_from_bin(bn, len, val) BN_bin2bn(val, len, bn) +#define _libssh2_bn_to_bin(bn, val) BN_bn2bin(bn, val) +#define _libssh2_bn_bytes(bn) BN_num_bytes(bn) +#define _libssh2_bn_bits(bn) BN_num_bits(bn) +#define _libssh2_bn_free(bn) BN_clear_free(bn) + +const EVP_CIPHER *_libssh2_EVP_aes_128_ctr(void); +const EVP_CIPHER *_libssh2_EVP_aes_192_ctr(void); +const EVP_CIPHER *_libssh2_EVP_aes_256_ctr(void); + diff --git a/vendor/libssh2-1.4.2/src/packet.c b/vendor/libssh2-1.4.2/src/packet.c new file mode 100644 index 0000000..bfbd56a --- /dev/null +++ b/vendor/libssh2-1.4.2/src/packet.c @@ -0,0 +1,1243 @@ +/* Copyright (c) 2004-2007, Sara Golemon + * Copyright (c) 2005,2006 Mikhail Gusarov + * Copyright (c) 2009-2010 by Daniel Stenberg + * Copyright (c) 2010 Simon Josefsson + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_INTTYPES_H +#include +#endif + +/* Needed for struct iovec on some platforms */ +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#include + +#include "transport.h" +#include "channel.h" +#include "packet.h" + +/* + * libssh2_packet_queue_listener + * + * Queue a connection request for a listener + */ +static inline int +packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, + unsigned long datalen, + packet_queue_listener_state_t *listen_state) +{ + /* + * Look for a matching listener + */ + /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ + unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1); + unsigned char *p; + LIBSSH2_LISTENER *listn = _libssh2_list_first(&session->listeners); + char failure_code = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; + int rc; + + (void) datalen; + + if (listen_state->state == libssh2_NB_state_idle) { + unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5; + listen_state->sender_channel = _libssh2_ntohu32(s); + s += 4; + + listen_state->initial_window_size = _libssh2_ntohu32(s); + s += 4; + listen_state->packet_size = _libssh2_ntohu32(s); + s += 4; + + listen_state->host_len = _libssh2_ntohu32(s); + s += 4; + listen_state->host = s; + s += listen_state->host_len; + listen_state->port = _libssh2_ntohu32(s); + s += 4; + + listen_state->shost_len = _libssh2_ntohu32(s); + s += 4; + listen_state->shost = s; + s += listen_state->shost_len; + listen_state->sport = _libssh2_ntohu32(s); + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Remote received connection from %s:%ld to %s:%ld", + listen_state->shost, listen_state->sport, + listen_state->host, listen_state->port); + + listen_state->state = libssh2_NB_state_allocated; + } + + if (listen_state->state != libssh2_NB_state_sent) { + while (listn) { + if ((listn->port == (int) listen_state->port) && + (strlen(listn->host) == listen_state->host_len) && + (memcmp (listn->host, listen_state->host, + listen_state->host_len) == 0)) { + /* This is our listener */ + LIBSSH2_CHANNEL *channel = NULL; + listen_state->channel = NULL; + + if (listen_state->state == libssh2_NB_state_allocated) { + if (listn->queue_maxsize && + (listn->queue_maxsize <= listn->queue_size)) { + /* Queue is full */ + failure_code = SSH_OPEN_RESOURCE_SHORTAGE; + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Listener queue full, ignoring"); + listen_state->state = libssh2_NB_state_sent; + break; + } + + channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL)); + if (!channel) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate a channel for " + "new connection"); + failure_code = SSH_OPEN_RESOURCE_SHORTAGE; + listen_state->state = libssh2_NB_state_sent; + break; + } + listen_state->channel = channel; + + memset(channel, 0, sizeof(LIBSSH2_CHANNEL)); + + channel->session = session; + channel->channel_type_len = sizeof("forwarded-tcpip") - 1; + channel->channel_type = LIBSSH2_ALLOC(session, + channel-> + channel_type_len + + 1); + if (!channel->channel_type) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate a channel for new" + " connection"); + LIBSSH2_FREE(session, channel); + failure_code = SSH_OPEN_RESOURCE_SHORTAGE; + listen_state->state = libssh2_NB_state_sent; + break; + } + memcpy(channel->channel_type, "forwarded-tcpip", + channel->channel_type_len + 1); + + channel->remote.id = listen_state->sender_channel; + channel->remote.window_size_initial = + LIBSSH2_CHANNEL_WINDOW_DEFAULT; + channel->remote.window_size = + LIBSSH2_CHANNEL_WINDOW_DEFAULT; + channel->remote.packet_size = + LIBSSH2_CHANNEL_PACKET_DEFAULT; + + channel->local.id = _libssh2_channel_nextid(session); + channel->local.window_size_initial = + listen_state->initial_window_size; + channel->local.window_size = + listen_state->initial_window_size; + channel->local.packet_size = listen_state->packet_size; + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Connection queued: channel %lu/%lu " + "win %lu/%lu packet %lu/%lu", + channel->local.id, channel->remote.id, + channel->local.window_size, + channel->remote.window_size, + channel->local.packet_size, + channel->remote.packet_size); + + p = listen_state->packet; + *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; + _libssh2_store_u32(&p, channel->remote.id); + _libssh2_store_u32(&p, channel->local.id); + _libssh2_store_u32(&p, + channel->remote.window_size_initial); + _libssh2_store_u32(&p, channel->remote.packet_size); + + listen_state->state = libssh2_NB_state_created; + } + + if (listen_state->state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, listen_state->packet, + 17, NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + else if (rc) { + listen_state->state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Unable to send channel " + "open confirmation"); + } + + /* Link the channel into the end of the queue list */ + _libssh2_list_add(&listn->queue, + &listen_state->channel->node); + listn->queue_size++; + + listen_state->state = libssh2_NB_state_idle; + return 0; + } + } + + listn = _libssh2_list_next(&listn->node); + } + + listen_state->state = libssh2_NB_state_sent; + } + + /* We're not listening to you */ + p = listen_state->packet; + *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; + _libssh2_store_u32(&p, listen_state->sender_channel); + _libssh2_store_u32(&p, failure_code); + _libssh2_store_str(&p, FwdNotReq, sizeof(FwdNotReq) - 1); + _libssh2_htonu32(p, 0); + + rc = _libssh2_transport_send(session, listen_state->packet, + packet_len, NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + listen_state->state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, "Unable to send open failure"); + + } + listen_state->state = libssh2_NB_state_idle; + return 0; +} + +/* + * packet_x11_open + * + * Accept a forwarded X11 connection + */ +static inline int +packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, + unsigned long datalen, + packet_x11_open_state_t *x11open_state) +{ + int failure_code = SSH_OPEN_CONNECT_FAILED; + /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ + unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1); + unsigned char *p; + LIBSSH2_CHANNEL *channel = x11open_state->channel; + int rc; + + (void) datalen; + + if (x11open_state->state == libssh2_NB_state_idle) { + unsigned char *s = data + (sizeof("x11") - 1) + 5; + x11open_state->sender_channel = _libssh2_ntohu32(s); + s += 4; + x11open_state->initial_window_size = _libssh2_ntohu32(s); + s += 4; + x11open_state->packet_size = _libssh2_ntohu32(s); + s += 4; + x11open_state->shost_len = _libssh2_ntohu32(s); + s += 4; + x11open_state->shost = s; + s += x11open_state->shost_len; + x11open_state->sport = _libssh2_ntohu32(s); + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "X11 Connection Received from %s:%ld on channel %lu", + x11open_state->shost, x11open_state->sport, + x11open_state->sender_channel); + + x11open_state->state = libssh2_NB_state_allocated; + } + + if (session->x11) { + if (x11open_state->state == libssh2_NB_state_allocated) { + channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL)); + if (!channel) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "allocate a channel for new connection"); + failure_code = SSH_OPEN_RESOURCE_SHORTAGE; + goto x11_exit; + } + memset(channel, 0, sizeof(LIBSSH2_CHANNEL)); + + channel->session = session; + channel->channel_type_len = sizeof("x11") - 1; + channel->channel_type = LIBSSH2_ALLOC(session, + channel->channel_type_len + + 1); + if (!channel->channel_type) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "allocate a channel for new connection"); + LIBSSH2_FREE(session, channel); + failure_code = SSH_OPEN_RESOURCE_SHORTAGE; + goto x11_exit; + } + memcpy(channel->channel_type, "x11", + channel->channel_type_len + 1); + + channel->remote.id = x11open_state->sender_channel; + channel->remote.window_size_initial = + LIBSSH2_CHANNEL_WINDOW_DEFAULT; + channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT; + channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT; + + channel->local.id = _libssh2_channel_nextid(session); + channel->local.window_size_initial = + x11open_state->initial_window_size; + channel->local.window_size = x11open_state->initial_window_size; + channel->local.packet_size = x11open_state->packet_size; + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "X11 Connection established: channel %lu/%lu " + "win %lu/%lu packet %lu/%lu", + channel->local.id, channel->remote.id, + channel->local.window_size, + channel->remote.window_size, + channel->local.packet_size, + channel->remote.packet_size); + p = x11open_state->packet; + *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; + _libssh2_store_u32(&p, channel->remote.id); + _libssh2_store_u32(&p, channel->local.id); + _libssh2_store_u32(&p, channel->remote.window_size_initial); + _libssh2_store_u32(&p, channel->remote.packet_size); + + x11open_state->state = libssh2_NB_state_created; + } + + if (x11open_state->state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, x11open_state->packet, 17, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + x11open_state->state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send channel open " + "confirmation"); + } + + /* Link the channel into the session */ + _libssh2_list_add(&session->channels, &channel->node); + + /* + * Pass control to the callback, they may turn right around and + * free the channel, or actually use it + */ + LIBSSH2_X11_OPEN(channel, (char *)x11open_state->shost, + x11open_state->sport); + + x11open_state->state = libssh2_NB_state_idle; + return 0; + } + } + else + failure_code = SSH_OPEN_RESOURCE_SHORTAGE; + /* fall-trough */ + x11_exit: + p = x11open_state->packet; + *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; + _libssh2_store_u32(&p, x11open_state->sender_channel); + _libssh2_store_u32(&p, failure_code); + _libssh2_store_str(&p, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1); + _libssh2_htonu32(p, 0); + + rc = _libssh2_transport_send(session, x11open_state->packet, packet_len, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + x11open_state->state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, "Unable to send open failure"); + } + x11open_state->state = libssh2_NB_state_idle; + return 0; +} + +/* + * _libssh2_packet_add + * + * Create a new packet and attach it to the brigade. Called from the transport + * layer when it has received a packet. + * + * The input pointer 'data' is pointing to allocated data that this function + * is asked to deal with so on failure OR success, it must be freed fine. + * + * This function will always be called with 'datalen' greater than zero. + */ +int +_libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, + size_t datalen, int macstate) +{ + int rc = 0; + char *message=NULL; + char *language=NULL; + size_t message_len=0; + size_t language_len=0; + LIBSSH2_CHANNEL *channelp = NULL; + size_t data_head = 0; + unsigned char msg = data[0]; + + switch(session->packAdd_state) { + case libssh2_NB_state_idle: + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "Packet type %d received, length=%d", + (int) msg, (int) datalen); + + if ((macstate == LIBSSH2_MAC_INVALID) && + (!session->macerror || + LIBSSH2_MACERROR(session, (char *) data, datalen))) { + /* Bad MAC input, but no callback set or non-zero return from the + callback */ + + LIBSSH2_FREE(session, data); + return _libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC, + "Invalid MAC received"); + } + session->packAdd_state = libssh2_NB_state_allocated; + break; + case libssh2_NB_state_jump1: + goto libssh2_packet_add_jump_point1; + case libssh2_NB_state_jump2: + goto libssh2_packet_add_jump_point2; + case libssh2_NB_state_jump3: + goto libssh2_packet_add_jump_point3; + case libssh2_NB_state_jump4: + goto libssh2_packet_add_jump_point4; + case libssh2_NB_state_jump5: + goto libssh2_packet_add_jump_point5; + default: /* nothing to do */ + break; + } + + if (session->packAdd_state == libssh2_NB_state_allocated) { + /* A couple exceptions to the packet adding rule: */ + switch (msg) { + + /* + byte SSH_MSG_DISCONNECT + uint32 reason code + string description in ISO-10646 UTF-8 encoding [RFC3629] + string language tag [RFC3066] + */ + + case SSH_MSG_DISCONNECT: + if(datalen >= 5) { + size_t reason = _libssh2_ntohu32(data + 1); + + if(datalen >= 9) { + message_len = _libssh2_ntohu32(data + 5); + + if(message_len < datalen-13) { + /* 9 = packet_type(1) + reason(4) + message_len(4) */ + message = (char *) data + 9; + + language_len = _libssh2_ntohu32(data + 9 + message_len); + language = (char *) data + 9 + message_len + 4; + + if(language_len > (datalen-13-message_len)) { + /* bad input, clear info */ + language = message = NULL; + language_len = message_len = 0; + } + } + else + /* bad size, clear it */ + message_len=0; + } + if (session->ssh_msg_disconnect) { + LIBSSH2_DISCONNECT(session, reason, message, + message_len, language, language_len); + } + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "Disconnect(%d): %s(%s)", reason, + message, language); + } + + LIBSSH2_FREE(session, data); + session->socket_state = LIBSSH2_SOCKET_DISCONNECTED; + session->packAdd_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT, + "socket disconnect"); + /* + byte SSH_MSG_IGNORE + string data + */ + + case SSH_MSG_IGNORE: + if (datalen >= 2) { + if (session->ssh_msg_ignore) { + LIBSSH2_IGNORE(session, (char *) data + 1, datalen - 1); + } + } else if (session->ssh_msg_ignore) { + LIBSSH2_IGNORE(session, "", 0); + } + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return 0; + + /* + byte SSH_MSG_DEBUG + boolean always_display + string message in ISO-10646 UTF-8 encoding [RFC3629] + string language tag [RFC3066] + */ + + case SSH_MSG_DEBUG: + if(datalen >= 2) { + int always_display= data[1]; + + if(datalen >= 6) { + message_len = _libssh2_ntohu32(data + 2); + + if(message_len <= (datalen - 10)) { + /* 6 = packet_type(1) + display(1) + message_len(4) */ + message = (char *) data + 6; + language_len = _libssh2_ntohu32(data + 6 + message_len); + + if(language_len <= (datalen - 10 - message_len)) + language = (char *) data + 10 + message_len; + } + } + + if (session->ssh_msg_debug) { + LIBSSH2_DEBUG(session, always_display, message, + message_len, language, language_len); + } + } + /* + * _libssh2_debug will actually truncate this for us so + * that it's not an inordinate about of data + */ + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "Debug Packet: %s", message); + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return 0; + + /* + byte SSH_MSG_GLOBAL_REQUEST + string request name in US-ASCII only + boolean want reply + .... request-specific data follows + */ + + case SSH_MSG_GLOBAL_REQUEST: + if(datalen >= 5) { + uint32_t len =0; + unsigned char want_reply=0; + len = _libssh2_ntohu32(data + 1); + if(datalen >= (6 + len)) { + want_reply = data[5 + len]; + _libssh2_debug(session, + LIBSSH2_TRACE_CONN, + "Received global request type %.*s (wr %X)", + len, data + 5, want_reply); + } + + + if (want_reply) { + unsigned char packet = SSH_MSG_REQUEST_FAILURE; + libssh2_packet_add_jump_point5: + session->packAdd_state = libssh2_NB_state_jump5; + rc = _libssh2_transport_send(session, &packet, 1, NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + } + } + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return 0; + + /* + byte SSH_MSG_CHANNEL_EXTENDED_DATA + uint32 recipient channel + uint32 data_type_code + string data + */ + + case SSH_MSG_CHANNEL_EXTENDED_DATA: + /* streamid(4) */ + data_head += 4; + + /* fall-through */ + + /* + byte SSH_MSG_CHANNEL_DATA + uint32 recipient channel + string data + */ + + case SSH_MSG_CHANNEL_DATA: + /* packet_type(1) + channelno(4) + datalen(4) */ + data_head += 9; + + if(datalen >= data_head) + channelp = + _libssh2_channel_locate(session, + _libssh2_ntohu32(data + 1)); + + if (!channelp) { + _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN, + "Packet received for unknown channel"); + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return 0; + } +#ifdef LIBSSH2DEBUG + { + uint32_t stream_id = 0; + if (msg == SSH_MSG_CHANNEL_EXTENDED_DATA) + stream_id = _libssh2_ntohu32(data + 5); + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "%d bytes packet_add() for %lu/%lu/%lu", + (int) (datalen - data_head), + channelp->local.id, + channelp->remote.id, + stream_id); + } +#endif + if ((channelp->remote.extended_data_ignore_mode == + LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) && + (msg == SSH_MSG_CHANNEL_EXTENDED_DATA)) { + /* Pretend we didn't receive this */ + LIBSSH2_FREE(session, data); + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Ignoring extended data and refunding %d bytes", + (int) (datalen - 13)); + session->packAdd_channelp = channelp; + + /* Adjust the window based on the block we just freed */ + libssh2_packet_add_jump_point1: + session->packAdd_state = libssh2_NB_state_jump1; + rc = _libssh2_channel_receive_window_adjust(session-> + packAdd_channelp, + datalen - 13, + 1, NULL); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + + session->packAdd_state = libssh2_NB_state_idle; + return 0; + } + + /* + * REMEMBER! remote means remote as source of data, + * NOT remote window! + */ + if (channelp->remote.packet_size < (datalen - data_head)) { + /* + * Spec says we MAY ignore bytes sent beyond + * packet_size + */ + _libssh2_error(session, + LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, + "Packet contains more data than we offered" + " to receive, truncating"); + datalen = channelp->remote.packet_size + data_head; + } + if (channelp->remote.window_size <= 0) { + /* + * Spec says we MAY ignore bytes sent beyond + * window_size + */ + _libssh2_error(session, + LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, + "The current receive window is full," + " data ignored"); + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return 0; + } + /* Reset EOF status */ + channelp->remote.eof = 0; + + if ((datalen - data_head) > channelp->remote.window_size) { + _libssh2_error(session, + LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, + "Remote sent more data than current " + "window allows, truncating"); + datalen = channelp->remote.window_size + data_head; + channelp->remote.window_size = 0; + } + else + /* Now that we've received it, shrink our window */ + channelp->remote.window_size -= datalen - data_head; + + break; + + /* + byte SSH_MSG_CHANNEL_EOF + uint32 recipient channel + */ + + case SSH_MSG_CHANNEL_EOF: + if(datalen >= 5) + channelp = + _libssh2_channel_locate(session, + _libssh2_ntohu32(data + 1)); + if (!channelp) + /* We may have freed already, just quietly ignore this... */ + ; + else { + _libssh2_debug(session, + LIBSSH2_TRACE_CONN, + "EOF received for channel %lu/%lu", + channelp->local.id, + channelp->remote.id); + channelp->remote.eof = 1; + } + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return 0; + + /* + byte SSH_MSG_CHANNEL_REQUEST + uint32 recipient channel + string request type in US-ASCII characters only + boolean want reply + .... type-specific data follows + */ + + case SSH_MSG_CHANNEL_REQUEST: + if(datalen >= 9) { + uint32_t channel = _libssh2_ntohu32(data + 1); + uint32_t len = _libssh2_ntohu32(data + 5); + unsigned char want_reply = 1; + + if(len < (datalen - 10)) + want_reply = data[9 + len]; + + _libssh2_debug(session, + LIBSSH2_TRACE_CONN, + "Channel %d received request type %.*s (wr %X)", + channel, len, data + 9, want_reply); + + if (len == sizeof("exit-status") - 1 + && !memcmp("exit-status", data + 9, + sizeof("exit-status") - 1)) { + + /* we've got "exit-status" packet. Set the session value */ + if(datalen >= 20) + channelp = + _libssh2_channel_locate(session, channel); + + if (channelp) { + channelp->exit_status = + _libssh2_ntohu32(data + 9 + sizeof("exit-status")); + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Exit status %lu received for " + "channel %lu/%lu", + channelp->exit_status, + channelp->local.id, + channelp->remote.id); + } + + } + else if (len == sizeof("exit-signal") - 1 + && !memcmp("exit-signal", data + 9, + sizeof("exit-signal") - 1)) { + /* command terminated due to signal */ + if(datalen >= 20) + channelp = _libssh2_channel_locate(session, channel); + + if (channelp) { + /* set signal name (without SIG prefix) */ + uint32_t namelen = + _libssh2_ntohu32(data + 9 + sizeof("exit-signal")); + channelp->exit_signal = + LIBSSH2_ALLOC(session, namelen + 1); + if (!channelp->exit_signal) + rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "memory for signal name"); + else { + memcpy(channelp->exit_signal, + data + 13 + sizeof("exit_signal"), namelen); + channelp->exit_signal[namelen] = '\0'; + /* TODO: save error message and language tag */ + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Exit signal %s received for " + "channel %lu/%lu", + channelp->exit_signal, + channelp->local.id, + channelp->remote.id); + } + } + } + + + if (want_reply) { + unsigned char packet[5]; + libssh2_packet_add_jump_point4: + session->packAdd_state = libssh2_NB_state_jump4; + packet[0] = SSH_MSG_CHANNEL_FAILURE; + memcpy(&packet[1], data+1, 4); + rc = _libssh2_transport_send(session, packet, 5, NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + } + } + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return rc; + + /* + byte SSH_MSG_CHANNEL_CLOSE + uint32 recipient channel + */ + + case SSH_MSG_CHANNEL_CLOSE: + if(datalen >= 5) + channelp = + _libssh2_channel_locate(session, + _libssh2_ntohu32(data + 1)); + if (!channelp) { + /* We may have freed already, just quietly ignore this... */ + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return 0; + } + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Close received for channel %lu/%lu", + channelp->local.id, + channelp->remote.id); + + channelp->remote.close = 1; + channelp->remote.eof = 1; + + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return 0; + + /* + byte SSH_MSG_CHANNEL_OPEN + string "session" + uint32 sender channel + uint32 initial window size + uint32 maximum packet size + */ + + case SSH_MSG_CHANNEL_OPEN: + if(datalen < 17) + ; + else if ((datalen >= (sizeof("forwarded-tcpip") + 4)) && + ((sizeof("forwarded-tcpip") - 1) == + _libssh2_ntohu32(data + 1)) + && + (memcmp(data + 5, "forwarded-tcpip", + sizeof("forwarded-tcpip") - 1) == 0)) { + + /* init the state struct */ + memset(&session->packAdd_Qlstn_state, 0, + sizeof(session->packAdd_Qlstn_state)); + + libssh2_packet_add_jump_point2: + session->packAdd_state = libssh2_NB_state_jump2; + rc = packet_queue_listener(session, data, datalen, + &session->packAdd_Qlstn_state); + } + else if ((datalen >= (sizeof("x11") + 4)) && + ((sizeof("x11") - 1) == _libssh2_ntohu32(data + 1)) && + (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) { + + /* init the state struct */ + memset(&session->packAdd_x11open_state, 0, + sizeof(session->packAdd_x11open_state)); + + libssh2_packet_add_jump_point3: + session->packAdd_state = libssh2_NB_state_jump3; + rc = packet_x11_open(session, data, datalen, + &session->packAdd_x11open_state); + } + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return rc; + + /* + byte SSH_MSG_CHANNEL_WINDOW_ADJUST + uint32 recipient channel + uint32 bytes to add + */ + case SSH_MSG_CHANNEL_WINDOW_ADJUST: + if(datalen < 9) + ; + else { + uint32_t bytestoadd = _libssh2_ntohu32(data + 5); + channelp = + _libssh2_channel_locate(session, + _libssh2_ntohu32(data + 1)); + if(channelp) { + channelp->local.window_size += bytestoadd; + + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Window adjust for channel %lu/%lu, " + "adding %lu bytes, new window_size=%lu", + channelp->local.id, + channelp->remote.id, + bytestoadd, + channelp->local.window_size); + } + } + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return 0; + default: + break; + } + + session->packAdd_state = libssh2_NB_state_sent; + } + + if (session->packAdd_state == libssh2_NB_state_sent) { + LIBSSH2_PACKET *packetp = + LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET)); + if (!packetp) { + _libssh2_debug(session, LIBSSH2_ERROR_ALLOC, + "memory for packet"); + session->packAdd_state = libssh2_NB_state_idle; + return LIBSSH2_ERROR_ALLOC; + } + packetp->data = data; + packetp->data_len = datalen; + packetp->data_head = data_head; + + _libssh2_list_add(&session->packets, &packetp->node); + + session->packAdd_state = libssh2_NB_state_sent1; + } + + if ((msg == SSH_MSG_KEXINIT && + !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) || + (session->packAdd_state == libssh2_NB_state_sent2)) { + if (session->packAdd_state == libssh2_NB_state_sent1) { + /* + * Remote wants new keys + * Well, it's already in the brigade, + * let's just call back into ourselves + */ + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Renegotiating Keys"); + + session->packAdd_state = libssh2_NB_state_sent2; + } + + /* + * The KEXINIT message has been added to the queue. The packAdd and + * readPack states need to be reset because _libssh2_kex_exchange + * (eventually) calls upon _libssh2_transport_read to read the rest of + * the key exchange conversation. + */ + session->readPack_state = libssh2_NB_state_idle; + session->packet.total_num = 0; + session->packAdd_state = libssh2_NB_state_idle; + session->fullpacket_state = libssh2_NB_state_idle; + + memset(&session->startup_key_state, 0, sizeof(key_exchange_state_t)); + + /* + * If there was a key reexchange failure, let's just hope we didn't + * send NEWKEYS yet, otherwise remote will drop us like a rock + */ + rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + } + + session->packAdd_state = libssh2_NB_state_idle; + return 0; +} + +/* + * _libssh2_packet_ask + * + * Scan the brigade for a matching packet type, optionally poll the socket for + * a packet first + */ +int +_libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type, + unsigned char **data, size_t *data_len, + int match_ofs, const unsigned char *match_buf, + size_t match_len) +{ + LIBSSH2_PACKET *packet = _libssh2_list_first(&session->packets); + + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "Looking for packet of type: %d", (int) packet_type); + + while (packet) { + if (packet->data[0] == packet_type + && (packet->data_len >= (match_ofs + match_len)) + && (!match_buf || + (memcmp(packet->data + match_ofs, match_buf, + match_len) == 0))) { + *data = packet->data; + *data_len = packet->data_len; + + /* unlink struct from session->packets */ + _libssh2_list_remove(&packet->node); + + LIBSSH2_FREE(session, packet); + + return 0; + } + packet = _libssh2_list_next(&packet->node); + } + return -1; +} + +/* + * libssh2_packet_askv + * + * Scan for any of a list of packet types in the brigade, optionally poll the + * socket for a packet first + */ +int +_libssh2_packet_askv(LIBSSH2_SESSION * session, + const unsigned char *packet_types, + unsigned char **data, size_t *data_len, + int match_ofs, + const unsigned char *match_buf, + size_t match_len) +{ + int i, packet_types_len = strlen((char *) packet_types); + + for(i = 0; i < packet_types_len; i++) { + if (0 == _libssh2_packet_ask(session, packet_types[i], data, + data_len, match_ofs, + match_buf, match_len)) { + return 0; + } + } + + return -1; +} + +/* + * _libssh2_packet_require + * + * Loops _libssh2_transport_read() until the packet requested is available + * SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout + * + * Returns negative on error + * Returns 0 when it has taken care of the requested packet. + */ +int +_libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type, + unsigned char **data, size_t *data_len, + int match_ofs, + const unsigned char *match_buf, + size_t match_len, + packet_require_state_t *state) +{ + if (state->start == 0) { + if (_libssh2_packet_ask(session, packet_type, data, data_len, + match_ofs, match_buf, + match_len) == 0) { + /* A packet was available in the packet brigade */ + return 0; + } + + state->start = time(NULL); + } + + while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) { + int ret = _libssh2_transport_read(session); + if (ret == LIBSSH2_ERROR_EAGAIN) + return ret; + else if (ret < 0) { + state->start = 0; + /* an error which is not just because of blocking */ + return ret; + } else if (ret == packet_type) { + /* Be lazy, let packet_ask pull it out of the brigade */ + ret = _libssh2_packet_ask(session, packet_type, data, data_len, + match_ofs, match_buf, match_len); + state->start = 0; + return ret; + } else if (ret == 0) { + /* nothing available, wait until data arrives or we time out */ + long left = LIBSSH2_READ_TIMEOUT - (long)(time(NULL) - + state->start); + + if (left <= 0) { + state->start = 0; + return LIBSSH2_ERROR_TIMEOUT; + } + return -1; /* no packet available yet */ + } + } + + /* Only reached if the socket died */ + return LIBSSH2_ERROR_SOCKET_DISCONNECT; +} + +/* + * _libssh2_packet_burn + * + * Loops _libssh2_transport_read() until any packet is available and promptly + * discards it. + * Used during KEX exchange to discard badly guessed KEX_INIT packets + */ +int +_libssh2_packet_burn(LIBSSH2_SESSION * session, + libssh2_nonblocking_states * state) +{ + unsigned char *data; + size_t data_len; + unsigned char all_packets[255]; + int i; + int ret; + + if (*state == libssh2_NB_state_idle) { + for(i = 1; i < 256; i++) { + all_packets[i - 1] = i; + } + + if (_libssh2_packet_askv(session, all_packets, &data, &data_len, 0, + NULL, 0) == 0) { + i = data[0]; + /* A packet was available in the packet brigade, burn it */ + LIBSSH2_FREE(session, data); + return i; + } + + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "Blocking until packet becomes available to burn"); + *state = libssh2_NB_state_created; + } + + while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) { + ret = _libssh2_transport_read(session); + if (ret == LIBSSH2_ERROR_EAGAIN) { + return ret; + } else if (ret < 0) { + *state = libssh2_NB_state_idle; + return ret; + } else if (ret == 0) { + /* FIXME: this might busyloop */ + continue; + } + + /* Be lazy, let packet_ask pull it out of the brigade */ + if (0 == + _libssh2_packet_ask(session, ret, &data, &data_len, 0, NULL, 0)) { + /* Smoke 'em if you got 'em */ + LIBSSH2_FREE(session, data); + *state = libssh2_NB_state_idle; + return ret; + } + } + + /* Only reached if the socket died */ + return LIBSSH2_ERROR_SOCKET_DISCONNECT; +} + +/* + * _libssh2_packet_requirev + * + * Loops _libssh2_transport_read() until one of a list of packet types + * requested is available. SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause + * a bailout. packet_types is a null terminated list of packet_type numbers + */ + +int +_libssh2_packet_requirev(LIBSSH2_SESSION *session, + const unsigned char *packet_types, + unsigned char **data, size_t *data_len, + int match_ofs, + const unsigned char *match_buf, size_t match_len, + packet_requirev_state_t * state) +{ + if (_libssh2_packet_askv(session, packet_types, data, data_len, match_ofs, + match_buf, match_len) == 0) { + /* One of the packets listed was available in the packet brigade */ + state->start = 0; + return 0; + } + + if (state->start == 0) { + state->start = time(NULL); + } + + while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) { + int ret = _libssh2_transport_read(session); + if ((ret < 0) && (ret != LIBSSH2_ERROR_EAGAIN)) { + state->start = 0; + return ret; + } + if (ret <= 0) { + long left = LIBSSH2_READ_TIMEOUT - + (long)(time(NULL) - state->start); + + if (left <= 0) { + state->start = 0; + return LIBSSH2_ERROR_TIMEOUT; + } + else if (ret == LIBSSH2_ERROR_EAGAIN) { + return ret; + } + } + + if (strchr((char *) packet_types, ret)) { + /* Be lazy, let packet_ask pull it out of the brigade */ + return _libssh2_packet_askv(session, packet_types, data, + data_len, match_ofs, match_buf, + match_len); + } + } + + /* Only reached if the socket died */ + state->start = 0; + return LIBSSH2_ERROR_SOCKET_DISCONNECT; +} + diff --git a/vendor/libssh2-1.4.2/src/packet.h b/vendor/libssh2-1.4.2/src/packet.h new file mode 100644 index 0000000..d66b15b --- /dev/null +++ b/vendor/libssh2-1.4.2/src/packet.h @@ -0,0 +1,76 @@ +#ifndef LIBSSH2_PACKET_H +#define LIBSSH2_PACKET_H +/* + * Copyright (C) 2010 by Daniel Stenberg + * Author: Daniel Stenberg + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +int _libssh2_packet_read(LIBSSH2_SESSION * session); + +int _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type, + unsigned char **data, size_t *data_len, + int match_ofs, + const unsigned char *match_buf, + size_t match_len); + +int _libssh2_packet_askv(LIBSSH2_SESSION * session, + const unsigned char *packet_types, + unsigned char **data, size_t *data_len, + int match_ofs, + const unsigned char *match_buf, + size_t match_len); +int _libssh2_packet_require(LIBSSH2_SESSION * session, + unsigned char packet_type, unsigned char **data, + size_t *data_len, int match_ofs, + const unsigned char *match_buf, + size_t match_len, + packet_require_state_t * state); +int _libssh2_packet_requirev(LIBSSH2_SESSION *session, + const unsigned char *packet_types, + unsigned char **data, size_t *data_len, + int match_ofs, + const unsigned char *match_buf, + size_t match_len, + packet_requirev_state_t * state); +int _libssh2_packet_burn(LIBSSH2_SESSION * session, + libssh2_nonblocking_states * state); +int _libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data, + unsigned long data_len); +int _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, + size_t datalen, int macstate); + +#endif /* LIBSSH2_PACKET_H */ diff --git a/vendor/libssh2-1.4.2/src/pem.c b/vendor/libssh2-1.4.2/src/pem.c new file mode 100644 index 0000000..5749bc8 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/pem.c @@ -0,0 +1,213 @@ +/* Copyright (C) 2007 The Written Word, Inc. + * Copyright (C) 2008, Simon Josefsson + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" + +#ifdef LIBSSH2_LIBGCRYPT /* compile only if we build with libgcrypt */ + +static int +readline(char *line, int line_size, FILE * fp) +{ + if (!fgets(line, line_size, fp)) { + return -1; + } + if (*line && line[strlen(line) - 1] == '\n') { + line[strlen(line) - 1] = '\0'; + } + if (*line && line[strlen(line) - 1] == '\r') { + line[strlen(line) - 1] = '\0'; + } + return 0; +} + +#define LINE_SIZE 128 + +int +_libssh2_pem_parse(LIBSSH2_SESSION * session, + const char *headerbegin, + const char *headerend, + FILE * fp, unsigned char **data, unsigned int *datalen) +{ + char line[LINE_SIZE]; + char *b64data = NULL; + unsigned int b64datalen = 0; + int ret; + + do { + if (readline(line, LINE_SIZE, fp)) { + return -1; + } + } + while (strcmp(line, headerbegin) != 0); + + *line = '\0'; + + do { + if (*line) { + char *tmp; + size_t linelen; + + linelen = strlen(line); + tmp = LIBSSH2_REALLOC(session, b64data, b64datalen + linelen); + if (!tmp) { + ret = -1; + goto out; + } + memcpy(tmp + b64datalen, line, linelen); + b64data = tmp; + b64datalen += linelen; + } + + if (readline(line, LINE_SIZE, fp)) { + ret = -1; + goto out; + } + } while (strcmp(line, headerend) != 0); + + if (libssh2_base64_decode(session, (char**) data, datalen, + b64data, b64datalen)) { + ret = -1; + goto out; + } + + ret = 0; + out: + if (b64data) { + LIBSSH2_FREE(session, b64data); + } + return ret; +} + +static int +read_asn1_length(const unsigned char *data, + unsigned int datalen, unsigned int *len) +{ + unsigned int lenlen; + int nextpos; + + if (datalen < 1) { + return -1; + } + *len = data[0]; + + if (*len >= 0x80) { + lenlen = *len & 0x7F; + *len = data[1]; + if (1 + lenlen > datalen) { + return -1; + } + if (lenlen > 1) { + *len <<= 8; + *len |= data[2]; + } + } else { + lenlen = 0; + } + + nextpos = 1 + lenlen; + if (lenlen > 2 || 1 + lenlen + *len > datalen) { + return -1; + } + + return nextpos; +} + +int +_libssh2_pem_decode_sequence(unsigned char **data, unsigned int *datalen) +{ + unsigned int len; + int lenlen; + + if (*datalen < 1) { + return -1; + } + + if ((*data)[0] != '\x30') { + return -1; + } + + (*data)++; + (*datalen)--; + + lenlen = read_asn1_length(*data, *datalen, &len); + if (lenlen < 0 || lenlen + len != *datalen) { + return -1; + } + + *data += lenlen; + *datalen -= lenlen; + + return 0; +} + +int +_libssh2_pem_decode_integer(unsigned char **data, unsigned int *datalen, + unsigned char **i, unsigned int *ilen) +{ + unsigned int len; + int lenlen; + + if (*datalen < 1) { + return -1; + } + + if ((*data)[0] != '\x02') { + return -1; + } + + (*data)++; + (*datalen)--; + + lenlen = read_asn1_length(*data, *datalen, &len); + if (lenlen < 0 || lenlen + len > *datalen) { + return -1; + } + + *data += lenlen; + *datalen -= lenlen; + + *i = *data; + *ilen = len; + + *data += len; + *datalen -= len; + + return 0; +} + +#endif /* LIBSSH2_LIBGCRYPT */ diff --git a/vendor/libssh2-1.4.2/src/publickey.c b/vendor/libssh2-1.4.2/src/publickey.c new file mode 100644 index 0000000..ab76ab2 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/publickey.c @@ -0,0 +1,1058 @@ +/* Copyright (c) 2004-2007, Sara Golemon + * Copyright (c) 2010 by Daniel Stenberg + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" +#include "libssh2_publickey.h" +#include "channel.h" +#include "session.h" + +#define LIBSSH2_PUBLICKEY_VERSION 2 + +/* Numericised response codes -- Not IETF, just local representation */ +#define LIBSSH2_PUBLICKEY_RESPONSE_STATUS 0 +#define LIBSSH2_PUBLICKEY_RESPONSE_VERSION 1 +#define LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY 2 + +typedef struct _LIBSSH2_PUBLICKEY_CODE_LIST +{ + int code; + const char *name; + int name_len; +} LIBSSH2_PUBLICKEY_CODE_LIST; + +static const LIBSSH2_PUBLICKEY_CODE_LIST publickey_response_codes[] = +{ + {LIBSSH2_PUBLICKEY_RESPONSE_STATUS, "status", sizeof("status") - 1}, + {LIBSSH2_PUBLICKEY_RESPONSE_VERSION, "version", sizeof("version") - 1}, + {LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY, "publickey", + sizeof("publickey") - 1} , + {0, NULL, 0} +}; + +/* PUBLICKEY status codes -- IETF defined */ +#define LIBSSH2_PUBLICKEY_SUCCESS 0 +#define LIBSSH2_PUBLICKEY_ACCESS_DENIED 1 +#define LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED 2 +#define LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED 3 +#define LIBSSH2_PUBLICKEY_KEY_NOT_FOUND 4 +#define LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED 5 +#define LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT 6 +#define LIBSSH2_PUBLICKEY_GENERAL_FAILURE 7 +#define LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED 8 + +#define LIBSSH2_PUBLICKEY_STATUS_CODE_MAX 8 + +static const LIBSSH2_PUBLICKEY_CODE_LIST publickey_status_codes[] = { + {LIBSSH2_PUBLICKEY_SUCCESS, "success", sizeof("success") - 1} , + {LIBSSH2_PUBLICKEY_ACCESS_DENIED, "access denied", + sizeof("access denied") - 1}, + {LIBSSH2_PUBLICKEY_STORAGE_EXCEEDED, "storage exceeded", + sizeof("storage exceeded") - 1} , + {LIBSSH2_PUBLICKEY_VERSION_NOT_SUPPORTED, "version not supported", + sizeof("version not supported") - 1} , + {LIBSSH2_PUBLICKEY_KEY_NOT_FOUND, "key not found", + sizeof("key not found") - 1}, + {LIBSSH2_PUBLICKEY_KEY_NOT_SUPPORTED, "key not supported", + sizeof("key not supported") - 1}, + {LIBSSH2_PUBLICKEY_KEY_ALREADY_PRESENT, "key already present", + sizeof("key already present") - 1}, + {LIBSSH2_PUBLICKEY_GENERAL_FAILURE, "general failure", + sizeof("general failure") - 1}, + {LIBSSH2_PUBLICKEY_REQUEST_NOT_SUPPORTED, "request not supported", + sizeof("request not supported") - 1}, + {0, NULL, 0} +}; + +/* + * publickey_status_error + * + * Format an error message from a status code + */ +static void +publickey_status_error(const LIBSSH2_PUBLICKEY *pkey, + LIBSSH2_SESSION *session, int status) +{ + const char *msg; + + /* GENERAL_FAILURE got remapped between version 1 and 2 */ + if (status == 6 && pkey && pkey->version == 1) { + status = 7; + } + + if (status < 0 || status > LIBSSH2_PUBLICKEY_STATUS_CODE_MAX) { + msg = "unknown"; + } else { + msg = publickey_status_codes[status].name; + } + + _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, msg); +} + +/* + * publickey_packet_receive + * + * Read a packet from the subsystem + */ +static int +publickey_packet_receive(LIBSSH2_PUBLICKEY * pkey, + unsigned char **data, size_t *data_len) +{ + LIBSSH2_CHANNEL *channel = pkey->channel; + LIBSSH2_SESSION *session = channel->session; + unsigned char buffer[4]; + int rc; + + if (pkey->receive_state == libssh2_NB_state_idle) { + rc = _libssh2_channel_read(channel, 0, (char *) buffer, 4); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc != 4) { + return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, + "Invalid response from publickey subsystem"); + } + + pkey->receive_packet_len = _libssh2_ntohu32(buffer); + pkey->receive_packet = + LIBSSH2_ALLOC(session, pkey->receive_packet_len); + if (!pkey->receive_packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate publickey response " + "buffer"); + } + + pkey->receive_state = libssh2_NB_state_sent; + } + + if (pkey->receive_state == libssh2_NB_state_sent) { + rc = _libssh2_channel_read(channel, 0, (char *) pkey->receive_packet, + pkey->receive_packet_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc != (int)pkey->receive_packet_len) { + LIBSSH2_FREE(session, pkey->receive_packet); + pkey->receive_packet = NULL; + pkey->receive_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, + "Timeout waiting for publickey subsystem " + "response packet"); + } + + *data = pkey->receive_packet; + *data_len = pkey->receive_packet_len; + } + + pkey->receive_state = libssh2_NB_state_idle; + + return 0; +} + +/* publickey_response_id + * + * Translate a string response name to a numeric code + * Data will be incremented by 4 + response_len on success only + */ +static int +publickey_response_id(unsigned char **pdata, size_t data_len) +{ + size_t response_len; + unsigned char *data = *pdata; + const LIBSSH2_PUBLICKEY_CODE_LIST *codes = publickey_response_codes; + + if (data_len < 4) { + /* Malformed response */ + return -1; + } + response_len = _libssh2_ntohu32(data); + data += 4; + data_len -= 4; + if (data_len < response_len) { + /* Malformed response */ + return -1; + } + + while (codes->name) { + if ((unsigned long)codes->name_len == response_len && + strncmp(codes->name, (char *) data, response_len) == 0) { + *pdata = data + response_len; + return codes->code; + } + codes++; + } + + return -1; +} + +/* publickey_response_success + * + * Generic helper routine to wait for success response and nothing else + */ +static int +publickey_response_success(LIBSSH2_PUBLICKEY * pkey) +{ + LIBSSH2_SESSION *session = pkey->channel->session; + unsigned char *data, *s; + size_t data_len; + int response; + + while (1) { + int rc = publickey_packet_receive(pkey, &data, &data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, + "Timeout waiting for response from " + "publickey subsystem"); + } + + s = data; + response = publickey_response_id(&s, data_len); + + switch (response) { + case LIBSSH2_PUBLICKEY_RESPONSE_STATUS: + /* Error, or processing complete */ + { + unsigned long status = _libssh2_ntohu32(s); + + LIBSSH2_FREE(session, data); + + if (status == LIBSSH2_PUBLICKEY_SUCCESS) + return 0; + + publickey_status_error(pkey, session, status); + return -1; + } + default: + LIBSSH2_FREE(session, data); + if (response < 0) { + return _libssh2_error(session, + LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, + "Invalid publickey subsystem response"); + } + /* Unknown/Unexpected */ + _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, + "Unexpected publickey subsystem response"); + data = NULL; + } + } + /* never reached, but include `return` to silence compiler warnings */ + return -1; +} + +/* ***************** + * Publickey API * + ***************** */ + +/* + * publickey_init + * + * Startup the publickey subsystem + */ +static LIBSSH2_PUBLICKEY *publickey_init(LIBSSH2_SESSION *session) +{ + int response; + int rc; + + if (session->pkeyInit_state == libssh2_NB_state_idle) { + session->pkeyInit_data = NULL; + session->pkeyInit_pkey = NULL; + session->pkeyInit_channel = NULL; + + _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + "Initializing publickey subsystem"); + + session->pkeyInit_state = libssh2_NB_state_allocated; + } + + if (session->pkeyInit_state == libssh2_NB_state_allocated) { + + session->pkeyInit_channel = + _libssh2_channel_open(session, "session", + sizeof("session") - 1, + LIBSSH2_CHANNEL_WINDOW_DEFAULT, + LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, + 0); + if (!session->pkeyInit_channel) { + if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) + /* The error state is already set, so leave it */ + return NULL; + _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, + "Unable to startup channel"); + goto err_exit; + } + + session->pkeyInit_state = libssh2_NB_state_sent; + } + + if (session->pkeyInit_state == libssh2_NB_state_sent) { + rc = _libssh2_channel_process_startup(session->pkeyInit_channel, + "subsystem", + sizeof("subsystem") - 1, + "publickey", + sizeof("publickey") - 1); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block starting publickey subsystem"); + return NULL; + } else if (rc) { + _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, + "Unable to request publickey subsystem"); + goto err_exit; + } + + session->pkeyInit_state = libssh2_NB_state_sent1; + } + + if (session->pkeyInit_state == libssh2_NB_state_sent1) { + unsigned char *s; + rc = _libssh2_channel_extended_data(session->pkeyInit_channel, + LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block starting publickey subsystem"); + return NULL; + } + + session->pkeyInit_pkey = + LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY)); + if (!session->pkeyInit_pkey) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate a new publickey structure"); + goto err_exit; + } + memset(session->pkeyInit_pkey, 0, sizeof(LIBSSH2_PUBLICKEY)); + session->pkeyInit_pkey->channel = session->pkeyInit_channel; + session->pkeyInit_pkey->version = 0; + + s = session->pkeyInit_buffer; + _libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4); + s += 4; + _libssh2_htonu32(s, sizeof("version") - 1); + s += 4; + memcpy(s, "version", sizeof("version") - 1); + s += sizeof("version") - 1; + _libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION); + + session->pkeyInit_buffer_sent = 0; + + _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + "Sending publickey advertising version %d support", + (int) LIBSSH2_PUBLICKEY_VERSION); + + session->pkeyInit_state = libssh2_NB_state_sent2; + } + + if (session->pkeyInit_state == libssh2_NB_state_sent2) { + rc = _libssh2_channel_write(session->pkeyInit_channel, 0, + session->pkeyInit_buffer, + 19 - session->pkeyInit_buffer_sent); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block sending publickey version packet"); + return NULL; + } else if (rc) { + _libssh2_error(session, rc, + "Unable to send publickey version packet"); + goto err_exit; + } + session->pkeyInit_buffer_sent += rc; + if(session->pkeyInit_buffer_sent < 19) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Need to be called again to complete this"); + return NULL; + } + + session->pkeyInit_state = libssh2_NB_state_sent3; + } + + if (session->pkeyInit_state == libssh2_NB_state_sent3) { + while (1) { + unsigned char *s; + rc = publickey_packet_receive(session->pkeyInit_pkey, + &session->pkeyInit_data, + &session->pkeyInit_data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block waiting for response from " + "publickey subsystem"); + return NULL; + } else if (rc) { + _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, + "Timeout waiting for response from " + "publickey subsystem"); + goto err_exit; + } + + s = session->pkeyInit_data; + if ((response = + publickey_response_id(&s, session->pkeyInit_data_len)) < 0) { + _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, + "Invalid publickey subsystem response code"); + goto err_exit; + } + + switch (response) { + case LIBSSH2_PUBLICKEY_RESPONSE_STATUS: + /* Error */ + { + unsigned long status, descr_len, lang_len; + + status = _libssh2_ntohu32(s); + s += 4; + descr_len = _libssh2_ntohu32(s); + s += 4; + /* description starts here */ + s += descr_len; + lang_len = _libssh2_ntohu32(s); + s += 4; + /* lang starts here */ + s += lang_len; + + if (s > + session->pkeyInit_data + session->pkeyInit_data_len) { + _libssh2_error(session, + LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, + "Malformed publickey subsystem packet"); + goto err_exit; + } + + publickey_status_error(NULL, session, status); + + goto err_exit; + } + + case LIBSSH2_PUBLICKEY_RESPONSE_VERSION: + /* What we want */ + session->pkeyInit_pkey->version = _libssh2_ntohu32(s); + if (session->pkeyInit_pkey->version > + LIBSSH2_PUBLICKEY_VERSION) { + _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + "Truncate remote publickey version from %lu", + session->pkeyInit_pkey->version); + session->pkeyInit_pkey->version = + LIBSSH2_PUBLICKEY_VERSION; + } + _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + "Enabling publickey subsystem version %lu", + session->pkeyInit_pkey->version); + LIBSSH2_FREE(session, session->pkeyInit_data); + session->pkeyInit_data = NULL; + session->pkeyInit_state = libssh2_NB_state_idle; + return session->pkeyInit_pkey; + + default: + /* Unknown/Unexpected */ + _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, + "Unexpected publickey subsystem response, " + "ignoring"); + LIBSSH2_FREE(session, session->pkeyInit_data); + session->pkeyInit_data = NULL; + } + } + } + + /* Never reached except by direct goto */ + err_exit: + session->pkeyInit_state = libssh2_NB_state_sent4; + if (session->pkeyInit_channel) { + rc = _libssh2_channel_close(session->pkeyInit_channel); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block closing channel"); + return NULL; + } + } + if (session->pkeyInit_pkey) { + LIBSSH2_FREE(session, session->pkeyInit_pkey); + session->pkeyInit_pkey = NULL; + } + if (session->pkeyInit_data) { + LIBSSH2_FREE(session, session->pkeyInit_data); + session->pkeyInit_data = NULL; + } + session->pkeyInit_state = libssh2_NB_state_idle; + return NULL; +} + +/* + * libssh2_publickey_init + * + * Startup the publickey subsystem + */ +LIBSSH2_API LIBSSH2_PUBLICKEY * +libssh2_publickey_init(LIBSSH2_SESSION *session) +{ + LIBSSH2_PUBLICKEY *ptr; + + BLOCK_ADJUST_ERRNO(ptr, session, + publickey_init(session)); + return ptr; +} + + + +/* + * libssh2_publickey_add_ex + * + * Add a new public key entry + */ +LIBSSH2_API int +libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, + unsigned long name_len, const unsigned char *blob, + unsigned long blob_len, char overwrite, + unsigned long num_attrs, + const libssh2_publickey_attribute attrs[]) +{ + LIBSSH2_CHANNEL *channel; + LIBSSH2_SESSION *session; + /* 19 = packet_len(4) + add_len(4) + "add"(3) + name_len(4) + {name} + blob_len(4) + {blob} */ + unsigned long i, packet_len = 19 + name_len + blob_len; + unsigned char *comment = NULL; + unsigned long comment_len = 0; + int rc; + + if(!pkey) + return LIBSSH2_ERROR_BAD_USE; + + channel = pkey->channel; + session = channel->session; + + if (pkey->add_state == libssh2_NB_state_idle) { + pkey->add_packet = NULL; + + _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, "Adding %s publickey", + name); + + if (pkey->version == 1) { + for(i = 0; i < num_attrs; i++) { + /* Search for a comment attribute */ + if (attrs[i].name_len == (sizeof("comment") - 1) && + strncmp(attrs[i].name, "comment", + sizeof("comment") - 1) == 0) { + comment = (unsigned char *) attrs[i].value; + comment_len = attrs[i].value_len; + break; + } + } + packet_len += 4 + comment_len; + } else { + packet_len += 5; /* overwrite(1) + attribute_count(4) */ + for(i = 0; i < num_attrs; i++) { + packet_len += 9 + attrs[i].name_len + attrs[i].value_len; + /* name_len(4) + value_len(4) + mandatory(1) */ + } + } + + pkey->add_packet = LIBSSH2_ALLOC(session, packet_len); + if (!pkey->add_packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "publickey \"add\" packet"); + } + + pkey->add_s = pkey->add_packet; + _libssh2_htonu32(pkey->add_s, packet_len - 4); + pkey->add_s += 4; + _libssh2_htonu32(pkey->add_s, sizeof("add") - 1); + pkey->add_s += 4; + memcpy(pkey->add_s, "add", sizeof("add") - 1); + pkey->add_s += sizeof("add") - 1; + if (pkey->version == 1) { + _libssh2_htonu32(pkey->add_s, comment_len); + pkey->add_s += 4; + if (comment) { + memcpy(pkey->add_s, comment, comment_len); + pkey->add_s += comment_len; + } + + _libssh2_htonu32(pkey->add_s, name_len); + pkey->add_s += 4; + memcpy(pkey->add_s, name, name_len); + pkey->add_s += name_len; + _libssh2_htonu32(pkey->add_s, blob_len); + pkey->add_s += 4; + memcpy(pkey->add_s, blob, blob_len); + pkey->add_s += blob_len; + } else { + /* Version == 2 */ + + _libssh2_htonu32(pkey->add_s, name_len); + pkey->add_s += 4; + memcpy(pkey->add_s, name, name_len); + pkey->add_s += name_len; + _libssh2_htonu32(pkey->add_s, blob_len); + pkey->add_s += 4; + memcpy(pkey->add_s, blob, blob_len); + pkey->add_s += blob_len; + *(pkey->add_s++) = overwrite ? 0x01 : 0; + _libssh2_htonu32(pkey->add_s, num_attrs); + pkey->add_s += 4; + for(i = 0; i < num_attrs; i++) { + _libssh2_htonu32(pkey->add_s, attrs[i].name_len); + pkey->add_s += 4; + memcpy(pkey->add_s, attrs[i].name, attrs[i].name_len); + pkey->add_s += attrs[i].name_len; + _libssh2_htonu32(pkey->add_s, attrs[i].value_len); + pkey->add_s += 4; + memcpy(pkey->add_s, attrs[i].value, attrs[i].value_len); + pkey->add_s += attrs[i].value_len; + *(pkey->add_s++) = attrs[i].mandatory ? 0x01 : 0; + } + } + + _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + "Sending publickey \"add\" packet: " + "type=%s blob_len=%ld num_attrs=%ld", + name, blob_len, num_attrs); + + pkey->add_state = libssh2_NB_state_created; + } + + if (pkey->add_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, pkey->add_packet, + (pkey->add_s - pkey->add_packet)); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if ((pkey->add_s - pkey->add_packet) != rc) { + LIBSSH2_FREE(session, pkey->add_packet); + pkey->add_packet = NULL; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send publickey add packet"); + } + LIBSSH2_FREE(session, pkey->add_packet); + pkey->add_packet = NULL; + + pkey->add_state = libssh2_NB_state_sent; + } + + rc = publickey_response_success(pkey); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + + pkey->add_state = libssh2_NB_state_idle; + + return rc; +} + +/* libssh2_publickey_remove_ex + * Remove an existing publickey so that authentication can no longer be + * performed using it + */ +LIBSSH2_API int +libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY * pkey, + const unsigned char *name, unsigned long name_len, + const unsigned char *blob, unsigned long blob_len) +{ + LIBSSH2_CHANNEL *channel; + LIBSSH2_SESSION *session; + /* 22 = packet_len(4) + remove_len(4) + "remove"(6) + name_len(4) + {name} + + blob_len(4) + {blob} */ + unsigned long packet_len = 22 + name_len + blob_len; + int rc; + + if(!pkey) + return LIBSSH2_ERROR_BAD_USE; + + channel = pkey->channel; + session = channel->session; + + if (pkey->remove_state == libssh2_NB_state_idle) { + pkey->remove_packet = NULL; + + pkey->remove_packet = LIBSSH2_ALLOC(session, packet_len); + if (!pkey->remove_packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "publickey \"remove\" packet"); + } + + pkey->remove_s = pkey->remove_packet; + _libssh2_htonu32(pkey->remove_s, packet_len - 4); + pkey->remove_s += 4; + _libssh2_htonu32(pkey->remove_s, sizeof("remove") - 1); + pkey->remove_s += 4; + memcpy(pkey->remove_s, "remove", sizeof("remove") - 1); + pkey->remove_s += sizeof("remove") - 1; + _libssh2_htonu32(pkey->remove_s, name_len); + pkey->remove_s += 4; + memcpy(pkey->remove_s, name, name_len); + pkey->remove_s += name_len; + _libssh2_htonu32(pkey->remove_s, blob_len); + pkey->remove_s += 4; + memcpy(pkey->remove_s, blob, blob_len); + pkey->remove_s += blob_len; + + _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + "Sending publickey \"remove\" packet: " + "type=%s blob_len=%ld", + name, blob_len); + + pkey->remove_state = libssh2_NB_state_created; + } + + if (pkey->remove_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, pkey->remove_packet, + (pkey->remove_s - pkey->remove_packet)); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if ((pkey->remove_s - pkey->remove_packet) != rc) { + LIBSSH2_FREE(session, pkey->remove_packet); + pkey->remove_packet = NULL; + pkey->remove_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send publickey remove packet"); + } + LIBSSH2_FREE(session, pkey->remove_packet); + pkey->remove_packet = NULL; + + pkey->remove_state = libssh2_NB_state_sent; + } + + rc = publickey_response_success(pkey); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + + pkey->remove_state = libssh2_NB_state_idle; + + return rc; +} + +/* libssh2_publickey_list_fetch + * Fetch a list of supported public key from a server + */ +LIBSSH2_API int +libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY * pkey, unsigned long *num_keys, + libssh2_publickey_list ** pkey_list) +{ + LIBSSH2_CHANNEL *channel; + LIBSSH2_SESSION *session; + libssh2_publickey_list *list = NULL; + unsigned long buffer_len = 12, keys = 0, max_keys = 0, i; + /* 12 = packet_len(4) + list_len(4) + "list"(4) */ + int response; + int rc; + + if(!pkey) + return LIBSSH2_ERROR_BAD_USE; + + channel = pkey->channel; + session = channel->session; + + if (pkey->listFetch_state == libssh2_NB_state_idle) { + pkey->listFetch_data = NULL; + + pkey->listFetch_s = pkey->listFetch_buffer; + _libssh2_htonu32(pkey->listFetch_s, buffer_len - 4); + pkey->listFetch_s += 4; + _libssh2_htonu32(pkey->listFetch_s, sizeof("list") - 1); + pkey->listFetch_s += 4; + memcpy(pkey->listFetch_s, "list", sizeof("list") - 1); + pkey->listFetch_s += sizeof("list") - 1; + + _libssh2_debug(session, LIBSSH2_TRACE_PUBLICKEY, + "Sending publickey \"list\" packet"); + + pkey->listFetch_state = libssh2_NB_state_created; + } + + if (pkey->listFetch_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, + pkey->listFetch_buffer, + (pkey->listFetch_s - + pkey->listFetch_buffer)); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if ((pkey->listFetch_s - pkey->listFetch_buffer) != rc) { + pkey->listFetch_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send publickey list packet"); + } + + pkey->listFetch_state = libssh2_NB_state_sent; + } + + while (1) { + rc = publickey_packet_receive(pkey, &pkey->listFetch_data, + &pkey->listFetch_data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + _libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, + "Timeout waiting for response from " + "publickey subsystem"); + goto err_exit; + } + + pkey->listFetch_s = pkey->listFetch_data; + if ((response = + publickey_response_id(&pkey->listFetch_s, + pkey->listFetch_data_len)) < 0) { + _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, + "Invalid publickey subsystem response code"); + goto err_exit; + } + + switch (response) { + case LIBSSH2_PUBLICKEY_RESPONSE_STATUS: + /* Error, or processing complete */ + { + unsigned long status, descr_len, lang_len; + + status = _libssh2_ntohu32(pkey->listFetch_s); + pkey->listFetch_s += 4; + descr_len = _libssh2_ntohu32(pkey->listFetch_s); + pkey->listFetch_s += 4; + /* description starts at pkey->listFetch_s */ + pkey->listFetch_s += descr_len; + lang_len = _libssh2_ntohu32(pkey->listFetch_s); + pkey->listFetch_s += 4; + /* lang starts at pkey->listFetch_s */ + pkey->listFetch_s += lang_len; + + if (pkey->listFetch_s > + pkey->listFetch_data + pkey->listFetch_data_len) { + _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, + "Malformed publickey subsystem packet"); + goto err_exit; + } + + if (status == LIBSSH2_PUBLICKEY_SUCCESS) { + LIBSSH2_FREE(session, pkey->listFetch_data); + pkey->listFetch_data = NULL; + *pkey_list = list; + *num_keys = keys; + pkey->listFetch_state = libssh2_NB_state_idle; + return 0; + } + + publickey_status_error(pkey, session, status); + goto err_exit; + } + case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY: + /* What we want */ + if (keys >= max_keys) { + libssh2_publickey_list *newlist; + /* Grow the key list if necessary */ + max_keys += 8; + newlist = + LIBSSH2_REALLOC(session, list, + (max_keys + + 1) * sizeof(libssh2_publickey_list)); + if (!newlist) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "publickey list"); + goto err_exit; + } + list = newlist; + } + if (pkey->version == 1) { + unsigned long comment_len; + + comment_len = _libssh2_ntohu32(pkey->listFetch_s); + pkey->listFetch_s += 4; + if (comment_len) { + list[keys].num_attrs = 1; + list[keys].attrs = + LIBSSH2_ALLOC(session, + sizeof(libssh2_publickey_attribute)); + if (!list[keys].attrs) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "publickey attributes"); + goto err_exit; + } + list[keys].attrs[0].name = "comment"; + list[keys].attrs[0].name_len = sizeof("comment") - 1; + list[keys].attrs[0].value = (char *) pkey->listFetch_s; + list[keys].attrs[0].value_len = comment_len; + list[keys].attrs[0].mandatory = 0; + + pkey->listFetch_s += comment_len; + } else { + list[keys].num_attrs = 0; + list[keys].attrs = NULL; + } + list[keys].name_len = _libssh2_ntohu32(pkey->listFetch_s); + pkey->listFetch_s += 4; + list[keys].name = pkey->listFetch_s; + pkey->listFetch_s += list[keys].name_len; + list[keys].blob_len = _libssh2_ntohu32(pkey->listFetch_s); + pkey->listFetch_s += 4; + list[keys].blob = pkey->listFetch_s; + pkey->listFetch_s += list[keys].blob_len; + } else { + /* Version == 2 */ + list[keys].name_len = _libssh2_ntohu32(pkey->listFetch_s); + pkey->listFetch_s += 4; + list[keys].name = pkey->listFetch_s; + pkey->listFetch_s += list[keys].name_len; + list[keys].blob_len = _libssh2_ntohu32(pkey->listFetch_s); + pkey->listFetch_s += 4; + list[keys].blob = pkey->listFetch_s; + pkey->listFetch_s += list[keys].blob_len; + list[keys].num_attrs = _libssh2_ntohu32(pkey->listFetch_s); + pkey->listFetch_s += 4; + if (list[keys].num_attrs) { + list[keys].attrs = + LIBSSH2_ALLOC(session, + list[keys].num_attrs * + sizeof(libssh2_publickey_attribute)); + if (!list[keys].attrs) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "publickey attributes"); + goto err_exit; + } + for(i = 0; i < list[keys].num_attrs; i++) { + list[keys].attrs[i].name_len = + _libssh2_ntohu32(pkey->listFetch_s); + pkey->listFetch_s += 4; + list[keys].attrs[i].name = (char *) pkey->listFetch_s; + pkey->listFetch_s += list[keys].attrs[i].name_len; + list[keys].attrs[i].value_len = + _libssh2_ntohu32(pkey->listFetch_s); + pkey->listFetch_s += 4; + list[keys].attrs[i].value = (char *) pkey->listFetch_s; + pkey->listFetch_s += list[keys].attrs[i].value_len; + + /* actually an ignored value */ + list[keys].attrs[i].mandatory = 0; + } + } else { + list[keys].attrs = NULL; + } + } + /* To be FREEd in libssh2_publickey_list_free() */ + list[keys].packet = pkey->listFetch_data; + keys++; + + list[keys].packet = NULL; /* Terminate the list */ + pkey->listFetch_data = NULL; + break; + default: + /* Unknown/Unexpected */ + _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, + "Unexpected publickey subsystem response"); + LIBSSH2_FREE(session, pkey->listFetch_data); + pkey->listFetch_data = NULL; + } + } + + /* Only reached via explicit goto */ + err_exit: + if (pkey->listFetch_data) { + LIBSSH2_FREE(session, pkey->listFetch_data); + pkey->listFetch_data = NULL; + } + if (list) { + libssh2_publickey_list_free(pkey, list); + } + pkey->listFetch_state = libssh2_NB_state_idle; + return -1; +} + +/* libssh2_publickey_list_free + * Free a previously fetched list of public keys + */ +LIBSSH2_API void +libssh2_publickey_list_free(LIBSSH2_PUBLICKEY * pkey, + libssh2_publickey_list * pkey_list) +{ + LIBSSH2_SESSION *session; + libssh2_publickey_list *p = pkey_list; + + if(!pkey || !p) + return; + + session = pkey->channel->session; + + while (p->packet) { + if (p->attrs) { + LIBSSH2_FREE(session, p->attrs); + } + LIBSSH2_FREE(session, p->packet); + p++; + } + + LIBSSH2_FREE(session, pkey_list); +} + +/* libssh2_publickey_shutdown + * Shutdown the publickey subsystem + */ +LIBSSH2_API int +libssh2_publickey_shutdown(LIBSSH2_PUBLICKEY *pkey) +{ + LIBSSH2_SESSION *session; + int rc; + + if(!pkey) + return LIBSSH2_ERROR_BAD_USE; + + session = pkey->channel->session; + + /* + * Make sure all memory used in the state variables are free + */ + if (pkey->receive_packet) { + LIBSSH2_FREE(session, pkey->receive_packet); + pkey->receive_packet = NULL; + } + if (pkey->add_packet) { + LIBSSH2_FREE(session, pkey->add_packet); + pkey->add_packet = NULL; + } + if (pkey->remove_packet) { + LIBSSH2_FREE(session, pkey->remove_packet); + pkey->remove_packet = NULL; + } + if (pkey->listFetch_data) { + LIBSSH2_FREE(session, pkey->listFetch_data); + pkey->listFetch_data = NULL; + } + + rc = _libssh2_channel_free(pkey->channel); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + + LIBSSH2_FREE(session, pkey); + return 0; +} diff --git a/vendor/libssh2-1.4.2/src/scp.c b/vendor/libssh2-1.4.2/src/scp.c new file mode 100644 index 0000000..6401dac --- /dev/null +++ b/vendor/libssh2-1.4.2/src/scp.c @@ -0,0 +1,1085 @@ +/* Copyright (c) 2009-2010 by Daniel Stenberg + * Copyright (c) 2004-2008, Sara Golemon + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" +#include +#include + +#include "channel.h" +#include "session.h" + + +/* Max. length of a quoted string after libssh2_shell_quotearg() processing */ +#define _libssh2_shell_quotedsize(s) (3 * strlen(s) + 2) + +/* + This function quotes a string in a way suitable to be used with a + shell, e.g. the file name + one two + becomes + 'one two' + + The resulting output string is crafted in a way that makes it usable + with the two most common shell types: Bourne Shell derived shells + (sh, ksh, ksh93, bash, zsh) and C-Shell derivates (csh, tcsh). + + The following special cases are handled: + o If the string contains an apostrophy itself, the apostrophy + character is written in quotation marks, e.g. "'". + The shell cannot handle the syntax 'doesn\'t', so we close the + current argument word, add the apostrophe in quotation marks "", + and open a new argument word instead (_ indicate the input + string characters): + _____ _ _ + 'doesn' "'" 't' + + Sequences of apostrophes are combined in one pair of quotation marks: + a'''b + becomes + _ ___ _ + 'a'"'''"'b' + + o If the string contains an exclamation mark (!), the C-Shell + interprets it as an event number. Using \! (not within quotation + marks or single quotation marks) is a mechanism understood by + both Bourne Shell and C-Shell. + + If a quotation was already started, the argument word is closed + first: + a!b + + become + _ _ _ + 'a'\!'b' + + The result buffer must be large enough for the expanded result. A + bad case regarding expansion is alternating characters and + apostrophes: + + a'b'c'd' (length 8) gets converted to + 'a'"'"'b'"'"'c'"'"'d'"'" (length 24) + + This is the worst case. + + Maximum length of the result: + 1 + 6 * (length(input) + 1) / 2) + 1 + + => 3 * length(input) + 2 + + Explanation: + o leading apostrophe + o one character / apostrophe pair (two characters) can get + represented as 6 characters: a' -> a'"'"' + o String terminator (+1) + + A result buffer three times the size of the input buffer + 2 + characters should be safe. + + References: + o csh-compatible quotation (special handling for '!' etc.), see + http://www.grymoire.com/Unix/Csh.html#toc-uh-10 + + Return value: + Length of the resulting string (not counting the terminating '\0'), + or 0 in case of errors, e.g. result buffer too small + + Note: this function could possible be used elsewhere within libssh2, but + until then it is kept static and in this source file. +*/ + +static unsigned +shell_quotearg(const char *path, unsigned char *buf, + unsigned bufsize) +{ + const char *src; + unsigned char *dst, *endp; + + /* + * Processing States: + * UQSTRING: unquoted string: ... -- used for quoting exclamation + * marks. This is the initial state + * SQSTRING: single-qouted-string: '... -- any character may follow + * QSTRING: quoted string: "... -- only apostrophes may follow + */ + enum { UQSTRING, SQSTRING, QSTRING } state = UQSTRING; + + endp = &buf[bufsize]; + src = path; + dst = buf; + while (*src && dst < endp - 1) { + + switch (*src) { + /* + * Special handling for apostrophe. + * An apostrophe is always written in quotation marks, e.g. + * ' -> "'". + */ + + case '\'': + switch (state) { + case UQSTRING: /* Unquoted string */ + if (dst+1 >= endp) + return 0; + *dst++ = '"'; + break; + case QSTRING: /* Continue quoted string */ + break; + case SQSTRING: /* Close single quoted string */ + if (dst+2 >= endp) + return 0; + *dst++ = '\''; + *dst++ = '"'; + break; + default: + break; + } + state = QSTRING; + break; + + /* + * Special handling for exclamation marks. CSH interprets + * exclamation marks even when quoted with apostrophes. We convert + * it to the plain string \!, because both Bourne Shell and CSH + * interpret that as a verbatim exclamation mark. + */ + + case '!': + switch (state) { + case UQSTRING: + if (dst+1 >= endp) + return 0; + *dst++ = '\\'; + break; + case QSTRING: + if (dst+2 >= endp) + return 0; + *dst++ = '"'; /* Closing quotation mark */ + *dst++ = '\\'; + break; + case SQSTRING: /* Close single quoted string */ + if (dst+2 >= endp) + return 0; + *dst++ = '\''; + *dst++ = '\\'; + break; + default: + break; + } + state = UQSTRING; + break; + + /* + * Ordinary character: prefer single-quoted string + */ + + default: + switch (state) { + case UQSTRING: + if (dst+1 >= endp) + return 0; + *dst++ = '\''; + break; + case QSTRING: + if (dst+2 >= endp) + return 0; + *dst++ = '"'; /* Closing quotation mark */ + *dst++ = '\''; + break; + case SQSTRING: /* Continue single quoted string */ + break; + default: + break; + } + state = SQSTRING; /* Start single-quoted string */ + break; + } + + if (dst+1 >= endp) + return 0; + *dst++ = *src++; + } + + switch (state) { + case UQSTRING: + break; + case QSTRING: /* Close quoted string */ + if (dst+1 >= endp) + return 0; + *dst++ = '"'; + break; + case SQSTRING: /* Close single quoted string */ + if (dst+1 >= endp) + return 0; + *dst++ = '\''; + break; + default: + break; + } + + if (dst+1 >= endp) + return 0; + *dst = '\0'; + + /* The result cannot be larger than 3 * strlen(path) + 2 */ + /* assert((dst - buf) <= (3 * (src - path) + 2)); */ + + return dst - buf; +} + +/* + * scp_recv + * + * Open a channel and request a remote file via SCP + * + */ +static LIBSSH2_CHANNEL * +scp_recv(LIBSSH2_SESSION * session, const char *path, struct stat * sb) +{ + int cmd_len; + int rc; + int tmp_err_code; + const char *tmp_err_msg; + + if (session->scpRecv_state == libssh2_NB_state_idle) { + session->scpRecv_mode = 0; + session->scpRecv_size = 0; + session->scpRecv_mtime = 0; + session->scpRecv_atime = 0; + + session->scpRecv_command_len = + _libssh2_shell_quotedsize(path) + sizeof("scp -f ") + (sb?1:0); + + session->scpRecv_command = + LIBSSH2_ALLOC(session, session->scpRecv_command_len); + + if (!session->scpRecv_command) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate a command buffer for " + "SCP session"); + return NULL; + } + + snprintf((char *)session->scpRecv_command, + session->scpRecv_command_len, "scp -%sf ", sb?"p":""); + + cmd_len = strlen((char *)session->scpRecv_command); + + (void) shell_quotearg(path, + &session->scpRecv_command[cmd_len], + session->scpRecv_command_len - cmd_len); + + + _libssh2_debug(session, LIBSSH2_TRACE_SCP, + "Opening channel for SCP receive"); + + session->scpRecv_state = libssh2_NB_state_created; + } + + if (session->scpRecv_state == libssh2_NB_state_created) { + /* Allocate a channel */ + session->scpRecv_channel = + _libssh2_channel_open(session, "session", + sizeof("session") - 1, + LIBSSH2_CHANNEL_WINDOW_DEFAULT, + LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, + 0); + if (!session->scpRecv_channel) { + if (libssh2_session_last_errno(session) != + LIBSSH2_ERROR_EAGAIN) { + LIBSSH2_FREE(session, session->scpRecv_command); + session->scpRecv_command = NULL; + session->scpRecv_state = libssh2_NB_state_idle; + } + else { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block starting up channel"); + } + return NULL; + } + + session->scpRecv_state = libssh2_NB_state_sent; + } + + if (session->scpRecv_state == libssh2_NB_state_sent) { + /* Request SCP for the desired file */ + rc = _libssh2_channel_process_startup(session->scpRecv_channel, "exec", + sizeof("exec") - 1, + (char *) session->scpRecv_command, + session->scpRecv_command_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block requesting SCP startup"); + return NULL; + } else if (rc) { + LIBSSH2_FREE(session, session->scpRecv_command); + session->scpRecv_command = NULL; + goto scp_recv_error; + } + LIBSSH2_FREE(session, session->scpRecv_command); + session->scpRecv_command = NULL; + + _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sending initial wakeup"); + /* SCP ACK */ + session->scpRecv_response[0] = '\0'; + + session->scpRecv_state = libssh2_NB_state_sent1; + } + + if (session->scpRecv_state == libssh2_NB_state_sent1) { + rc = _libssh2_channel_write(session->scpRecv_channel, 0, + session->scpRecv_response, 1); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block sending initial wakeup"); + return NULL; + } else if (rc != 1) { + goto scp_recv_error; + } + + /* Parse SCP response */ + session->scpRecv_response_len = 0; + + session->scpRecv_state = libssh2_NB_state_sent2; + } + + if ((session->scpRecv_state == libssh2_NB_state_sent2) + || (session->scpRecv_state == libssh2_NB_state_sent3)) { + while (sb && (session->scpRecv_response_len < + LIBSSH2_SCP_RESPONSE_BUFLEN)) { + unsigned char *s, *p; + + if (session->scpRecv_state == libssh2_NB_state_sent2) { + rc = _libssh2_channel_read(session->scpRecv_channel, 0, + (char *) session-> + scpRecv_response + + session->scpRecv_response_len, 1); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block waiting for SCP response"); + return NULL; + } + else if (rc < 0) { + /* error, give up */ + _libssh2_error(session, rc, "Failed reading SCP response"); + goto scp_recv_error; + } + else if(rc == 0) + goto scp_recv_empty_channel; + + session->scpRecv_response_len++; + + if (session->scpRecv_response[0] != 'T') { + size_t err_len; + char *err_msg; + + /* there can be + 01 for warnings + 02 for errors + + The following string MUST be newline terminated + */ + err_len = + _libssh2_channel_packet_data_len(session-> + scpRecv_channel, 0); + err_msg = LIBSSH2_ALLOC(session, err_len + 1); + if (!err_msg) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed to get memory "); + goto scp_recv_error; + } + + /* Read the remote error message */ + (void)_libssh2_channel_read(session->scpRecv_channel, 0, + err_msg, err_len); + /* If it failed for any reason, we ignore it anyway. */ + + /* zero terminate the error */ + err_msg[err_len]=0; + + _libssh2_debug(session, LIBSSH2_TRACE_SCP, + "got %02x %s", session->scpRecv_response[0], + err_msg); + + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Failed to recv file"); + + LIBSSH2_FREE(session, err_msg); + goto scp_recv_error; + } + + if ((session->scpRecv_response_len > 1) && + ((session-> + scpRecv_response[session->scpRecv_response_len - 1] < + '0') + || (session-> + scpRecv_response[session->scpRecv_response_len - 1] > + '9')) + && (session-> + scpRecv_response[session->scpRecv_response_len - 1] != + ' ') + && (session-> + scpRecv_response[session->scpRecv_response_len - 1] != + '\r') + && (session-> + scpRecv_response[session->scpRecv_response_len - 1] != + '\n')) { + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid data in SCP response"); + goto scp_recv_error; + } + + if ((session->scpRecv_response_len < 9) + || (session-> + scpRecv_response[session->scpRecv_response_len - 1] != + '\n')) { + if (session->scpRecv_response_len == + LIBSSH2_SCP_RESPONSE_BUFLEN) { + /* You had your chance */ + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Unterminated response from SCP server"); + goto scp_recv_error; + } + /* Way too short to be an SCP response, or not done yet, + short circuit */ + continue; + } + + /* We're guaranteed not to go under response_len == 0 by the + logic above */ + while ((session-> + scpRecv_response[session->scpRecv_response_len - 1] == + '\r') + || (session-> + scpRecv_response[session->scpRecv_response_len - + 1] == '\n')) + session->scpRecv_response_len--; + session->scpRecv_response[session->scpRecv_response_len] = + '\0'; + + if (session->scpRecv_response_len < 8) { + /* EOL came too soon */ + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid response from SCP server, " + "too short" ); + goto scp_recv_error; + } + + s = session->scpRecv_response + 1; + + p = (unsigned char *) strchr((char *) s, ' '); + if (!p || ((p - s) <= 0)) { + /* No spaces or space in the wrong spot */ + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid response from SCP server, " + "malformed mtime"); + goto scp_recv_error; + } + + *(p++) = '\0'; + /* Make sure we don't get fooled by leftover values */ + session->scpRecv_mtime = strtol((char *) s, NULL, 10); + + s = (unsigned char *) strchr((char *) p, ' '); + if (!s || ((s - p) <= 0)) { + /* No spaces or space in the wrong spot */ + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid response from SCP server, malformed mtime.usec"); + goto scp_recv_error; + } + + /* Ignore mtime.usec */ + s++; + p = (unsigned char *) strchr((char *) s, ' '); + if (!p || ((p - s) <= 0)) { + /* No spaces or space in the wrong spot */ + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid response from SCP server, too short or malformed"); + goto scp_recv_error; + } + + *p = '\0'; + /* Make sure we don't get fooled by leftover values */ + session->scpRecv_atime = strtol((char *) s, NULL, 10); + + /* SCP ACK */ + session->scpRecv_response[0] = '\0'; + + session->scpRecv_state = libssh2_NB_state_sent3; + } + + if (session->scpRecv_state == libssh2_NB_state_sent3) { + rc = _libssh2_channel_write(session->scpRecv_channel, 0, + session->scpRecv_response, 1); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block waiting to send SCP ACK"); + return NULL; + } else if (rc != 1) { + goto scp_recv_error; + } + + _libssh2_debug(session, LIBSSH2_TRACE_SCP, + "mtime = %ld, atime = %ld", + session->scpRecv_mtime, session->scpRecv_atime); + + /* We *should* check that atime.usec is valid, but why let + that stop use? */ + break; + } + } + + session->scpRecv_state = libssh2_NB_state_sent4; + } + + if (session->scpRecv_state == libssh2_NB_state_sent4) { + session->scpRecv_response_len = 0; + + session->scpRecv_state = libssh2_NB_state_sent5; + } + + if ((session->scpRecv_state == libssh2_NB_state_sent5) + || (session->scpRecv_state == libssh2_NB_state_sent6)) { + while (session->scpRecv_response_len < LIBSSH2_SCP_RESPONSE_BUFLEN) { + char *s, *p, *e = NULL; + + if (session->scpRecv_state == libssh2_NB_state_sent5) { + rc = _libssh2_channel_read(session->scpRecv_channel, 0, + (char *) session-> + scpRecv_response + + session->scpRecv_response_len, 1); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block waiting for SCP response"); + return NULL; + } + else if (rc < 0) { + /* error, bail out*/ + _libssh2_error(session, rc, "Failed reading SCP response"); + goto scp_recv_error; + } + else if(rc == 0) + goto scp_recv_empty_channel; + + session->scpRecv_response_len++; + + if (session->scpRecv_response[0] != 'C') { + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid response from SCP server"); + goto scp_recv_error; + } + + if ((session->scpRecv_response_len > 1) && + (session-> + scpRecv_response[session->scpRecv_response_len - 1] != + '\r') + && (session-> + scpRecv_response[session->scpRecv_response_len - 1] != + '\n') + && + (session-> + scpRecv_response[session->scpRecv_response_len - 1] + < 32)) { + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid data in SCP response"); + goto scp_recv_error; + } + + if ((session->scpRecv_response_len < 7) + || (session-> + scpRecv_response[session->scpRecv_response_len - 1] != + '\n')) { + if (session->scpRecv_response_len == + LIBSSH2_SCP_RESPONSE_BUFLEN) { + /* You had your chance */ + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Unterminated response from SCP server"); + goto scp_recv_error; + } + /* Way too short to be an SCP response, or not done yet, + short circuit */ + continue; + } + + /* We're guaranteed not to go under response_len == 0 by the + logic above */ + while ((session-> + scpRecv_response[session->scpRecv_response_len - 1] == + '\r') + || (session-> + scpRecv_response[session->scpRecv_response_len - + 1] == '\n')) { + session->scpRecv_response_len--; + } + session->scpRecv_response[session->scpRecv_response_len] = + '\0'; + + if (session->scpRecv_response_len < 6) { + /* EOL came too soon */ + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid response from SCP server, too short"); + goto scp_recv_error; + } + + s = (char *) session->scpRecv_response + 1; + + p = strchr(s, ' '); + if (!p || ((p - s) <= 0)) { + /* No spaces or space in the wrong spot */ + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid response from SCP server, malformed mode"); + goto scp_recv_error; + } + + *(p++) = '\0'; + /* Make sure we don't get fooled by leftover values */ + + session->scpRecv_mode = strtol(s, &e, 8); + if (e && *e) { + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid response from SCP server, invalid mode"); + goto scp_recv_error; + } + + s = strchr(p, ' '); + if (!s || ((s - p) <= 0)) { + /* No spaces or space in the wrong spot */ + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid response from SCP server, too short or malformed"); + goto scp_recv_error; + } + + *s = '\0'; + /* Make sure we don't get fooled by leftover values */ + session->scpRecv_size = scpsize_strtol(p, &e, 10); + if (e && *e) { + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid response from SCP server, invalid size"); + goto scp_recv_error; + } + + /* SCP ACK */ + session->scpRecv_response[0] = '\0'; + + session->scpRecv_state = libssh2_NB_state_sent6; + } + + if (session->scpRecv_state == libssh2_NB_state_sent6) { + rc = _libssh2_channel_write(session->scpRecv_channel, 0, + session->scpRecv_response, 1); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block sending SCP ACK"); + return NULL; + } else if (rc != 1) { + goto scp_recv_error; + } + _libssh2_debug(session, LIBSSH2_TRACE_SCP, + "mode = 0%lo size = %ld", session->scpRecv_mode, + session->scpRecv_size); + + /* We *should* check that basename is valid, but why let that + stop us? */ + break; + } + } + + session->scpRecv_state = libssh2_NB_state_sent7; + } + + if (sb) { + memset(sb, 0, sizeof(struct stat)); + + sb->st_mtime = session->scpRecv_mtime; + sb->st_atime = session->scpRecv_atime; + sb->st_size = session->scpRecv_size; + sb->st_mode = session->scpRecv_mode; + } + + session->scpRecv_state = libssh2_NB_state_idle; + return session->scpRecv_channel; + + scp_recv_empty_channel: + /* the code only jumps here as a result of a zero read from channel_read() + so we check EOF status to avoid getting stuck in a loop */ + if(libssh2_channel_eof(session->scpRecv_channel)) + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Unexpected channel close"); + else + return session->scpRecv_channel; + /* fall-through */ + scp_recv_error: + tmp_err_code = session->err_code; + tmp_err_msg = session->err_msg; + while (libssh2_channel_free(session->scpRecv_channel) == + LIBSSH2_ERROR_EAGAIN); + session->err_code = tmp_err_code; + session->err_msg = tmp_err_msg; + session->scpRecv_channel = NULL; + session->scpRecv_state = libssh2_NB_state_idle; + return NULL; +} + +/* + * libssh2_scp_recv + * + * Open a channel and request a remote file via SCP + * + */ +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_scp_recv(LIBSSH2_SESSION *session, const char *path, struct stat * sb) +{ + LIBSSH2_CHANNEL *ptr; + BLOCK_ADJUST_ERRNO(ptr, session, scp_recv(session, path, sb)); + return ptr; +} + +/* + * scp_send() + * + * Send a file using SCP + * + */ +static LIBSSH2_CHANNEL * +scp_send(LIBSSH2_SESSION * session, const char *path, int mode, + libssh2_int64_t size, time_t mtime, time_t atime) +{ + int cmd_len; + int rc; + int tmp_err_code; + const char *tmp_err_msg; + + if (session->scpSend_state == libssh2_NB_state_idle) { + session->scpSend_command_len = + _libssh2_shell_quotedsize(path) + sizeof("scp -t ") + + ((mtime || atime)?1:0); + + session->scpSend_command = + LIBSSH2_ALLOC(session, session->scpSend_command_len); + if (!session->scpSend_command) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate a command buffer for scp session"); + return NULL; + } + + snprintf((char *)session->scpSend_command, session->scpSend_command_len, + "scp -%st ", (mtime || atime)?"p":""); + + cmd_len = strlen((char *)session->scpSend_command); + + (void)shell_quotearg(path, + &session->scpSend_command[cmd_len], + session->scpSend_command_len - cmd_len); + + session->scpSend_command[session->scpSend_command_len - 1] = '\0'; + + _libssh2_debug(session, LIBSSH2_TRACE_SCP, + "Opening channel for SCP send"); + /* Allocate a channel */ + + session->scpSend_state = libssh2_NB_state_created; + } + + if (session->scpSend_state == libssh2_NB_state_created) { + session->scpSend_channel = + _libssh2_channel_open(session, "session", sizeof("session") - 1, + LIBSSH2_CHANNEL_WINDOW_DEFAULT, + LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0); + if (!session->scpSend_channel) { + if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) { + /* previous call set libssh2_session_last_error(), pass it + through */ + LIBSSH2_FREE(session, session->scpSend_command); + session->scpSend_command = NULL; + session->scpSend_state = libssh2_NB_state_idle; + } + else { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block starting up channel"); + } + return NULL; + } + + session->scpSend_state = libssh2_NB_state_sent; + } + + if (session->scpSend_state == libssh2_NB_state_sent) { + /* Request SCP for the desired file */ + rc = _libssh2_channel_process_startup(session->scpSend_channel, "exec", + sizeof("exec") - 1, + (char *) session->scpSend_command, + session->scpSend_command_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block requesting SCP startup"); + return NULL; + } + else if (rc) { + /* previous call set libssh2_session_last_error(), pass it + through */ + LIBSSH2_FREE(session, session->scpSend_command); + session->scpSend_command = NULL; + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Unknown error while getting error string"); + goto scp_send_error; + } + LIBSSH2_FREE(session, session->scpSend_command); + session->scpSend_command = NULL; + + session->scpSend_state = libssh2_NB_state_sent1; + } + + if (session->scpSend_state == libssh2_NB_state_sent1) { + /* Wait for ACK */ + rc = _libssh2_channel_read(session->scpSend_channel, 0, + (char *) session->scpSend_response, 1); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block waiting for response from remote"); + return NULL; + } + else if (rc < 0) { + _libssh2_error(session, rc, "SCP failure"); + goto scp_send_error; + } + else if(!rc) + /* remain in the same state */ + goto scp_send_empty_channel; + else if (session->scpSend_response[0] != 0) { + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid ACK response from remote"); + goto scp_send_error; + } + if (mtime || atime) { + /* Send mtime and atime to be used for file */ + session->scpSend_response_len = + snprintf((char *) session->scpSend_response, + LIBSSH2_SCP_RESPONSE_BUFLEN, "T%ld 0 %ld 0\n", + (long)mtime, (long)atime); + _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s", + session->scpSend_response); + } + + session->scpSend_state = libssh2_NB_state_sent2; + } + + /* Send mtime and atime to be used for file */ + if (mtime || atime) { + if (session->scpSend_state == libssh2_NB_state_sent2) { + rc = _libssh2_channel_write(session->scpSend_channel, 0, + session->scpSend_response, + session->scpSend_response_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block sending time data for SCP file"); + return NULL; + } else if (rc != (int)session->scpSend_response_len) { + _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send time data for SCP file"); + goto scp_send_error; + } + + session->scpSend_state = libssh2_NB_state_sent3; + } + + if (session->scpSend_state == libssh2_NB_state_sent3) { + /* Wait for ACK */ + rc = _libssh2_channel_read(session->scpSend_channel, 0, + (char *) session->scpSend_response, 1); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block waiting for response"); + return NULL; + } + else if (rc < 0) { + _libssh2_error(session, rc, "SCP failure"); + goto scp_send_error; + } + else if(!rc) + /* remain in the same state */ + goto scp_send_empty_channel; + else if (session->scpSend_response[0] != 0) { + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid SCP ACK response"); + goto scp_send_error; + } + + session->scpSend_state = libssh2_NB_state_sent4; + } + } else { + if (session->scpSend_state == libssh2_NB_state_sent2) { + session->scpSend_state = libssh2_NB_state_sent4; + } + } + + if (session->scpSend_state == libssh2_NB_state_sent4) { + /* Send mode, size, and basename */ + const char *base = strrchr(path, '/'); + if (base) + base++; + else + base = path; + + session->scpSend_response_len = + snprintf((char *) session->scpSend_response, + LIBSSH2_SCP_RESPONSE_BUFLEN, "C0%o %" + LIBSSH2_INT64_T_FORMAT "u %s\n", mode, + size, base); + _libssh2_debug(session, LIBSSH2_TRACE_SCP, "Sent %s", + session->scpSend_response); + + session->scpSend_state = libssh2_NB_state_sent5; + } + + if (session->scpSend_state == libssh2_NB_state_sent5) { + rc = _libssh2_channel_write(session->scpSend_channel, 0, + session->scpSend_response, + session->scpSend_response_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block send core file data for SCP file"); + return NULL; + } else if (rc != (int)session->scpSend_response_len) { + _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send core file data for SCP file"); + goto scp_send_error; + } + + session->scpSend_state = libssh2_NB_state_sent6; + } + + if (session->scpSend_state == libssh2_NB_state_sent6) { + /* Wait for ACK */ + rc = _libssh2_channel_read(session->scpSend_channel, 0, + (char *) session->scpSend_response, 1); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block waiting for response"); + return NULL; + } + else if (rc < 0) { + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Invalid ACK response from remote"); + goto scp_send_error; + } + else if (rc == 0) + goto scp_send_empty_channel; + + else if (session->scpSend_response[0] != 0) { + size_t err_len; + char *err_msg; + + err_len = + _libssh2_channel_packet_data_len(session->scpSend_channel, 0); + err_msg = LIBSSH2_ALLOC(session, err_len + 1); + if (!err_msg) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "failed to get memory"); + goto scp_send_error; + } + + /* Read the remote error message */ + rc = _libssh2_channel_read(session->scpSend_channel, 0, + err_msg, err_len); + if (rc > 0) { + err_msg[err_len]=0; + _libssh2_debug(session, LIBSSH2_TRACE_SCP, + "got %02x %s", session->scpSend_response[0], + err_msg); + } + LIBSSH2_FREE(session, err_msg); + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "failed to send file"); + goto scp_send_error; + } + } + + session->scpSend_state = libssh2_NB_state_idle; + return session->scpSend_channel; + + scp_send_empty_channel: + /* the code only jumps here as a result of a zero read from channel_read() + so we check EOF status to avoid getting stuck in a loop */ + if(libssh2_channel_eof(session->scpSend_channel)) { + _libssh2_error(session, LIBSSH2_ERROR_SCP_PROTOCOL, + "Unexpected channel close"); + } + else + return session->scpSend_channel; + /* fall-through */ + scp_send_error: + tmp_err_code = session->err_code; + tmp_err_msg = session->err_msg; + while (libssh2_channel_free(session->scpSend_channel) == + LIBSSH2_ERROR_EAGAIN); + session->err_code = tmp_err_code; + session->err_msg = tmp_err_msg; + session->scpSend_channel = NULL; + session->scpSend_state = libssh2_NB_state_idle; + return NULL; +} + +/* + * libssh2_scp_send_ex + * + * Send a file using SCP. Old API. + */ +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_scp_send_ex(LIBSSH2_SESSION *session, const char *path, int mode, + size_t size, long mtime, long atime) +{ + LIBSSH2_CHANNEL *ptr; + BLOCK_ADJUST_ERRNO(ptr, session, + scp_send(session, path, mode, size, + (time_t)mtime, (time_t)atime)); + return ptr; +} + +/* + * libssh2_scp_send64 + * + * Send a file using SCP + */ +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_scp_send64(LIBSSH2_SESSION *session, const char *path, int mode, + libssh2_int64_t size, time_t mtime, time_t atime) +{ + LIBSSH2_CHANNEL *ptr; + BLOCK_ADJUST_ERRNO(ptr, session, + scp_send(session, path, mode, size, mtime, atime)); + return ptr; +} diff --git a/vendor/libssh2-1.4.2/src/session.c b/vendor/libssh2-1.4.2/src/session.c new file mode 100644 index 0000000..77ab9bc --- /dev/null +++ b/vendor/libssh2-1.4.2/src/session.c @@ -0,0 +1,1751 @@ +/* Copyright (c) 2004-2007 Sara Golemon + * Copyright (c) 2009-2011 by Daniel Stenberg + * Copyright (c) 2010 Simon Josefsson + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include +#include + +#ifdef HAVE_GETTIMEOFDAY +#include +#endif +#ifdef HAVE_ALLOCA_H +#include +#endif + +#include "transport.h" +#include "session.h" +#include "channel.h" +#include "mac.h" +#include "misc.h" + +/* libssh2_default_alloc + */ +static +LIBSSH2_ALLOC_FUNC(libssh2_default_alloc) +{ + (void) abstract; + return malloc(count); +} + +/* libssh2_default_free + */ +static +LIBSSH2_FREE_FUNC(libssh2_default_free) +{ + (void) abstract; + free(ptr); +} + +/* libssh2_default_realloc + */ +static +LIBSSH2_REALLOC_FUNC(libssh2_default_realloc) +{ + (void) abstract; + return realloc(ptr, count); +} + +/* + * banner_receive + * + * Wait for a hello from the remote host + * Allocate a buffer and store the banner in session->remote.banner + * Returns: 0 on success, LIBSSH2_ERROR_EAGAIN if read would block, negative + * on failure + */ +static int +banner_receive(LIBSSH2_SESSION * session) +{ + int ret; + int banner_len; + + if (session->banner_TxRx_state == libssh2_NB_state_idle) { + banner_len = 0; + + session->banner_TxRx_state = libssh2_NB_state_created; + } else { + banner_len = session->banner_TxRx_total_send; + } + + while ((banner_len < (int) sizeof(session->banner_TxRx_banner)) && + ((banner_len == 0) + || (session->banner_TxRx_banner[banner_len - 1] != '\n'))) { + char c = '\0'; + + /* no incoming block yet! */ + session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND; + + ret = LIBSSH2_RECV(session, &c, 1, + LIBSSH2_SOCKET_RECV_FLAGS(session)); + if (ret < 0) { + if(session->api_block_mode || (ret != -EAGAIN)) + /* ignore EAGAIN when non-blocking */ + _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + "Error recving %d bytes: %d", 1, -ret); + } + else + _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + "Recved %d bytes banner", ret); + + if (ret < 0) { + if (ret == -EAGAIN) { + session->socket_block_directions = + LIBSSH2_SESSION_BLOCK_INBOUND; + session->banner_TxRx_total_send = banner_len; + return LIBSSH2_ERROR_EAGAIN; + } + + /* Some kinda error */ + session->banner_TxRx_state = libssh2_NB_state_idle; + session->banner_TxRx_total_send = 0; + return LIBSSH2_ERROR_SOCKET_RECV; + } + + if (ret == 0) { + session->socket_state = LIBSSH2_SOCKET_DISCONNECTED; + return LIBSSH2_ERROR_SOCKET_DISCONNECT; + } + + if (c == '\0') { + /* NULLs are not allowed in SSH banners */ + session->banner_TxRx_state = libssh2_NB_state_idle; + session->banner_TxRx_total_send = 0; + return LIBSSH2_ERROR_BANNER_RECV; + } + + session->banner_TxRx_banner[banner_len++] = c; + } + + while (banner_len && + ((session->banner_TxRx_banner[banner_len - 1] == '\n') || + (session->banner_TxRx_banner[banner_len - 1] == '\r'))) { + banner_len--; + } + + /* From this point on, we are done here */ + session->banner_TxRx_state = libssh2_NB_state_idle; + session->banner_TxRx_total_send = 0; + + if (!banner_len) + return LIBSSH2_ERROR_BANNER_RECV; + + session->remote.banner = LIBSSH2_ALLOC(session, banner_len + 1); + if (!session->remote.banner) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Error allocating space for remote banner"); + } + memcpy(session->remote.banner, session->banner_TxRx_banner, banner_len); + session->remote.banner[banner_len] = '\0'; + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Received Banner: %s", + session->remote.banner); + return LIBSSH2_ERROR_NONE; +} + +/* + * banner_send + * + * Send the default banner, or the one set via libssh2_setopt_string + * + * Returns LIBSSH2_ERROR_EAGAIN if it would block - and if it does so, you + * should call this function again as soon as it is likely that more data can + * be sent, and this function should then be called with the same argument set + * (same data pointer and same data_len) until zero or failure is returned. + */ +static int +banner_send(LIBSSH2_SESSION * session) +{ + char *banner = (char *) LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF; + int banner_len = sizeof(LIBSSH2_SSH_DEFAULT_BANNER_WITH_CRLF) - 1; + ssize_t ret; +#ifdef LIBSSH2DEBUG + char banner_dup[256]; +#endif + + if (session->banner_TxRx_state == libssh2_NB_state_idle) { + if (session->local.banner) { + /* setopt_string will have given us our \r\n characters */ + banner_len = strlen((char *) session->local.banner); + banner = (char *) session->local.banner; + } +#ifdef LIBSSH2DEBUG + /* Hack and slash to avoid sending CRLF in debug output */ + if (banner_len < 256) { + memcpy(banner_dup, banner, banner_len - 2); + banner_dup[banner_len - 2] = '\0'; + } else { + memcpy(banner_dup, banner, 255); + banner[255] = '\0'; + } + + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Sending Banner: %s", + banner_dup); +#endif + + session->banner_TxRx_state = libssh2_NB_state_created; + } + + /* no outgoing block yet! */ + session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND; + + ret = LIBSSH2_SEND(session, + banner + session->banner_TxRx_total_send, + banner_len - session->banner_TxRx_total_send, + LIBSSH2_SOCKET_SEND_FLAGS(session)); + if (ret < 0) + _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + "Error sending %d bytes: %d", + banner_len - session->banner_TxRx_total_send, -ret); + else + _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + "Sent %d/%d bytes at %p+%d", ret, + banner_len - session->banner_TxRx_total_send, + banner, session->banner_TxRx_total_send); + + if (ret != (banner_len - session->banner_TxRx_total_send)) { + if (ret >= 0 || ret == -EAGAIN) { + /* the whole packet could not be sent, save the what was */ + session->socket_block_directions = + LIBSSH2_SESSION_BLOCK_OUTBOUND; + if (ret > 0) + session->banner_TxRx_total_send += ret; + return LIBSSH2_ERROR_EAGAIN; + } + session->banner_TxRx_state = libssh2_NB_state_idle; + session->banner_TxRx_total_send = 0; + return LIBSSH2_ERROR_SOCKET_RECV; + } + + /* Set the state back to idle */ + session->banner_TxRx_state = libssh2_NB_state_idle; + session->banner_TxRx_total_send = 0; + + return 0; +} + +/* + * session_nonblock() sets the given socket to either blocking or + * non-blocking mode based on the 'nonblock' boolean argument. This function + * is copied from the libcurl sources with permission. + */ +static int +session_nonblock(libssh2_socket_t sockfd, /* operate on this */ + int nonblock /* TRUE or FALSE */ ) +{ +#undef SETBLOCK +#define SETBLOCK 0 +#ifdef HAVE_O_NONBLOCK + /* most recent unix versions */ + int flags; + + flags = fcntl(sockfd, F_GETFL, 0); + if (nonblock) + return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); + else + return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); +#undef SETBLOCK +#define SETBLOCK 1 +#endif + +#if defined(HAVE_FIONBIO) && (SETBLOCK == 0) + /* older unix versions and VMS*/ + int flags; + + flags = nonblock; + return ioctl(sockfd, FIONBIO, &flags); +#undef SETBLOCK +#define SETBLOCK 2 +#endif + +#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0) + /* Windows? */ + unsigned long flags; + flags = nonblock; + + return ioctlsocket(sockfd, FIONBIO, &flags); +#undef SETBLOCK +#define SETBLOCK 3 +#endif + +#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0) + /* presumably for Amiga */ + return IoctlSocket(sockfd, FIONBIO, (long) nonblock); +#undef SETBLOCK +#define SETBLOCK 4 +#endif + +#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0) + /* BeOS */ + long b = nonblock ? 1 : 0; + return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); +#undef SETBLOCK +#define SETBLOCK 5 +#endif + +#ifdef HAVE_DISABLED_NONBLOCKING + return 0; /* returns success */ +#undef SETBLOCK +#define SETBLOCK 6 +#endif + +#if (SETBLOCK == 0) +#error "no non-blocking method was found/used/set" +#endif +} + +/* + * get_socket_nonblocking() + * + * gets the given blocking or non-blocking state of the socket. + */ +static int +get_socket_nonblocking(int sockfd) +{ /* operate on this */ +#undef GETBLOCK +#define GETBLOCK 0 +#ifdef HAVE_O_NONBLOCK + /* most recent unix versions */ + int flags; + + if ((flags = fcntl(sockfd, F_GETFL, 0)) == -1) { + /* Assume blocking on error */ + return 1; + } + return (flags & O_NONBLOCK); +#undef GETBLOCK +#define GETBLOCK 1 +#endif + +#if defined(WSAEWOULDBLOCK) && (GETBLOCK == 0) + /* Windows? */ + unsigned int option_value; + socklen_t option_len = sizeof(option_value); + + if (getsockopt + (sockfd, SOL_SOCKET, SO_ERROR, (void *) &option_value, &option_len)) { + /* Assume blocking on error */ + return 1; + } + return (int) option_value; +#undef GETBLOCK +#define GETBLOCK 2 +#endif + +#if defined(HAVE_SO_NONBLOCK) && (GETBLOCK == 0) + /* BeOS */ + long b; + if (getsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b))) { + /* Assume blocking on error */ + return 1; + } + return (int) b; +#undef GETBLOCK +#define GETBLOCK 5 +#endif + +#if defined(SO_STATE) && defined( __VMS ) && (GETBLOCK == 0) + + /* VMS TCP/IP Services */ + + size_t sockstat = 0; + int callstat = 0; + size_t size = sizeof( int ); + + callstat = getsockopt(sockfd, SOL_SOCKET, SO_STATE, + (char *)&sockstat, &size); + if ( callstat == -1 ) return(0); + if ( (sockstat&SS_NBIO) )return(1); + return(0); + +#undef GETBLOCK +#define GETBLOCK 6 +#endif + +#ifdef HAVE_DISABLED_NONBLOCKING + return 1; /* returns blocking */ +#undef GETBLOCK +#define GETBLOCK 7 +#endif + +#if (GETBLOCK == 0) +#error "no non-blocking method was found/used/get" +#endif +} + +/* libssh2_session_banner_set + * Set the local banner to use in the server handshake. + */ +LIBSSH2_API int +libssh2_session_banner_set(LIBSSH2_SESSION * session, const char *banner) +{ + size_t banner_len = banner ? strlen(banner) : 0; + + if (session->local.banner) { + LIBSSH2_FREE(session, session->local.banner); + session->local.banner = NULL; + } + + if (!banner_len) + return 0; + + session->local.banner = LIBSSH2_ALLOC(session, banner_len + 3); + if (!session->local.banner) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for local banner"); + } + + memcpy(session->local.banner, banner, banner_len); + + /* first zero terminate like this so that the debug output is nice */ + session->local.banner[banner_len] = '\0'; + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Setting local Banner: %s", + session->local.banner); + session->local.banner[banner_len++] = '\r'; + session->local.banner[banner_len++] = '\n'; + session->local.banner[banner_len] = '\0'; + + return 0; +} + +/* libssh2_banner_set + * Set the local banner. DEPRECATED VERSION + */ +LIBSSH2_API int +libssh2_banner_set(LIBSSH2_SESSION * session, const char *banner) +{ + return libssh2_session_banner_set(session, banner); +} + +/* + * libssh2_session_init_ex + * + * Allocate and initialize a libssh2 session structure. Allows for malloc + * callbacks in case the calling program has its own memory manager It's + * allowable (but unadvisable) to define some but not all of the malloc + * callbacks An additional pointer value may be optionally passed to be sent + * to the callbacks (so they know who's asking) + */ +LIBSSH2_API LIBSSH2_SESSION * +libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), + LIBSSH2_FREE_FUNC((*my_free)), + LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract) +{ + LIBSSH2_ALLOC_FUNC((*local_alloc)) = libssh2_default_alloc; + LIBSSH2_FREE_FUNC((*local_free)) = libssh2_default_free; + LIBSSH2_REALLOC_FUNC((*local_realloc)) = libssh2_default_realloc; + LIBSSH2_SESSION *session; + + if (my_alloc) { + local_alloc = my_alloc; + } + if (my_free) { + local_free = my_free; + } + if (my_realloc) { + local_realloc = my_realloc; + } + + session = local_alloc(sizeof(LIBSSH2_SESSION), &abstract); + if (session) { + memset(session, 0, sizeof(LIBSSH2_SESSION)); + session->alloc = local_alloc; + session->free = local_free; + session->realloc = local_realloc; + session->send = _libssh2_send; + session->recv = _libssh2_recv; + session->abstract = abstract; + session->api_timeout = 0; /* timeout-free API by default */ + session->api_block_mode = 1; /* blocking API by default */ + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "New session resource allocated"); + _libssh2_init_if_needed (); + } + return session; +} + +/* + * libssh2_session_callback_set + * + * Set (or reset) a callback function + * Returns the prior address + * + * FIXME: this function relies on that we can typecast function pointers + * to void pointers, which isn't allowed in ISO C! + */ +LIBSSH2_API void * +libssh2_session_callback_set(LIBSSH2_SESSION * session, + int cbtype, void *callback) +{ + void *oldcb; + + switch (cbtype) { + case LIBSSH2_CALLBACK_IGNORE: + oldcb = session->ssh_msg_ignore; + session->ssh_msg_ignore = callback; + return oldcb; + + case LIBSSH2_CALLBACK_DEBUG: + oldcb = session->ssh_msg_debug; + session->ssh_msg_debug = callback; + return oldcb; + + case LIBSSH2_CALLBACK_DISCONNECT: + oldcb = session->ssh_msg_disconnect; + session->ssh_msg_disconnect = callback; + return oldcb; + + case LIBSSH2_CALLBACK_MACERROR: + oldcb = session->macerror; + session->macerror = callback; + return oldcb; + + case LIBSSH2_CALLBACK_X11: + oldcb = session->x11; + session->x11 = callback; + return oldcb; + + case LIBSSH2_CALLBACK_SEND: + oldcb = session->send; + session->send = callback; + return oldcb; + + case LIBSSH2_CALLBACK_RECV: + oldcb = session->recv; + session->recv = callback; + return oldcb; + } + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Setting Callback %d", cbtype); + + return NULL; +} + +/* + * _libssh2_wait_socket() + * + * Utility function that waits for action on the socket. Returns 0 when ready + * to run again or error on timeout. + */ +int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) +{ + int rc; + int seconds_to_next; + int dir; + int has_timeout; + long ms_to_next = 0; + long elapsed_ms; + + /* since libssh2 often sets EAGAIN internally before this function is + called, we can decrease some amount of confusion in user programs by + resetting the error code in this function to reduce the risk of EAGAIN + being stored as error when a blocking function has returned */ + session->err_code = LIBSSH2_ERROR_NONE; + + rc = libssh2_keepalive_send (session, &seconds_to_next); + if (rc < 0) + return rc; + + ms_to_next = seconds_to_next * 1000; + + /* figure out what to wait for */ + dir = libssh2_session_block_directions(session); + + if(!dir) { + _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + "Nothing to wait for in wait_socket"); + /* To avoid that we hang below just because there's nothing set to + wait for, we timeout on 1 second to also avoid busy-looping + during this condition */ + ms_to_next = 1000; + } + + if (session->api_timeout > 0 && + (seconds_to_next == 0 || + seconds_to_next > session->api_timeout)) { + time_t now = time (NULL); + elapsed_ms = (long)(1000*difftime(start_time, now)); + if (elapsed_ms > session->api_timeout) { + session->err_code = LIBSSH2_ERROR_TIMEOUT; + return LIBSSH2_ERROR_TIMEOUT; + } + ms_to_next = (session->api_timeout - elapsed_ms); + has_timeout = 1; + } + else if (ms_to_next > 0) { + has_timeout = 1; + } + else + has_timeout = 0; + +#ifdef HAVE_POLL + { + struct pollfd sockets[1]; + + sockets[0].fd = session->socket_fd; + sockets[0].events = 0; + sockets[0].revents = 0; + + if(dir & LIBSSH2_SESSION_BLOCK_INBOUND) + sockets[0].events |= POLLIN; + + if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) + sockets[0].events |= POLLOUT; + + rc = poll(sockets, 1, has_timeout?ms_to_next: -1); + } +#else + { + fd_set rfd; + fd_set wfd; + fd_set *writefd = NULL; + fd_set *readfd = NULL; + struct timeval tv; + + tv.tv_sec = ms_to_next / 1000; + tv.tv_usec = (ms_to_next - tv.tv_sec*1000) * 1000; + + if(dir & LIBSSH2_SESSION_BLOCK_INBOUND) { + FD_ZERO(&rfd); + FD_SET(session->socket_fd, &rfd); + readfd = &rfd; + } + + if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) { + FD_ZERO(&wfd); + FD_SET(session->socket_fd, &wfd); + writefd = &wfd; + } + + rc = select(session->socket_fd + 1, readfd, writefd, NULL, + has_timeout ? &tv : NULL); + } +#endif + if(rc <= 0) { + /* timeout (or error), bail out with a timeout error */ + session->err_code = LIBSSH2_ERROR_TIMEOUT; + return LIBSSH2_ERROR_TIMEOUT; + } + + return 0; /* ready to try again */ +} + +static int +session_startup(LIBSSH2_SESSION *session, libssh2_socket_t sock) +{ + int rc; + + if (session->startup_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "session_startup for socket %d", sock); + if (LIBSSH2_INVALID_SOCKET == sock) { + /* Did we forget something? */ + return _libssh2_error(session, LIBSSH2_ERROR_BAD_SOCKET, + "Bad socket provided"); + } + session->socket_fd = sock; + + session->socket_prev_blockstate = + !get_socket_nonblocking(session->socket_fd); + + if (session->socket_prev_blockstate) { + /* If in blocking state chang to non-blocking */ + session_nonblock(session->socket_fd, 1); + } + + session->startup_state = libssh2_NB_state_created; + } + + if (session->startup_state == libssh2_NB_state_created) { + rc = banner_send(session); + if (rc) { + return _libssh2_error(session, rc, + "Failed sending banner"); + } + session->startup_state = libssh2_NB_state_sent; + session->banner_TxRx_state = libssh2_NB_state_idle; + } + + if (session->startup_state == libssh2_NB_state_sent) { + do { + rc = banner_receive(session); + if (rc) + return _libssh2_error(session, rc, + "Failed getting banner"); + } while(strncmp("SSH-", (char *)session->remote.banner, 4)); + + session->startup_state = libssh2_NB_state_sent1; + } + + if (session->startup_state == libssh2_NB_state_sent1) { + rc = _libssh2_kex_exchange(session, 0, &session->startup_key_state); + if (rc) + return _libssh2_error(session, rc, + "Unable to exchange encryption keys"); + + session->startup_state = libssh2_NB_state_sent2; + } + + if (session->startup_state == libssh2_NB_state_sent2) { + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "Requesting userauth service"); + + /* Request the userauth service */ + session->startup_service[0] = SSH_MSG_SERVICE_REQUEST; + _libssh2_htonu32(session->startup_service + 1, + sizeof("ssh-userauth") - 1); + memcpy(session->startup_service + 5, "ssh-userauth", + sizeof("ssh-userauth") - 1); + + session->startup_state = libssh2_NB_state_sent3; + } + + if (session->startup_state == libssh2_NB_state_sent3) { + rc = _libssh2_transport_send(session, session->startup_service, + sizeof("ssh-userauth") + 5 - 1, + NULL, 0); + if (rc) { + return _libssh2_error(session, rc, + "Unable to ask for ssh-userauth service"); + } + + session->startup_state = libssh2_NB_state_sent4; + } + + if (session->startup_state == libssh2_NB_state_sent4) { + rc = _libssh2_packet_require(session, SSH_MSG_SERVICE_ACCEPT, + &session->startup_data, + &session->startup_data_len, 0, NULL, 0, + &session->startup_req_state); + if (rc) + return rc; + + session->startup_service_length = + _libssh2_ntohu32(session->startup_data + 1); + + if ((session->startup_service_length != (sizeof("ssh-userauth") - 1)) + || strncmp("ssh-userauth", (char *) session->startup_data + 5, + session->startup_service_length)) { + LIBSSH2_FREE(session, session->startup_data); + session->startup_data = NULL; + return _libssh2_error(session, LIBSSH2_ERROR_PROTO, + "Invalid response received from server"); + } + LIBSSH2_FREE(session, session->startup_data); + session->startup_data = NULL; + + session->startup_state = libssh2_NB_state_idle; + + return 0; + } + + /* just for safety return some error */ + return LIBSSH2_ERROR_INVAL; +} + +/* + * libssh2_session_handshake() + * + * session: LIBSSH2_SESSION struct allocated and owned by the calling program + * sock: *must* be populated with an opened and connected socket. + * + * Returns: 0 on success, or non-zero on failure + */ +LIBSSH2_API int +libssh2_session_handshake(LIBSSH2_SESSION *session, libssh2_socket_t sock) +{ + int rc; + + BLOCK_ADJUST(rc, session, session_startup(session, sock) ); + + return rc; +} + +/* + * libssh2_session_startup() + * + * DEPRECATED. Use libssh2_session_handshake() instead! This function is not + * portable enough. + * + * session: LIBSSH2_SESSION struct allocated and owned by the calling program + * sock: *must* be populated with an opened and connected socket. + * + * Returns: 0 on success, or non-zero on failure + */ +LIBSSH2_API int +libssh2_session_startup(LIBSSH2_SESSION *session, int sock) +{ + return libssh2_session_handshake(session, (libssh2_socket_t) sock); +} + +/* + * libssh2_session_free + * + * Frees the memory allocated to the session + * Also closes and frees any channels attached to this session + */ +static int +session_free(LIBSSH2_SESSION *session) +{ + int rc; + LIBSSH2_PACKET *pkg; + LIBSSH2_CHANNEL *ch; + LIBSSH2_LISTENER *l; + int packets_left = 0; + + if (session->free_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Freeing session resource", + session->remote.banner); + + session->state = libssh2_NB_state_created; + } + + if (session->free_state == libssh2_NB_state_created) { + while ((ch = _libssh2_list_first(&session->channels))) { + + rc = _libssh2_channel_free(ch); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + } + + session->state = libssh2_NB_state_sent; + } + + if (session->state == libssh2_NB_state_sent) { + while ((l = _libssh2_list_first(&session->listeners))) { + rc = _libssh2_channel_forward_cancel(l); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + } + + session->state = libssh2_NB_state_sent1; + } + + if (session->state & LIBSSH2_STATE_NEWKEYS) { + /* hostkey */ + if (session->hostkey && session->hostkey->dtor) { + session->hostkey->dtor(session, &session->server_hostkey_abstract); + } + + /* Client to Server */ + /* crypt */ + if (session->local.crypt && session->local.crypt->dtor) { + session->local.crypt->dtor(session, + &session->local.crypt_abstract); + } + /* comp */ + if (session->local.comp && session->local.comp->dtor) { + session->local.comp->dtor(session, 1, + &session->local.comp_abstract); + } + /* mac */ + if (session->local.mac && session->local.mac->dtor) { + session->local.mac->dtor(session, &session->local.mac_abstract); + } + + /* Server to Client */ + /* crypt */ + if (session->remote.crypt && session->remote.crypt->dtor) { + session->remote.crypt->dtor(session, + &session->remote.crypt_abstract); + } + /* comp */ + if (session->remote.comp && session->remote.comp->dtor) { + session->remote.comp->dtor(session, 0, + &session->remote.comp_abstract); + } + /* mac */ + if (session->remote.mac && session->remote.mac->dtor) { + session->remote.mac->dtor(session, &session->remote.mac_abstract); + } + + /* session_id */ + if (session->session_id) { + LIBSSH2_FREE(session, session->session_id); + } + } + + /* Free banner(s) */ + if (session->remote.banner) { + LIBSSH2_FREE(session, session->remote.banner); + } + if (session->local.banner) { + LIBSSH2_FREE(session, session->local.banner); + } + + /* Free preference(s) */ + if (session->kex_prefs) { + LIBSSH2_FREE(session, session->kex_prefs); + } + if (session->hostkey_prefs) { + LIBSSH2_FREE(session, session->hostkey_prefs); + } + + if (session->local.kexinit) { + LIBSSH2_FREE(session, session->local.kexinit); + } + if (session->local.crypt_prefs) { + LIBSSH2_FREE(session, session->local.crypt_prefs); + } + if (session->local.mac_prefs) { + LIBSSH2_FREE(session, session->local.mac_prefs); + } + if (session->local.comp_prefs) { + LIBSSH2_FREE(session, session->local.comp_prefs); + } + if (session->local.lang_prefs) { + LIBSSH2_FREE(session, session->local.lang_prefs); + } + + if (session->remote.kexinit) { + LIBSSH2_FREE(session, session->remote.kexinit); + } + if (session->remote.crypt_prefs) { + LIBSSH2_FREE(session, session->remote.crypt_prefs); + } + if (session->remote.mac_prefs) { + LIBSSH2_FREE(session, session->remote.mac_prefs); + } + if (session->remote.comp_prefs) { + LIBSSH2_FREE(session, session->remote.comp_prefs); + } + if (session->remote.lang_prefs) { + LIBSSH2_FREE(session, session->remote.lang_prefs); + } + + /* + * Make sure all memory used in the state variables are free + */ + if (session->kexinit_data) { + LIBSSH2_FREE(session, session->kexinit_data); + } + if (session->startup_data) { + LIBSSH2_FREE(session, session->startup_data); + } + if (session->userauth_list_data) { + LIBSSH2_FREE(session, session->userauth_list_data); + } + if (session->userauth_pswd_data) { + LIBSSH2_FREE(session, session->userauth_pswd_data); + } + if (session->userauth_pswd_newpw) { + LIBSSH2_FREE(session, session->userauth_pswd_newpw); + } + if (session->userauth_host_packet) { + LIBSSH2_FREE(session, session->userauth_host_packet); + } + if (session->userauth_host_method) { + LIBSSH2_FREE(session, session->userauth_host_method); + } + if (session->userauth_host_data) { + LIBSSH2_FREE(session, session->userauth_host_data); + } + if (session->userauth_pblc_data) { + LIBSSH2_FREE(session, session->userauth_pblc_data); + } + if (session->userauth_pblc_packet) { + LIBSSH2_FREE(session, session->userauth_pblc_packet); + } + if (session->userauth_pblc_method) { + LIBSSH2_FREE(session, session->userauth_pblc_method); + } + if (session->userauth_kybd_data) { + LIBSSH2_FREE(session, session->userauth_kybd_data); + } + if (session->userauth_kybd_packet) { + LIBSSH2_FREE(session, session->userauth_kybd_packet); + } + if (session->userauth_kybd_auth_instruction) { + LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction); + } + if (session->open_packet) { + LIBSSH2_FREE(session, session->open_packet); + } + if (session->open_data) { + LIBSSH2_FREE(session, session->open_data); + } + if (session->direct_message) { + LIBSSH2_FREE(session, session->direct_message); + } + if (session->fwdLstn_packet) { + LIBSSH2_FREE(session, session->fwdLstn_packet); + } + if (session->pkeyInit_data) { + LIBSSH2_FREE(session, session->pkeyInit_data); + } + if (session->scpRecv_command) { + LIBSSH2_FREE(session, session->scpRecv_command); + } + if (session->scpSend_command) { + LIBSSH2_FREE(session, session->scpSend_command); + } + + /* Cleanup all remaining packets */ + while ((pkg = _libssh2_list_first(&session->packets))) { + packets_left++; + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "packet left with id %d", pkg->data[0]); + /* unlink the node */ + _libssh2_list_remove(&pkg->node); + + /* free */ + LIBSSH2_FREE(session, pkg->data); + LIBSSH2_FREE(session, pkg); + } + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "Extra packets left %d", packets_left); + + if(session->socket_prev_blockstate) + /* if the socket was previously blocking, put it back so */ + session_nonblock(session->socket_fd, 0); + + if (session->server_hostkey) { + LIBSSH2_FREE(session, session->server_hostkey); + } + + LIBSSH2_FREE(session, session); + + return 0; +} + +/* + * libssh2_session_free + * + * Frees the memory allocated to the session + * Also closes and frees any channels attached to this session + */ +LIBSSH2_API int +libssh2_session_free(LIBSSH2_SESSION * session) +{ + int rc; + + BLOCK_ADJUST(rc, session, session_free(session) ); + + return rc; +} + +/* + * libssh2_session_disconnect_ex + */ +static int +session_disconnect(LIBSSH2_SESSION *session, int reason, + const char *description, + const char *lang) +{ + unsigned char *s; + unsigned long descr_len = 0, lang_len = 0; + int rc; + + if (session->disconnect_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, + "Disconnecting: reason=%d, desc=%s, lang=%s", reason, + description, lang); + if (description) + descr_len = strlen(description); + + if (lang) + lang_len = strlen(lang); + + if(descr_len > 256) + return _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "too long description"); + + /* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */ + session->disconnect_data_len = descr_len + lang_len + 13; + + s = session->disconnect_data; + + *(s++) = SSH_MSG_DISCONNECT; + _libssh2_store_u32(&s, reason); + _libssh2_store_str(&s, description, descr_len); + /* store length only, lang is sent separately */ + _libssh2_store_u32(&s, lang_len); + + session->disconnect_state = libssh2_NB_state_created; + } + + rc = _libssh2_transport_send(session, session->disconnect_data, + session->disconnect_data_len, + (unsigned char *)lang, lang_len); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + + session->disconnect_state = libssh2_NB_state_idle; + + return 0; +} + +/* + * libssh2_session_disconnect_ex + */ +LIBSSH2_API int +libssh2_session_disconnect_ex(LIBSSH2_SESSION *session, int reason, + const char *desc, const char *lang) +{ + int rc; + + BLOCK_ADJUST(rc, session, + session_disconnect(session, reason, desc, lang)); + + return rc; +} + +/* libssh2_session_methods + * + * Return the currently active methods for method_type + * + * NOTE: Currently lang_cs and lang_sc are ALWAYS set to empty string + * regardless of actual negotiation Strings should NOT be freed + */ +LIBSSH2_API const char * +libssh2_session_methods(LIBSSH2_SESSION * session, int method_type) +{ + /* All methods have char *name as their first element */ + const LIBSSH2_KEX_METHOD *method = NULL; + + switch (method_type) { + case LIBSSH2_METHOD_KEX: + method = session->kex; + break; + + case LIBSSH2_METHOD_HOSTKEY: + method = (LIBSSH2_KEX_METHOD *) session->hostkey; + break; + + case LIBSSH2_METHOD_CRYPT_CS: + method = (LIBSSH2_KEX_METHOD *) session->local.crypt; + break; + + case LIBSSH2_METHOD_CRYPT_SC: + method = (LIBSSH2_KEX_METHOD *) session->remote.crypt; + break; + + case LIBSSH2_METHOD_MAC_CS: + method = (LIBSSH2_KEX_METHOD *) session->local.mac; + break; + + case LIBSSH2_METHOD_MAC_SC: + method = (LIBSSH2_KEX_METHOD *) session->remote.mac; + break; + + case LIBSSH2_METHOD_COMP_CS: + method = (LIBSSH2_KEX_METHOD *) session->local.comp; + break; + + case LIBSSH2_METHOD_COMP_SC: + method = (LIBSSH2_KEX_METHOD *) session->remote.comp; + break; + + case LIBSSH2_METHOD_LANG_CS: + return ""; + + case LIBSSH2_METHOD_LANG_SC: + return ""; + + default: + _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "Invalid parameter specified for method_type"); + return NULL; + } + + if (!method) { + _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, + "No method negotiated"); + return NULL; + } + + return method->name; +} + +/* libssh2_session_abstract + * Retrieve a pointer to the abstract property + */ +LIBSSH2_API void ** +libssh2_session_abstract(LIBSSH2_SESSION * session) +{ + return &session->abstract; +} + +/* libssh2_session_last_error + * + * Returns error code and populates an error string into errmsg If want_buf is + * non-zero then the string placed into errmsg must be freed by the calling + * program. Otherwise it is assumed to be owned by libssh2 + */ +LIBSSH2_API int +libssh2_session_last_error(LIBSSH2_SESSION * session, char **errmsg, + int *errmsg_len, int want_buf) +{ + size_t msglen = 0; + + /* No error to report */ + if (!session->err_code) { + if (errmsg) { + if (want_buf) { + *errmsg = LIBSSH2_ALLOC(session, 1); + if (*errmsg) { + **errmsg = 0; + } + } else { + *errmsg = (char *) ""; + } + } + if (errmsg_len) { + *errmsg_len = 0; + } + return 0; + } + + if (errmsg) { + const char *error = session->err_msg ? session->err_msg : ""; + + msglen = strlen(error); + + if (want_buf) { + /* Make a copy so the calling program can own it */ + *errmsg = LIBSSH2_ALLOC(session, msglen + 1); + if (*errmsg) { + memcpy(*errmsg, error, msglen); + (*errmsg)[msglen] = 0; + } + } + else + *errmsg = (char *)error; + } + + if (errmsg_len) { + *errmsg_len = msglen; + } + + return session->err_code; +} + +/* libssh2_session_last_errno + * + * Returns error code + */ +LIBSSH2_API int +libssh2_session_last_errno(LIBSSH2_SESSION * session) +{ + return session->err_code; +} + +/* libssh2_session_flag + * + * Set/Get session flags + * + * Return error code. + */ +LIBSSH2_API int +libssh2_session_flag(LIBSSH2_SESSION * session, int flag, int value) +{ + switch(flag) { + case LIBSSH2_FLAG_SIGPIPE: + session->flag.sigpipe = value; + break; + case LIBSSH2_FLAG_COMPRESS: + session->flag.compress = value; + break; + default: + /* unknown flag */ + return LIBSSH2_ERROR_INVAL; + } + + return LIBSSH2_ERROR_NONE; +} + +/* _libssh2_session_set_blocking + * + * Set a session's blocking mode on or off, return the previous status when + * this function is called. Note this function does not alter the state of the + * actual socket involved. + */ +int +_libssh2_session_set_blocking(LIBSSH2_SESSION *session, int blocking) +{ + int bl = session->api_block_mode; + _libssh2_debug(session, LIBSSH2_TRACE_CONN, + "Setting blocking mode %s", blocking?"ON":"OFF"); + session->api_block_mode = blocking; + + return bl; +} + +/* libssh2_session_set_blocking + * + * Set a channel's blocking mode on or off, similar to a socket's + * fcntl(fd, F_SETFL, O_NONBLOCK); type command + */ +LIBSSH2_API void +libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking) +{ + (void) _libssh2_session_set_blocking(session, blocking); +} + +/* libssh2_session_get_blocking + * + * Returns a session's blocking mode on or off + */ +LIBSSH2_API int +libssh2_session_get_blocking(LIBSSH2_SESSION * session) +{ + return session->api_block_mode; +} + + +/* libssh2_session_set_timeout + * + * Set a session's timeout (in msec) for blocking mode, + * or 0 to disable timeouts. + */ +LIBSSH2_API void +libssh2_session_set_timeout(LIBSSH2_SESSION * session, long timeout) +{ + session->api_timeout = timeout; +} + +/* libssh2_session_get_timeout + * + * Returns a session's timeout, or 0 if disabled + */ +LIBSSH2_API long +libssh2_session_get_timeout(LIBSSH2_SESSION * session) +{ + return session->api_timeout; +} + +/* + * libssh2_poll_channel_read + * + * Returns 0 if no data is waiting on channel, + * non-0 if data is available + */ +LIBSSH2_API int +libssh2_poll_channel_read(LIBSSH2_CHANNEL *channel, int extended) +{ + LIBSSH2_SESSION *session; + LIBSSH2_PACKET *packet; + + if(!channel) + return LIBSSH2_ERROR_BAD_USE; + + session = channel->session; + packet = _libssh2_list_first(&session->packets); + + while (packet) { + if ( channel->local.id == _libssh2_ntohu32(packet->data + 1)) { + if ( extended == 1 && + (packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA + || packet->data[0] == SSH_MSG_CHANNEL_DATA )) { + return 1; + } else if ( extended == 0 && + packet->data[0] == SSH_MSG_CHANNEL_DATA) { + return 1; + } + /* else - no data of any type is ready to be read */ + } + packet = _libssh2_list_next(&packet->node); + } + + return 0; +} + +/* + * poll_channel_write + * + * Returns 0 if writing to channel would block, + * non-0 if data can be written without blocking + */ +static inline int +poll_channel_write(LIBSSH2_CHANNEL * channel) +{ + return channel->local.window_size ? 1 : 0; +} + +/* poll_listener_queued + * + * Returns 0 if no connections are waiting to be accepted + * non-0 if one or more connections are available + */ +static inline int +poll_listener_queued(LIBSSH2_LISTENER * listener) +{ + return _libssh2_list_first(&listener->queue) ? 1 : 0; +} + +/* + * libssh2_poll + * + * Poll sockets, channels, and listeners for activity + */ +LIBSSH2_API int +libssh2_poll(LIBSSH2_POLLFD * fds, unsigned int nfds, long timeout) +{ + long timeout_remaining; + unsigned int i, active_fds; +#ifdef HAVE_POLL + LIBSSH2_SESSION *session = NULL; +#ifdef HAVE_ALLOCA + struct pollfd *sockets = alloca(sizeof(struct pollfd) * nfds); +#else + struct pollfd sockets[256]; + + if (nfds > 256) + /* systems without alloca use a fixed-size array, this can be fixed if + we really want to, at least if the compiler is a C99 capable one */ + return -1; +#endif + /* Setup sockets for polling */ + for(i = 0; i < nfds; i++) { + fds[i].revents = 0; + switch (fds[i].type) { + case LIBSSH2_POLLFD_SOCKET: + sockets[i].fd = fds[i].fd.socket; + sockets[i].events = fds[i].events; + sockets[i].revents = 0; + break; + + case LIBSSH2_POLLFD_CHANNEL: + sockets[i].fd = fds[i].fd.channel->session->socket_fd; + sockets[i].events = POLLIN; + sockets[i].revents = 0; + if (!session) + session = fds[i].fd.channel->session; + break; + + case LIBSSH2_POLLFD_LISTENER: + sockets[i].fd = fds[i].fd.listener->session->socket_fd; + sockets[i].events = POLLIN; + sockets[i].revents = 0; + if (!session) + session = fds[i].fd.listener->session; + break; + + default: + if (session) + _libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, + "Invalid descriptor passed to libssh2_poll()"); + return -1; + } + } +#elif defined(HAVE_SELECT) + LIBSSH2_SESSION *session = NULL; + libssh2_socket_t maxfd = 0; + fd_set rfds, wfds; + struct timeval tv; + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + for(i = 0; i < nfds; i++) { + fds[i].revents = 0; + switch (fds[i].type) { + case LIBSSH2_POLLFD_SOCKET: + if (fds[i].events & LIBSSH2_POLLFD_POLLIN) { + FD_SET(fds[i].fd.socket, &rfds); + if (fds[i].fd.socket > maxfd) + maxfd = fds[i].fd.socket; + } + if (fds[i].events & LIBSSH2_POLLFD_POLLOUT) { + FD_SET(fds[i].fd.socket, &wfds); + if (fds[i].fd.socket > maxfd) + maxfd = fds[i].fd.socket; + } + break; + + case LIBSSH2_POLLFD_CHANNEL: + FD_SET(fds[i].fd.channel->session->socket_fd, &rfds); + if (fds[i].fd.channel->session->socket_fd > maxfd) + maxfd = fds[i].fd.channel->session->socket_fd; + if (!session) + session = fds[i].fd.channel->session; + break; + + case LIBSSH2_POLLFD_LISTENER: + FD_SET(fds[i].fd.listener->session->socket_fd, &rfds); + if (fds[i].fd.listener->session->socket_fd > maxfd) + maxfd = fds[i].fd.listener->session->socket_fd; + if (!session) + session = fds[i].fd.listener->session; + break; + + default: + if (session) + _libssh2_error(session, LIBSSH2_ERROR_INVALID_POLL_TYPE, + "Invalid descriptor passed to libssh2_poll()"); + return -1; + } + } +#else + /* No select() or poll() + * no sockets sturcture to setup + */ + + timeout = 0; +#endif /* HAVE_POLL or HAVE_SELECT */ + + timeout_remaining = timeout; + do { +#if defined(HAVE_POLL) || defined(HAVE_SELECT) + int sysret; +#endif + + active_fds = 0; + + for(i = 0; i < nfds; i++) { + if (fds[i].events != fds[i].revents) { + switch (fds[i].type) { + case LIBSSH2_POLLFD_CHANNEL: + if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && + /* Want to be ready for read */ + ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { + /* Not yet known to be ready for read */ + fds[i].revents |= + libssh2_poll_channel_read(fds[i].fd.channel, + 0) ? + LIBSSH2_POLLFD_POLLIN : 0; + } + if ((fds[i].events & LIBSSH2_POLLFD_POLLEXT) && + /* Want to be ready for extended read */ + ((fds[i].revents & LIBSSH2_POLLFD_POLLEXT) == 0)) { + /* Not yet known to be ready for extended read */ + fds[i].revents |= + libssh2_poll_channel_read(fds[i].fd.channel, + 1) ? + LIBSSH2_POLLFD_POLLEXT : 0; + } + if ((fds[i].events & LIBSSH2_POLLFD_POLLOUT) && + /* Want to be ready for write */ + ((fds[i].revents & LIBSSH2_POLLFD_POLLOUT) == 0)) { + /* Not yet known to be ready for write */ + fds[i].revents |= + poll_channel_write(fds[i].fd. channel) ? + LIBSSH2_POLLFD_POLLOUT : 0; + } + if (fds[i].fd.channel->remote.close + || fds[i].fd.channel->local.close) { + fds[i].revents |= LIBSSH2_POLLFD_CHANNEL_CLOSED; + } + if (fds[i].fd.channel->session->socket_state == + LIBSSH2_SOCKET_DISCONNECTED) { + fds[i].revents |= + LIBSSH2_POLLFD_CHANNEL_CLOSED | + LIBSSH2_POLLFD_SESSION_CLOSED; + } + break; + + case LIBSSH2_POLLFD_LISTENER: + if ((fds[i].events & LIBSSH2_POLLFD_POLLIN) && + /* Want a connection */ + ((fds[i].revents & LIBSSH2_POLLFD_POLLIN) == 0)) { + /* No connections known of yet */ + fds[i].revents |= + poll_listener_queued(fds[i].fd. listener) ? + LIBSSH2_POLLFD_POLLIN : 0; + } + if (fds[i].fd.listener->session->socket_state == + LIBSSH2_SOCKET_DISCONNECTED) { + fds[i].revents |= + LIBSSH2_POLLFD_LISTENER_CLOSED | + LIBSSH2_POLLFD_SESSION_CLOSED; + } + break; + } + } + if (fds[i].revents) { + active_fds++; + } + } + + if (active_fds) { + /* Don't block on the sockets if we have channels/listeners which + are ready */ + timeout_remaining = 0; + } +#ifdef HAVE_POLL + +#ifdef HAVE_LIBSSH2_GETTIMEOFDAY + { + struct timeval tv_begin, tv_end; + + _libssh2_gettimeofday((struct timeval *) &tv_begin, NULL); + sysret = poll(sockets, nfds, timeout_remaining); + _libssh2_gettimeofday((struct timeval *) &tv_end, NULL); + timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000; + timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000; + } +#else + /* If the platform doesn't support gettimeofday, + * then just make the call non-blocking and walk away + */ + sysret = poll(sockets, nfds, timeout_remaining); + timeout_remaining = 0; +#endif /* HAVE_GETTIMEOFDAY */ + + if (sysret > 0) { + for(i = 0; i < nfds; i++) { + switch (fds[i].type) { + case LIBSSH2_POLLFD_SOCKET: + fds[i].revents = sockets[i].revents; + sockets[i].revents = 0; /* In case we loop again, be nice */ + if (fds[i].revents) { + active_fds++; + } + break; + case LIBSSH2_POLLFD_CHANNEL: + if (sockets[i].events & POLLIN) { + /* Spin session until no data available */ + while (_libssh2_transport_read(fds[i].fd.channel->session) + > 0); + } + if (sockets[i].revents & POLLHUP) { + fds[i].revents |= + LIBSSH2_POLLFD_CHANNEL_CLOSED | + LIBSSH2_POLLFD_SESSION_CLOSED; + } + sockets[i].revents = 0; + break; + case LIBSSH2_POLLFD_LISTENER: + if (sockets[i].events & POLLIN) { + /* Spin session until no data available */ + while (_libssh2_transport_read(fds[i].fd.listener->session) + > 0); + } + if (sockets[i].revents & POLLHUP) { + fds[i].revents |= + LIBSSH2_POLLFD_LISTENER_CLOSED | + LIBSSH2_POLLFD_SESSION_CLOSED; + } + sockets[i].revents = 0; + break; + } + } + } +#elif defined(HAVE_SELECT) + tv.tv_sec = timeout_remaining / 1000; + tv.tv_usec = (timeout_remaining % 1000) * 1000; +#ifdef HAVE_LIBSSH2_GETTIMEOFDAY + { + struct timeval tv_begin, tv_end; + + _libssh2_gettimeofday((struct timeval *) &tv_begin, NULL); + sysret = select(maxfd+1, &rfds, &wfds, NULL, &tv); + _libssh2_gettimeofday((struct timeval *) &tv_end, NULL); + + timeout_remaining -= (tv_end.tv_sec - tv_begin.tv_sec) * 1000; + timeout_remaining -= (tv_end.tv_usec - tv_begin.tv_usec) / 1000; + } +#else + /* If the platform doesn't support gettimeofday, + * then just make the call non-blocking and walk away + */ + sysret = select(maxfd+1, &rfds, &wfds, NULL, &tv); + timeout_remaining = 0; +#endif + + if (sysret > 0) { + for(i = 0; i < nfds; i++) { + switch (fds[i].type) { + case LIBSSH2_POLLFD_SOCKET: + if (FD_ISSET(fds[i].fd.socket, &rfds)) { + fds[i].revents |= LIBSSH2_POLLFD_POLLIN; + } + if (FD_ISSET(fds[i].fd.socket, &wfds)) { + fds[i].revents |= LIBSSH2_POLLFD_POLLOUT; + } + if (fds[i].revents) { + active_fds++; + } + break; + + case LIBSSH2_POLLFD_CHANNEL: + if (FD_ISSET(fds[i].fd.channel->session->socket_fd, &rfds)) { + /* Spin session until no data available */ + while (_libssh2_transport_read(fds[i].fd.channel->session) + > 0); + } + break; + + case LIBSSH2_POLLFD_LISTENER: + if (FD_ISSET + (fds[i].fd.listener->session->socket_fd, &rfds)) { + /* Spin session until no data available */ + while (_libssh2_transport_read(fds[i].fd.listener->session) + > 0); + } + break; + } + } + } +#endif /* else no select() or poll() -- timeout (and by extension + * timeout_remaining) will be equal to 0 */ + } while ((timeout_remaining > 0) && !active_fds); + + return active_fds; +} + +/* + * libssh2_session_block_directions + * + * Get blocked direction when a function returns LIBSSH2_ERROR_EAGAIN + * Returns LIBSSH2_SOCKET_BLOCK_INBOUND if recv() blocked + * or LIBSSH2_SOCKET_BLOCK_OUTBOUND if send() blocked + */ +LIBSSH2_API int +libssh2_session_block_directions(LIBSSH2_SESSION *session) +{ + return session->socket_block_directions; +} + +/* libssh2_session_banner_get + * Get the remote banner (server ID string) + */ + +LIBSSH2_API const char * +libssh2_session_banner_get(LIBSSH2_SESSION *session) +{ + /* to avoid a coredump when session is NULL */ + if (NULL == session) + return NULL; + + if (NULL==session->remote.banner) + return NULL; + + return (const char *) session->remote.banner; +} diff --git a/vendor/libssh2-1.4.2/src/session.h b/vendor/libssh2-1.4.2/src/session.h new file mode 100644 index 0000000..aff4f2c --- /dev/null +++ b/vendor/libssh2-1.4.2/src/session.h @@ -0,0 +1,93 @@ +#ifndef LIBSSH2_SESSION_H +#define LIBSSH2_SESSION_H +/* Copyright (c) 2004-2007 Sara Golemon + * Copyright (c) 2009-2010 by Daniel Stenberg + * Copyright (c) 2010 Simon Josefsson + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +/* Conveniance-macros to allow code like this; + + int rc = BLOCK_ADJUST(rc, session, session_startup(session, sock) ); + + int rc = BLOCK_ADJUST_ERRNO(ptr, session, session_startup(session, sock) ); + + The point of course being to make sure that while in non-blocking mode + these always return no matter what the return code is, but in blocking mode + it blocks if EAGAIN is the reason for the return from the underlying + function. + +*/ +#define BLOCK_ADJUST(rc,sess,x) \ + do { \ + time_t entry_time = time (NULL); \ + do { \ + rc = x; \ + /* the order of the check below is important to properly deal with \ + the case when the 'sess' is freed */ \ + if((rc != LIBSSH2_ERROR_EAGAIN) || !sess->api_block_mode) \ + break; \ + rc = _libssh2_wait_socket(sess, entry_time); \ + } while(!rc); \ + } while(0) + +/* + * For functions that returns a pointer, we need to check if the API is + * non-blocking and return immediately. If the pointer is non-NULL we return + * immediately. If the API is blocking and we get a NULL we check the errno + * and *only* if that is EAGAIN we loop and wait for socket action. + */ +#define BLOCK_ADJUST_ERRNO(ptr,sess,x) \ + do { \ + time_t entry_time = time (NULL); \ + int rc; \ + do { \ + ptr = x; \ + if(!sess->api_block_mode || \ + (ptr != NULL) || \ + (libssh2_session_last_errno(sess) != LIBSSH2_ERROR_EAGAIN) ) \ + break; \ + rc = _libssh2_wait_socket(sess, entry_time); \ + } while(!rc); \ + } while(0) + + +int _libssh2_wait_socket(LIBSSH2_SESSION *session, time_t entry_time); + +/* this is the lib-internal set blocking function */ +int _libssh2_session_set_blocking(LIBSSH2_SESSION * session, int blocking); + +#endif /* LIBSSH2_SESSION_H */ diff --git a/vendor/libssh2-1.4.2/src/sftp.c b/vendor/libssh2-1.4.2/src/sftp.c new file mode 100644 index 0000000..ec9d033 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/sftp.c @@ -0,0 +1,3278 @@ +/* Copyright (c) 2004-2008, Sara Golemon + * Copyright (c) 2007 Eli Fant + * Copyright (c) 2009-2012 by Daniel Stenberg + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include + +#include "libssh2_priv.h" +#include "libssh2_sftp.h" +#include "channel.h" +#include "session.h" +#include "sftp.h" + +/* Note: Version 6 was documented at the time of writing + * However it was marked as "DO NOT IMPLEMENT" due to pending changes + * + * This release of libssh2 implements Version 5 with automatic downgrade + * based on server's declaration + */ + +/* SFTP packet types */ +#define SSH_FXP_INIT 1 +#define SSH_FXP_VERSION 2 +#define SSH_FXP_OPEN 3 +#define SSH_FXP_CLOSE 4 +#define SSH_FXP_READ 5 +#define SSH_FXP_WRITE 6 +#define SSH_FXP_LSTAT 7 +#define SSH_FXP_FSTAT 8 +#define SSH_FXP_SETSTAT 9 +#define SSH_FXP_FSETSTAT 10 +#define SSH_FXP_OPENDIR 11 +#define SSH_FXP_READDIR 12 +#define SSH_FXP_REMOVE 13 +#define SSH_FXP_MKDIR 14 +#define SSH_FXP_RMDIR 15 +#define SSH_FXP_REALPATH 16 +#define SSH_FXP_STAT 17 +#define SSH_FXP_RENAME 18 +#define SSH_FXP_READLINK 19 +#define SSH_FXP_SYMLINK 20 +#define SSH_FXP_STATUS 101 +#define SSH_FXP_HANDLE 102 +#define SSH_FXP_DATA 103 +#define SSH_FXP_NAME 104 +#define SSH_FXP_ATTRS 105 +#define SSH_FXP_EXTENDED 200 +#define SSH_FXP_EXTENDED_REPLY 201 + +/* S_IFREG */ +#define LIBSSH2_SFTP_ATTR_PFILETYPE_FILE 0100000 +/* S_IFDIR */ +#define LIBSSH2_SFTP_ATTR_PFILETYPE_DIR 0040000 + +#define SSH_FXE_STATVFS_ST_RDONLY 0x00000001 +#define SSH_FXE_STATVFS_ST_NOSUID 0x00000002 + +/* This is the maximum packet length to accept, as larger than this indicate + some kind of server problem. */ +#define LIBSSH2_SFTP_PACKET_MAXLEN 80000 + +static int sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle); +static int sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type, + uint32_t request_id, unsigned char **data, + size_t *data_len); +static void sftp_packet_flush(LIBSSH2_SFTP *sftp); + +/* sftp_attrsize + * Size that attr with this flagset will occupy when turned into a bin struct + */ +static int sftp_attrsize(unsigned long flags) +{ + return (4 + /* flags(4) */ + ((flags & LIBSSH2_SFTP_ATTR_SIZE) ? 8 : 0) + + ((flags & LIBSSH2_SFTP_ATTR_UIDGID) ? 8 : 0) + + ((flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) ? 4 : 0) + + ((flags & LIBSSH2_SFTP_ATTR_ACMODTIME) ? 8 : 0)); + /* atime + mtime as u32 */ +} + +/* _libssh2_store_u64 + */ +static void _libssh2_store_u64(unsigned char **ptr, libssh2_uint64_t value) +{ + uint32_t msl = (uint32_t)(value >> 32); + unsigned char *buf = *ptr; + + buf[0] = (unsigned char)((msl >> 24) & 0xFF); + buf[1] = (unsigned char)((msl >> 16) & 0xFF); + buf[2] = (unsigned char)((msl >> 8) & 0xFF); + buf[3] = (unsigned char)( msl & 0xFF); + + buf[4] = (unsigned char)((value >> 24) & 0xFF); + buf[5] = (unsigned char)((value >> 16) & 0xFF); + buf[6] = (unsigned char)((value >> 8) & 0xFF); + buf[7] = (unsigned char)( value & 0xFF); + + *ptr += 8; +} + +/* + * Search list of zombied FXP_READ request IDs. + * + * Returns NULL if ID not in list. + */ +static struct sftp_zombie_requests * +find_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) +{ + struct sftp_zombie_requests *zombie = + _libssh2_list_first(&sftp->zombie_requests); + + while(zombie) { + if(zombie->request_id == request_id) + break; + else + zombie = _libssh2_list_next(&zombie->node); + } + + return zombie; +} + +static void +remove_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) +{ + LIBSSH2_SESSION *session = sftp->channel->session; + + struct sftp_zombie_requests *zombie = find_zombie_request(sftp, + request_id); + if(zombie) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "Removing request ID %ld from the list of zombie requests", + request_id); + + _libssh2_list_remove(&zombie->node); + LIBSSH2_FREE(session, zombie); + } +} + +static int +add_zombie_request(LIBSSH2_SFTP *sftp, uint32_t request_id) +{ + LIBSSH2_SESSION *session = sftp->channel->session; + + struct sftp_zombie_requests *zombie; + + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "Marking request ID %ld as a zombie request", request_id); + + zombie = LIBSSH2_ALLOC(sftp->channel->session, + sizeof(struct sftp_zombie_requests)); + if (!zombie) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "malloc fail for zombie request ID"); + else { + zombie->request_id = request_id; + _libssh2_list_add(&sftp->zombie_requests, &zombie->node); + return LIBSSH2_ERROR_NONE; + } +} + +/* + * sftp_packet_add + * + * Add a packet to the SFTP packet brigade + */ +static int +sftp_packet_add(LIBSSH2_SFTP *sftp, unsigned char *data, + size_t data_len) +{ + LIBSSH2_SESSION *session = sftp->channel->session; + LIBSSH2_SFTP_PACKET *packet; + uint32_t request_id; + + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Received packet %d (len %d)", + (int) data[0], data_len); + + /* + * Experience shows that if we mess up EAGAIN handling somewhere or + * otherwise get out of sync with the channel, this is where we first get + * a wrong byte and if so we need to bail out at once to aid tracking the + * problem better. + */ + + switch(data[0]) { + case SSH_FXP_INIT: + case SSH_FXP_VERSION: + case SSH_FXP_OPEN: + case SSH_FXP_CLOSE: + case SSH_FXP_READ: + case SSH_FXP_WRITE: + case SSH_FXP_LSTAT: + case SSH_FXP_FSTAT: + case SSH_FXP_SETSTAT: + case SSH_FXP_FSETSTAT: + case SSH_FXP_OPENDIR: + case SSH_FXP_READDIR: + case SSH_FXP_REMOVE: + case SSH_FXP_MKDIR: + case SSH_FXP_RMDIR: + case SSH_FXP_REALPATH: + case SSH_FXP_STAT: + case SSH_FXP_RENAME: + case SSH_FXP_READLINK: + case SSH_FXP_SYMLINK: + case SSH_FXP_STATUS: + case SSH_FXP_HANDLE: + case SSH_FXP_DATA: + case SSH_FXP_NAME: + case SSH_FXP_ATTRS: + case SSH_FXP_EXTENDED: + case SSH_FXP_EXTENDED_REPLY: + break; + default: + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "Out of sync with the world"); + } + + request_id = _libssh2_ntohu32(&data[1]); + + /* Don't add the packet if it answers a request we've given up on. */ + if((data[0] == SSH_FXP_STATUS || data[0] == SSH_FXP_DATA) + && find_zombie_request(sftp, request_id)) { + + /* If we get here, the file ended before the response arrived. We + are no longer interested in the request so we discard it */ + + LIBSSH2_FREE(session, data); + + remove_zombie_request(sftp, request_id); + return LIBSSH2_ERROR_NONE; + } + + packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP_PACKET)); + if (!packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate datablock for SFTP packet"); + } + + packet->data = data; + packet->data_len = data_len; + packet->request_id = request_id; + + _libssh2_list_add(&sftp->packets, &packet->node); + + return LIBSSH2_ERROR_NONE; +} + +/* + * sftp_packet_read + * + * Frame an SFTP packet off the channel + */ +static int +sftp_packet_read(LIBSSH2_SFTP *sftp) +{ + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + unsigned char *packet = NULL; + ssize_t rc; + unsigned long recv_window; + int packet_type; + + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "recv packet"); + + switch(sftp->packet_state) { + case libssh2_NB_state_sent: /* EAGAIN from window adjusting */ + sftp->packet_state = libssh2_NB_state_idle; + + packet = sftp->partial_packet; + goto window_adjust; + + case libssh2_NB_state_sent1: /* EAGAIN from channel read */ + sftp->packet_state = libssh2_NB_state_idle; + + packet = sftp->partial_packet; + + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "partial read cont, len: %lu", sftp->partial_len); + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "partial read cont, already recvd: %lu", + sftp->partial_received); + /* fall-through */ + default: + if(!packet) { + /* only do this if there's not already a packet buffer allocated + to use */ + + /* each packet starts with a 32 bit length field */ + rc = _libssh2_channel_read(channel, 0, + (char *)&sftp->partial_size[ + sftp->partial_size_len], + 4 - sftp->partial_size_len); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + else if (rc < 0) + return _libssh2_error(session, rc, "channel read"); + + sftp->partial_size_len += rc; + + if(4 != sftp->partial_size_len) + /* we got a short read for the length part */ + return LIBSSH2_ERROR_EAGAIN; + + sftp->partial_len = _libssh2_ntohu32(sftp->partial_size); + /* make sure we don't proceed if the packet size is unreasonably + large */ + if (sftp->partial_len > LIBSSH2_SFTP_PACKET_MAXLEN) + return _libssh2_error(session, + LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, + "SFTP packet too large"); + + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "Data begin - Packet Length: %lu", + sftp->partial_len); + packet = LIBSSH2_ALLOC(session, sftp->partial_len); + if (!packet) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate SFTP packet"); + sftp->partial_size_len = 0; + sftp->partial_received = 0; /* how much of the packet already + received */ + sftp->partial_packet = packet; + + window_adjust: + recv_window = libssh2_channel_window_read_ex(channel, NULL, NULL); + + if(sftp->partial_len > recv_window) { + /* ask for twice the data amount we need at once */ + rc = _libssh2_channel_receive_window_adjust(channel, + sftp->partial_len*2, + 1, NULL); + /* store the state so that we continue with the correct + operation at next invoke */ + sftp->packet_state = (rc == LIBSSH2_ERROR_EAGAIN)? + libssh2_NB_state_sent: + libssh2_NB_state_idle; + + if(rc == LIBSSH2_ERROR_EAGAIN) + return rc; + } + } + + /* Read as much of the packet as we can */ + while (sftp->partial_len > sftp->partial_received) { + rc = _libssh2_channel_read(channel, 0, + (char *)&packet[sftp->partial_received], + sftp->partial_len - + sftp->partial_received); + + if (rc == LIBSSH2_ERROR_EAGAIN) { + /* + * We received EAGAIN, save what we have and return EAGAIN to + * the caller. Set 'partial_packet' so that this function + * knows how to continue on the next invoke. + */ + sftp->packet_state = libssh2_NB_state_sent1; + return rc; + } + else if (rc < 0) { + LIBSSH2_FREE(session, packet); + sftp->partial_packet = NULL; + return _libssh2_error(session, rc, + "Error waiting for SFTP packet"); + } + sftp->partial_received += rc; + } + + sftp->partial_packet = NULL; + + /* sftp_packet_add takes ownership of the packet and might free it + so we take a copy of the packet type before we call it. */ + packet_type = packet[0]; + rc = sftp_packet_add(sftp, packet, sftp->partial_len); + if (rc) { + LIBSSH2_FREE(session, packet); + return rc; + } + else { + return packet_type; + } + } + /* WON'T REACH */ +} +/* + * sftp_packetlist_flush + * + * Remove all pending packets in the packet_list and the corresponding one(s) + * in the SFTP packet brigade. + */ +static void sftp_packetlist_flush(LIBSSH2_SFTP_HANDLE *handle) +{ + struct sftp_pipeline_chunk *chunk; + LIBSSH2_SFTP *sftp = handle->sftp; + LIBSSH2_SESSION *session = sftp->channel->session; + + /* remove pending packets, if any */ + chunk = _libssh2_list_first(&handle->packet_list); + while(chunk) { + unsigned char *data; + size_t data_len; + int rc; + struct sftp_pipeline_chunk *next = _libssh2_list_next(&chunk->node); + + rc = sftp_packet_ask(sftp, SSH_FXP_STATUS, + chunk->request_id, &data, &data_len); + if(rc) + rc = sftp_packet_ask(sftp, SSH_FXP_DATA, + chunk->request_id, &data, &data_len); + + if(!rc) + /* we found a packet, free it */ + LIBSSH2_FREE(session, data); + else if(chunk->sent) + /* there was no incoming packet for this request, mark this + request as a zombie if it ever sent the request */ + add_zombie_request(sftp, chunk->request_id); + + _libssh2_list_remove(&chunk->node); + LIBSSH2_FREE(session, chunk); + chunk = next; + } +} + + +/* + * sftp_packet_ask() + * + * Checks if there's a matching SFTP packet available. + */ +static int +sftp_packet_ask(LIBSSH2_SFTP *sftp, unsigned char packet_type, + uint32_t request_id, unsigned char **data, + size_t *data_len) +{ + LIBSSH2_SESSION *session = sftp->channel->session; + LIBSSH2_SFTP_PACKET *packet = _libssh2_list_first(&sftp->packets); + + if(!packet) + return -1; + + /* Special consideration when getting VERSION packet */ + + while (packet) { + if((packet->data[0] == packet_type) && + ((packet_type == SSH_FXP_VERSION) || + (packet->request_id == request_id))) { + + /* Match! Fetch the data */ + *data = packet->data; + *data_len = packet->data_len; + + /* unlink and free this struct */ + _libssh2_list_remove(&packet->node); + LIBSSH2_FREE(session, packet); + + return 0; + } + /* check next struct in the list */ + packet = _libssh2_list_next(&packet->node); + } + return -1; +} + +/* sftp_packet_require + * A la libssh2_packet_require + */ +static int +sftp_packet_require(LIBSSH2_SFTP *sftp, unsigned char packet_type, + uint32_t request_id, unsigned char **data, + size_t *data_len) +{ + LIBSSH2_SESSION *session = sftp->channel->session; + int rc; + + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Requiring packet %d id %ld", + (int) packet_type, request_id); + + if (sftp_packet_ask(sftp, packet_type, request_id, data, data_len) == 0) { + /* The right packet was available in the packet brigade */ + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d", + (int) packet_type); + return LIBSSH2_ERROR_NONE; + } + + while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) { + rc = sftp_packet_read(sftp); + if (rc < 0) + return rc; + + /* data was read, check the queue again */ + if (!sftp_packet_ask(sftp, packet_type, request_id, data, data_len)) { + /* The right packet was available in the packet brigade */ + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Got %d", + (int) packet_type); + return LIBSSH2_ERROR_NONE; + } + } + + /* Only reached if the socket died */ + return LIBSSH2_ERROR_SOCKET_DISCONNECT; +} + +/* sftp_packet_requirev + * Require one of N possible reponses + */ +static int +sftp_packet_requirev(LIBSSH2_SFTP *sftp, int num_valid_responses, + const unsigned char *valid_responses, + uint32_t request_id, unsigned char **data, + size_t *data_len) +{ + int i; + int rc; + + /* If no timeout is active, start a new one */ + if (sftp->requirev_start == 0) + sftp->requirev_start = time(NULL); + + while (sftp->channel->session->socket_state == LIBSSH2_SOCKET_CONNECTED) { + for(i = 0; i < num_valid_responses; i++) { + if (sftp_packet_ask(sftp, valid_responses[i], request_id, + data, data_len) == 0) { + /* + * Set to zero before all returns to say + * the timeout is not active + */ + sftp->requirev_start = 0; + return LIBSSH2_ERROR_NONE; + } + } + + rc = sftp_packet_read(sftp); + if ((rc < 0) && (rc != LIBSSH2_ERROR_EAGAIN)) { + sftp->requirev_start = 0; + return rc; + } else if (rc <= 0) { + /* prevent busy-looping */ + long left = + LIBSSH2_READ_TIMEOUT - (long)(time(NULL) - sftp->requirev_start); + + if (left <= 0) { + sftp->requirev_start = 0; + return LIBSSH2_ERROR_TIMEOUT; + } + else if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + } + } + + sftp->requirev_start = 0; + + /* Only reached if the socket died */ + return LIBSSH2_ERROR_SOCKET_DISCONNECT; +} + +/* sftp_attr2bin + * Populate attributes into an SFTP block + */ +static ssize_t +sftp_attr2bin(unsigned char *p, const LIBSSH2_SFTP_ATTRIBUTES * attrs) +{ + unsigned char *s = p; + uint32_t flag_mask = + LIBSSH2_SFTP_ATTR_SIZE | LIBSSH2_SFTP_ATTR_UIDGID | + LIBSSH2_SFTP_ATTR_PERMISSIONS | LIBSSH2_SFTP_ATTR_ACMODTIME; + + /* TODO: When we add SFTP4+ functionality flag_mask can get additional + bits */ + + if (!attrs) { + _libssh2_htonu32(s, 0); + return 4; + } + + _libssh2_store_u32(&s, attrs->flags & flag_mask); + + if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) { + _libssh2_store_u64(&s, attrs->filesize); + } + + if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) { + _libssh2_store_u32(&s, attrs->uid); + _libssh2_store_u32(&s, attrs->gid); + } + + if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { + _libssh2_store_u32(&s, attrs->permissions); + } + + if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { + _libssh2_store_u32(&s, attrs->atime); + _libssh2_store_u32(&s, attrs->mtime); + } + + return (s - p); +} + +/* sftp_bin2attr + */ +static int +sftp_bin2attr(LIBSSH2_SFTP_ATTRIBUTES * attrs, const unsigned char *p) +{ + const unsigned char *s = p; + + memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); + attrs->flags = _libssh2_ntohu32(s); + s += 4; + + if (attrs->flags & LIBSSH2_SFTP_ATTR_SIZE) { + attrs->filesize = _libssh2_ntohu64(s); + s += 8; + } + + if (attrs->flags & LIBSSH2_SFTP_ATTR_UIDGID) { + attrs->uid = _libssh2_ntohu32(s); + s += 4; + attrs->gid = _libssh2_ntohu32(s); + s += 4; + } + + if (attrs->flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) { + attrs->permissions = _libssh2_ntohu32(s); + s += 4; + } + + if (attrs->flags & LIBSSH2_SFTP_ATTR_ACMODTIME) { + attrs->atime = _libssh2_ntohu32(s); + s += 4; + attrs->mtime = _libssh2_ntohu32(s); + s += 4; + } + + return (s - p); +} + +/* ************ + * SFTP API * + ************ */ + +LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor); + +/* libssh2_sftp_dtor + * Shutdown an SFTP stream when the channel closes + */ +LIBSSH2_CHANNEL_CLOSE_FUNC(libssh2_sftp_dtor) +{ + LIBSSH2_SFTP *sftp = (LIBSSH2_SFTP *) (*channel_abstract); + + (void) session_abstract; + (void) channel; + + /* Free the partial packet storage for sftp_packet_read */ + if (sftp->partial_packet) { + LIBSSH2_FREE(session, sftp->partial_packet); + } + + /* Free the packet storage for _libssh2_sftp_packet_readdir */ + if (sftp->readdir_packet) { + LIBSSH2_FREE(session, sftp->readdir_packet); + } + + LIBSSH2_FREE(session, sftp); +} + +/* + * sftp_init + * + * Startup an SFTP session + */ +static LIBSSH2_SFTP *sftp_init(LIBSSH2_SESSION *session) +{ + unsigned char *data, *s; + size_t data_len; + ssize_t rc; + LIBSSH2_SFTP *sftp_handle; + + if (session->sftpInit_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "Initializing SFTP subsystem"); + + /* + * The 'sftpInit_sftp' and 'sftpInit_channel' struct fields within the + * session struct are only to be used during the setup phase. As soon + * as the SFTP session is created they are cleared and can thus be + * re-used again to allow any amount of SFTP handles per sessions. + * + * Note that you MUST NOT try to call libssh2_sftp_init() again to get + * another handle until the previous call has finished and either + * succesffully made a handle or failed and returned error (not + * including *EAGAIN). + */ + + assert(session->sftpInit_sftp == NULL); + session->sftpInit_sftp = NULL; + session->sftpInit_state = libssh2_NB_state_created; + } + + sftp_handle = session->sftpInit_sftp; + + if (session->sftpInit_state == libssh2_NB_state_created) { + session->sftpInit_channel = + _libssh2_channel_open(session, "session", sizeof("session") - 1, + LIBSSH2_CHANNEL_WINDOW_DEFAULT, + LIBSSH2_CHANNEL_PACKET_DEFAULT, NULL, 0); + if (!session->sftpInit_channel) { + if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block starting up channel"); + } + else { + _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, + "Unable to startup channel"); + session->sftpInit_state = libssh2_NB_state_idle; + } + return NULL; + } + + session->sftpInit_state = libssh2_NB_state_sent; + } + + if (session->sftpInit_state == libssh2_NB_state_sent) { + int ret = _libssh2_channel_process_startup(session->sftpInit_channel, + "subsystem", + sizeof("subsystem") - 1, "sftp", + strlen("sftp")); + if (ret == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block to request SFTP subsystem"); + return NULL; + } else if (ret) { + _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, + "Unable to request SFTP subsystem"); + goto sftp_init_error; + } + + session->sftpInit_state = libssh2_NB_state_sent1; + } + + if (session->sftpInit_state == libssh2_NB_state_sent1) { + rc = _libssh2_channel_extended_data(session->sftpInit_channel, + LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block requesting handle extended data"); + return NULL; + } + + sftp_handle = + session->sftpInit_sftp = + LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP)); + if (!sftp_handle) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate a new SFTP structure"); + goto sftp_init_error; + } + memset(sftp_handle, 0, sizeof(LIBSSH2_SFTP)); + sftp_handle->channel = session->sftpInit_channel; + sftp_handle->request_id = 0; + + _libssh2_htonu32(session->sftpInit_buffer, 5); + session->sftpInit_buffer[4] = SSH_FXP_INIT; + _libssh2_htonu32(session->sftpInit_buffer + 5, LIBSSH2_SFTP_VERSION); + session->sftpInit_sent = 0; /* nothing's sent yet */ + + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "Sending FXP_INIT packet advertising version %d support", + (int) LIBSSH2_SFTP_VERSION); + + session->sftpInit_state = libssh2_NB_state_sent2; + } + + if (session->sftpInit_state == libssh2_NB_state_sent2) { + /* sent off what's left of the init buffer to send */ + rc = _libssh2_channel_write(session->sftpInit_channel, 0, + session->sftpInit_buffer + + session->sftpInit_sent, + 9 - session->sftpInit_sent); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block sending SSH_FXP_INIT"); + return NULL; + } + else if(rc < 0) { + _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send SSH_FXP_INIT"); + goto sftp_init_error; + } + else { + /* add up the number of bytes sent */ + session->sftpInit_sent += rc; + + if(session->sftpInit_sent == 9) + /* move on */ + session->sftpInit_state = libssh2_NB_state_sent3; + + /* if less than 9, we remain in this state to send more later on */ + } + } + + rc = sftp_packet_require(sftp_handle, SSH_FXP_VERSION, + 0, &data, &data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) + return NULL; + else if (rc) { + _libssh2_error(session, rc, + "Timeout waiting for response from SFTP subsystem"); + goto sftp_init_error; + } + if (data_len < 5) { + _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "Invalid SSH_FXP_VERSION response"); + goto sftp_init_error; + } + + s = data + 1; + sftp_handle->version = _libssh2_ntohu32(s); + s += 4; + if (sftp_handle->version > LIBSSH2_SFTP_VERSION) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "Truncating remote SFTP version from %lu", + sftp_handle->version); + sftp_handle->version = LIBSSH2_SFTP_VERSION; + } + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "Enabling SFTP version %lu compatability", + sftp_handle->version); + while (s < (data + data_len)) { + size_t extname_len, extdata_len; + + extname_len = _libssh2_ntohu32(s); + s += 4; + /* the extension name starts here */ + s += extname_len; + + extdata_len = _libssh2_ntohu32(s); + s += 4; + + /* TODO: Actually process extensions */ + s += extdata_len; + + } + LIBSSH2_FREE(session, data); + + /* Make sure that when the channel gets closed, the SFTP service is shut + down too */ + sftp_handle->channel->abstract = sftp_handle; + sftp_handle->channel->close_cb = libssh2_sftp_dtor; + + session->sftpInit_state = libssh2_NB_state_idle; + + /* clear the sftp and channel pointers in this session struct now */ + session->sftpInit_sftp = NULL; + session->sftpInit_channel = NULL; + + _libssh2_list_init(&sftp_handle->sftp_handles); + + return sftp_handle; + + sftp_init_error: + while (_libssh2_channel_free(session->sftpInit_channel) == + LIBSSH2_ERROR_EAGAIN); + session->sftpInit_channel = NULL; + if (session->sftpInit_sftp) { + LIBSSH2_FREE(session, session->sftpInit_sftp); + session->sftpInit_sftp = NULL; + } + session->sftpInit_state = libssh2_NB_state_idle; + return NULL; +} + +/* + * libssh2_sftp_init + * + * Startup an SFTP session + */ +LIBSSH2_API LIBSSH2_SFTP *libssh2_sftp_init(LIBSSH2_SESSION *session) +{ + LIBSSH2_SFTP *ptr; + + if(!session) + return NULL; + + if(!(session->state & LIBSSH2_STATE_AUTHENTICATED)) { + _libssh2_error(session, LIBSSH2_ERROR_INVAL, + "session not authenticated yet"); + return NULL; + } + + BLOCK_ADJUST_ERRNO(ptr, session, sftp_init(session)); + return ptr; +} + +/* + * sftp_shutdown + * + * Shutsdown the SFTP subsystem + */ +static int +sftp_shutdown(LIBSSH2_SFTP *sftp) +{ + int rc; + LIBSSH2_SESSION *session = sftp->channel->session; + /* + * Make sure all memory used in the state variables are free + */ + if (sftp->partial_packet) { + LIBSSH2_FREE(session, sftp->partial_packet); + sftp->partial_packet = NULL; + } + if (sftp->open_packet) { + LIBSSH2_FREE(session, sftp->open_packet); + sftp->open_packet = NULL; + } + if (sftp->readdir_packet) { + LIBSSH2_FREE(session, sftp->readdir_packet); + sftp->readdir_packet = NULL; + } + if (sftp->fstat_packet) { + LIBSSH2_FREE(session, sftp->fstat_packet); + sftp->fstat_packet = NULL; + } + if (sftp->unlink_packet) { + LIBSSH2_FREE(session, sftp->unlink_packet); + sftp->unlink_packet = NULL; + } + if (sftp->rename_packet) { + LIBSSH2_FREE(session, sftp->rename_packet); + sftp->rename_packet = NULL; + } + if (sftp->fstatvfs_packet) { + LIBSSH2_FREE(session, sftp->fstatvfs_packet); + sftp->fstatvfs_packet = NULL; + } + if (sftp->statvfs_packet) { + LIBSSH2_FREE(session, sftp->statvfs_packet); + sftp->statvfs_packet = NULL; + } + if (sftp->mkdir_packet) { + LIBSSH2_FREE(session, sftp->mkdir_packet); + sftp->mkdir_packet = NULL; + } + if (sftp->rmdir_packet) { + LIBSSH2_FREE(session, sftp->rmdir_packet); + sftp->rmdir_packet = NULL; + } + if (sftp->stat_packet) { + LIBSSH2_FREE(session, sftp->stat_packet); + sftp->stat_packet = NULL; + } + if (sftp->symlink_packet) { + LIBSSH2_FREE(session, sftp->symlink_packet); + sftp->symlink_packet = NULL; + } + + sftp_packet_flush(sftp); + + /* TODO: We should consider walking over the sftp_handles list and kill + * any remaining sftp handles ... */ + + rc = _libssh2_channel_free(sftp->channel); + + return rc; +} + +/* libssh2_sftp_shutdown + * Shutsdown the SFTP subsystem + */ +LIBSSH2_API int +libssh2_sftp_shutdown(LIBSSH2_SFTP *sftp) +{ + int rc; + if(!sftp) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, sftp->channel->session, sftp_shutdown(sftp)); + return rc; +} + +/* ******************************* + * SFTP File and Directory Ops * + ******************************* */ + +/* sftp_open + */ +static LIBSSH2_SFTP_HANDLE * +sftp_open(LIBSSH2_SFTP *sftp, const char *filename, + size_t filename_len, uint32_t flags, long mode, + int open_type) +{ + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + LIBSSH2_SFTP_HANDLE *fp; + LIBSSH2_SFTP_ATTRIBUTES attrs = { + LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0 + }; + unsigned char *s; + ssize_t rc; + int open_file = (open_type == LIBSSH2_SFTP_OPENFILE)?1:0; + + if (sftp->open_state == libssh2_NB_state_idle) { + /* packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) + + flags(4) */ + sftp->open_packet_len = filename_len + 13 + + (open_file? (4 + sftp_attrsize(LIBSSH2_SFTP_ATTR_PERMISSIONS)) : 0); + + /* surprise! this starts out with nothing sent */ + sftp->open_packet_sent = 0; + s = sftp->open_packet = LIBSSH2_ALLOC(session, sftp->open_packet_len); + if (!sftp->open_packet) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for FXP_OPEN or " + "FXP_OPENDIR packet"); + return NULL; + } + /* Filetype in SFTP 3 and earlier */ + attrs.permissions = mode | + (open_file ? LIBSSH2_SFTP_ATTR_PFILETYPE_FILE : + LIBSSH2_SFTP_ATTR_PFILETYPE_DIR); + + _libssh2_store_u32(&s, sftp->open_packet_len - 4); + *(s++) = open_file? SSH_FXP_OPEN : SSH_FXP_OPENDIR; + sftp->open_request_id = sftp->request_id++; + _libssh2_store_u32(&s, sftp->open_request_id); + _libssh2_store_str(&s, filename, filename_len); + + if (open_file) { + _libssh2_store_u32(&s, flags); + s += sftp_attr2bin(s, &attrs); + } + + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Sending %s open request", + open_file? "file" : "directory"); + + sftp->open_state = libssh2_NB_state_created; + } + + if (sftp->open_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, sftp->open_packet+ + sftp->open_packet_sent, + sftp->open_packet_len - + sftp->open_packet_sent); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block sending FXP_OPEN or FXP_OPENDIR command"); + return NULL; + } + else if(rc < 0) { + _libssh2_error(session, rc, "Unable to send FXP_OPEN*"); + LIBSSH2_FREE(session, sftp->open_packet); + sftp->open_packet = NULL; + sftp->open_state = libssh2_NB_state_idle; + return NULL; + } + + /* bump the sent counter and remain in this state until the whole + data is off */ + sftp->open_packet_sent += rc; + + if(sftp->open_packet_len == sftp->open_packet_sent) { + LIBSSH2_FREE(session, sftp->open_packet); + sftp->open_packet = NULL; + + sftp->open_state = libssh2_NB_state_sent; + } + } + + if (sftp->open_state == libssh2_NB_state_sent) { + size_t data_len; + unsigned char *data; + static const unsigned char fopen_responses[2] = + { SSH_FXP_HANDLE, SSH_FXP_STATUS }; + rc = sftp_packet_requirev(sftp, 2, fopen_responses, + sftp->open_request_id, &data, + &data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block waiting for status message"); + return NULL; + } + sftp->open_state = libssh2_NB_state_idle; + if (rc) { + _libssh2_error(session, rc, "Timeout waiting for status message"); + return NULL; + } + + /* OPEN can basically get STATUS or HANDLE back, where HANDLE implies + a fine response while STATUS means error. It seems though that at + times we get an SSH_FX_OK back in a STATUS, followed the "real" + HANDLE so we need to properly deal with that. */ + if (data[0] == SSH_FXP_STATUS) { + int badness = 1; + + if(data_len < 9) { + _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "Too small FXP_STATUS"); + LIBSSH2_FREE(session, data); + return NULL; + } + + sftp->last_errno = _libssh2_ntohu32(data + 5); + + if(LIBSSH2_FX_OK == sftp->last_errno) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "got HANDLE FXOK!"); + + LIBSSH2_FREE(session, data); + + /* silly situation, but check for a HANDLE */ + rc = sftp_packet_require(sftp, SSH_FXP_HANDLE, + sftp->open_request_id, &data, + &data_len); + if(rc == LIBSSH2_ERROR_EAGAIN) { + /* go back to sent state and wait for something else */ + sftp->open_state = libssh2_NB_state_sent; + return NULL; + } + else if(!rc) + /* we got the handle so this is not a bad situation */ + badness = 0; + } + + if(badness) { + _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "Failed opening remote file"); + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "got FXP_STATUS %d", + sftp->last_errno); + LIBSSH2_FREE(session, data); + return NULL; + } + } + + if(data_len < 10) { + _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "Too small FXP_HANDLE"); + LIBSSH2_FREE(session, data); + return NULL; + } + + fp = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_SFTP_HANDLE)); + if (!fp) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate new SFTP handle structure"); + LIBSSH2_FREE(session, data); + return NULL; + } + memset(fp, 0, sizeof(LIBSSH2_SFTP_HANDLE)); + fp->handle_type = open_file ? LIBSSH2_SFTP_HANDLE_FILE : + LIBSSH2_SFTP_HANDLE_DIR; + + fp->handle_len = _libssh2_ntohu32(data + 5); + if (fp->handle_len > SFTP_HANDLE_MAXLEN) + /* SFTP doesn't allow handles longer than 256 characters */ + fp->handle_len = SFTP_HANDLE_MAXLEN; + + if(fp->handle_len > (data_len - 9)) + /* do not reach beyond the end of the data we got */ + fp->handle_len = data_len - 9; + + memcpy(fp->handle, data + 9, fp->handle_len); + + LIBSSH2_FREE(session, data); + + /* add this file handle to the list kept in the sftp session */ + _libssh2_list_add(&sftp->sftp_handles, &fp->node); + + fp->sftp = sftp; /* point to the parent struct */ + + fp->u.file.offset = 0; + fp->u.file.offset_sent = 0; + + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Open command successful"); + return fp; + } + return NULL; +} + +/* libssh2_sftp_open_ex + */ +LIBSSH2_API LIBSSH2_SFTP_HANDLE * +libssh2_sftp_open_ex(LIBSSH2_SFTP *sftp, const char *filename, + unsigned int filename_len, unsigned long flags, long mode, + int open_type) +{ + LIBSSH2_SFTP_HANDLE *hnd; + + if(!sftp) + return NULL; + + BLOCK_ADJUST_ERRNO(hnd, sftp->channel->session, + sftp_open(sftp, filename, filename_len, flags, mode, + open_type)); + return hnd; +} + +/* + * sftp_read + * + * Read from an SFTP file handle + * + */ +static ssize_t sftp_read(LIBSSH2_SFTP_HANDLE * handle, char *buffer, + size_t buffer_size) +{ + LIBSSH2_SFTP *sftp = handle->sftp; + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t count = 0; + struct sftp_pipeline_chunk *chunk; + struct sftp_pipeline_chunk *next; + ssize_t rc; + struct _libssh2_sftp_handle_file_data *filep = + &handle->u.file; + + /* This function can be interrupted in three different places where it + might need to wait for data from the network. It returns EAGAIN to + allow non-blocking clients to do other work but these client are + expected to call this function again (possibly many times) to finish + the operation. + + The tricky part is that if we previously aborted a sftp_read due to + EAGAIN, we must continue at the same spot to continue the previously + interrupted operation. This is done using a state machine to record + what phase of execution we were at. The state is stored in + sftp->read_state. + + libssh2_NB_state_idle: The first phase is where we prepare multiple + FXP_READ packets to do optimistic read-ahead. We send off as many as + possible in the second phase without waiting for a response to each + one; this is the key to fast reads. But we may have to adjust the + channel window size to do this which may interrupt this function while + waiting. The state machine saves the phase as libssh2_NB_state_idle so + it returns here on the next call. + + libssh2_NB_state_sent: The second phase is where we send the FXP_READ + packets. Writing them to the channel can be interrupted with EAGAIN + but the state machine ensures we skip the first phase on the next call + and resume sending. + + libssh2_NB_state_sent2: In the third phase (indicated by ) we read the + data from the responses that have arrived so far. Reading can be + interrupted with EAGAIN but the state machine ensures we skip the first + and second phases on the next call and resume sending. + */ + + switch (sftp->read_state) { + case libssh2_NB_state_idle: + + /* Some data may already have been read from the server in the + previous call but didn't fit in the buffer at the time. If so, we + return that now as we can't risk being interrupted later with data + partially written to the buffer. */ + if(filep->data_left) { + size_t copy = MIN(buffer_size, filep->data_left); + + memcpy(buffer, &filep->data[ filep->data_len - filep->data_left], + copy); + + filep->data_left -= copy; + filep->offset += copy; + + if(!filep->data_left) { + LIBSSH2_FREE(session, filep->data); + filep->data = NULL; + } + + return copy; + } + + /* We allow a number of bytes being requested at any given time + without having been acked - until we reach EOF. */ + if(!filep->eof) { + /* Number of bytes asked for that haven't been acked yet */ + size_t already = (filep->offset_sent - filep->offset); + + size_t max_read_ahead = buffer_size*4; + unsigned long recv_window; + + if(max_read_ahead > LIBSSH2_CHANNEL_WINDOW_DEFAULT*4) + max_read_ahead = LIBSSH2_CHANNEL_WINDOW_DEFAULT*4; + + /* if the buffer_size passed in now is smaller than what has + already been sent, we risk getting count become a very large + number */ + if(max_read_ahead > already) + count = max_read_ahead - already; + + /* 'count' is how much more data to ask for, and 'already' is how + much data that already has been asked for but not yet returned. + Specificly, 'count' means how much data that have or will be + asked for by the nodes that are already added to the linked + list. Some of those read requests may not actually have been + sent off successfully yet. + + If 'already' is very large it should be perfectly fine to have + count set to 0 as then we don't have to ask for more data + (right now). + + buffer_size*4 is just picked more or less out of the air. The + idea is that when reading SFTP from a remote server, we send + away multiple read requests guessing that the client will read + more than only this 'buffer_size' amount of memory. So we ask + for maximum buffer_size*4 amount of data so that we can return + them very fast in subsequent calls. + */ + + recv_window = libssh2_channel_window_read_ex(sftp->channel, + NULL, NULL); + if(max_read_ahead > recv_window) { + /* more data will be asked for than what the window currently + allows, expand it! */ + + rc = _libssh2_channel_receive_window_adjust(sftp->channel, + max_read_ahead*8, + 1, NULL); + /* if this returns EAGAIN, we will get back to this function + at next call */ + assert(rc != LIBSSH2_ERROR_EAGAIN || !filep->data_left); + assert(rc != LIBSSH2_ERROR_EAGAIN || !filep->eof); + if (rc) + return rc; + } + } + + while(count > 0) { + unsigned char *s; + uint32_t size = MIN(MAX_SFTP_READ_SIZE, count); + + /* 25 = packet_len(4) + packet_type(1) + request_id(4) + + handle_len(4) + offset(8) + count(4) */ + uint32_t packet_len = (uint32_t)handle->handle_len + 25; + uint32_t request_id; + + chunk = LIBSSH2_ALLOC(session, packet_len + + sizeof(struct sftp_pipeline_chunk)); + if (!chunk) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "malloc fail for FXP_WRITE"); + + chunk->len = size; + chunk->lefttosend = packet_len; + chunk->sent = 0; + + s = chunk->packet; + + _libssh2_store_u32(&s, packet_len - 4); + *s++ = SSH_FXP_READ; + request_id = sftp->request_id++; + chunk->request_id = request_id; + _libssh2_store_u32(&s, request_id); + _libssh2_store_str(&s, handle->handle, handle->handle_len); + _libssh2_store_u64(&s, filep->offset_sent); + filep->offset_sent += size; /* advance offset at once */ + _libssh2_store_u32(&s, size); + + /* add this new entry LAST in the list */ + _libssh2_list_add(&handle->packet_list, &chunk->node); + count -= size; /* deduct the size we used, as we might have + to create more packets */ + } + + case libssh2_NB_state_sent: + + sftp->read_state = libssh2_NB_state_idle; + + /* move through the READ packets that haven't been sent and send as + many as possible - remember that we don't block */ + chunk = _libssh2_list_first(&handle->packet_list); + + while(chunk) { + if(chunk->lefttosend) { + + rc = _libssh2_channel_write(channel, 0, + &chunk->packet[chunk->sent], + chunk->lefttosend); + if(rc < 0) { + sftp->read_state = libssh2_NB_state_sent; + return rc; + } + + /* remember where to continue sending the next time */ + chunk->lefttosend -= rc; + chunk->sent += rc; + + if(chunk->lefttosend) + /* data left to send, get out of loop */ + break; + } + + /* move on to the next chunk with data to send */ + chunk = _libssh2_list_next(&chunk->node); + } + + case libssh2_NB_state_sent2: + + sftp->read_state = libssh2_NB_state_idle; + + /* + * Count all ACKed packets and act on the contents of them. + */ + chunk = _libssh2_list_first(&handle->packet_list); + + while(chunk) { + unsigned char *data; + size_t data_len; + uint32_t rc32; + static const unsigned char read_responses[2] = { + SSH_FXP_DATA, SSH_FXP_STATUS + }; + + if(chunk->lefttosend) + /* if the chunk still has data left to send, we shouldn't wait + for an ACK for it just yet */ + break; + + rc = sftp_packet_requirev(sftp, 2, read_responses, + chunk->request_id, &data, &data_len); + if (rc < 0) { + sftp->read_state = libssh2_NB_state_sent2; + return rc; + } + + /* + * We get DATA or STATUS back. STATUS can be error, or it is + * FX_EOF when we reach the end of the file. + */ + + switch (data[0]) { + case SSH_FXP_STATUS: + /* remove the chunk we just processed keeping track of the + * next one in case we need it */ + next = _libssh2_list_next(&chunk->node); + _libssh2_list_remove(&chunk->node); + LIBSSH2_FREE(session, chunk); + + /* we must remove all outstanding READ requests, as either we + got an error or we're at end of file */ + sftp_packetlist_flush(handle); + + rc32 = _libssh2_ntohu32(data + 5); + LIBSSH2_FREE(session, data); + + if (rc32 == LIBSSH2_FX_EOF) { + filep->eof = TRUE; + return 0; + } + else { + sftp->last_errno = rc32; + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP READ error"); + } + break; + + case SSH_FXP_DATA: + rc32 = _libssh2_ntohu32(data + 5); + if (rc32 > (data_len - 9)) + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol badness"); + + if(rc32 != chunk->len) { + /* a short read does not imply end of file, but we must + adjust the offset_sent since it was advanced with a + full chunk->len before */ + filep->offset_sent -= (chunk->len - rc32); + } + + if(rc32 > buffer_size) { + /* figure out the overlap amount */ + filep->data_left = rc32 - buffer_size; + + /* getting the full packet would overflow the buffer, so + only get the correct amount and keep the remainder */ + rc32 = (uint32_t)buffer_size; + + /* store data to keep for next call */ + filep->data = data; + filep->data_len = data_len; + } + else + filep->data_len = 0; + + /* copy the received data from the received FXP_DATA packet to + the buffer at the correct index */ + memcpy(buffer, data + 9, rc32); + filep->offset += rc32; + + if(filep->data_len == 0) + /* free the allocated data if not stored to keep */ + LIBSSH2_FREE(session, data); + + + /* remove the chunk we just processed keeping track of the + * next one in case we need it */ + next = _libssh2_list_next(&chunk->node); + _libssh2_list_remove(&chunk->node); + LIBSSH2_FREE(session, chunk); + chunk = NULL; + + if(rc32 > 0) { + /* we must return as we wrote some data to the buffer */ + return rc32; + } else { + /* A zero-byte read is not necessarily EOF so we must not + * return 0 (that would signal EOF to the caller) so + * instead we carry on to the next chunk */ + chunk = next; + } + + break; + default: + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol badness: unrecognised " + "read request response"); + } + } + + break; + + default: + assert(!"State machine error; unrecognised read state"); + } + + return 0; +} + +/* libssh2_sftp_read + * Read from an SFTP file handle + */ +LIBSSH2_API ssize_t +libssh2_sftp_read(LIBSSH2_SFTP_HANDLE *hnd, char *buffer, + size_t buffer_maxlen) +{ + ssize_t rc; + if(!hnd) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, hnd->sftp->channel->session, + sftp_read(hnd, buffer, buffer_maxlen)); + return rc; +} + +/* sftp_readdir + * Read from an SFTP directory handle + */ +static ssize_t sftp_readdir(LIBSSH2_SFTP_HANDLE *handle, char *buffer, + size_t buffer_maxlen, char *longentry, + size_t longentry_maxlen, + LIBSSH2_SFTP_ATTRIBUTES *attrs) +{ + LIBSSH2_SFTP *sftp = handle->sftp; + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len; + uint32_t num_names; + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ + uint32_t packet_len = handle->handle_len + 13; + unsigned char *s, *data; + static const unsigned char read_responses[2] = { + SSH_FXP_NAME, SSH_FXP_STATUS }; + ssize_t retcode; + + if (sftp->readdir_state == libssh2_NB_state_idle) { + if (handle->u.dir.names_left) { + /* + * A prior request returned more than one directory entry, + * feed it back from the buffer + */ + LIBSSH2_SFTP_ATTRIBUTES attrs_dummy; + size_t real_longentry_len; + size_t real_filename_len; + size_t filename_len; + size_t longentry_len; + + s = (unsigned char *) handle->u.dir.next_name; + real_filename_len = _libssh2_ntohu32(s); + + s += 4; + + filename_len = real_filename_len; + if (filename_len >= buffer_maxlen) { + filename_len = LIBSSH2_ERROR_BUFFER_TOO_SMALL; + goto end; + } + + memcpy(buffer, s, filename_len); + buffer[filename_len] = '\0'; /* zero terminate */ + s += real_filename_len; + + real_longentry_len = _libssh2_ntohu32(s); + s += 4; + + if (longentry && (longentry_maxlen>1)) { + longentry_len = real_longentry_len; + + if (longentry_len >= longentry_maxlen) { + filename_len = LIBSSH2_ERROR_BUFFER_TOO_SMALL; + goto end; + } + + memcpy(longentry, s, longentry_len); + longentry[longentry_len] = '\0'; /* zero terminate */ + } + s += real_longentry_len; + + if (attrs) + memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); + + s += sftp_bin2attr(attrs ? attrs : &attrs_dummy, s); + + handle->u.dir.next_name = (char *) s; + end: + + if ((--handle->u.dir.names_left) == 0) + LIBSSH2_FREE(session, handle->u.dir.names_packet); + + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "libssh2_sftp_readdir_ex() return %d", + filename_len); + return (ssize_t)filename_len; + } + + /* Request another entry(entries?) */ + + s = sftp->readdir_packet = LIBSSH2_ALLOC(session, packet_len); + if (!sftp->readdir_packet) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "FXP_READDIR packet"); + + _libssh2_store_u32(&s, packet_len - 4); + *(s++) = SSH_FXP_READDIR; + sftp->readdir_request_id = sftp->request_id++; + _libssh2_store_u32(&s, sftp->readdir_request_id); + _libssh2_store_str(&s, handle->handle, handle->handle_len); + + sftp->readdir_state = libssh2_NB_state_created; + } + + if (sftp->readdir_state == libssh2_NB_state_created) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "Reading entries from directory handle"); + retcode = _libssh2_channel_write(channel, 0, sftp->readdir_packet, + packet_len); + if (retcode == LIBSSH2_ERROR_EAGAIN) { + return retcode; + } + else if ((ssize_t)packet_len != retcode) { + LIBSSH2_FREE(session, sftp->readdir_packet); + sftp->readdir_packet = NULL; + sftp->readdir_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "_libssh2_channel_write() failed"); + } + + LIBSSH2_FREE(session, sftp->readdir_packet); + sftp->readdir_packet = NULL; + + sftp->readdir_state = libssh2_NB_state_sent; + } + + retcode = sftp_packet_requirev(sftp, 2, read_responses, + sftp->readdir_request_id, &data, + &data_len); + if (retcode == LIBSSH2_ERROR_EAGAIN) + return retcode; + else if (retcode) { + sftp->readdir_state = libssh2_NB_state_idle; + return _libssh2_error(session, retcode, + "Timeout waiting for status message"); + } + + if (data[0] == SSH_FXP_STATUS) { + retcode = _libssh2_ntohu32(data + 5); + LIBSSH2_FREE(session, data); + if (retcode == LIBSSH2_FX_EOF) { + sftp->readdir_state = libssh2_NB_state_idle; + return 0; + } + else { + sftp->last_errno = retcode; + sftp->readdir_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error"); + } + } + + sftp->readdir_state = libssh2_NB_state_idle; + + num_names = _libssh2_ntohu32(data + 5); + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%lu entries returned", + num_names); + if (!num_names) { + LIBSSH2_FREE(session, data); + return 0; + } + + handle->u.dir.names_left = num_names; + handle->u.dir.names_packet = data; + handle->u.dir.next_name = (char *) data + 9; + + /* use the name popping mechanism from the start of the function */ + return sftp_readdir(handle, buffer, buffer_maxlen, longentry, + longentry_maxlen, attrs); +} + +/* libssh2_sftp_readdir_ex + * Read from an SFTP directory handle + */ +LIBSSH2_API int +libssh2_sftp_readdir_ex(LIBSSH2_SFTP_HANDLE *hnd, char *buffer, + size_t buffer_maxlen, char *longentry, + size_t longentry_maxlen, + LIBSSH2_SFTP_ATTRIBUTES *attrs) +{ + int rc; + if(!hnd) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, hnd->sftp->channel->session, + sftp_readdir(hnd, buffer, buffer_maxlen, longentry, + longentry_maxlen, attrs)); + return rc; +} + +/* + * sftp_write + * + * Write data to an SFTP handle. Returns the number of bytes written, or + * a negative error code. + * + * We recommend sending very large data buffers to this function! + * + * Concept: + * + * - Detect how much of the given buffer that was already sent in a previous + * call by inspecting the linked list of outgoing chunks. Make sure to skip + * passed the data that has already been taken care of. + * + * - Split all (new) outgoing data in chunks no larger than N. + * + * - Each N bytes chunk gets created as a separate SFTP packet. + * + * - Add all created outgoing packets to the linked list. + * + * - Walk through the list and send the chunks that haven't been sent, + * as many as possible until EAGAIN. Some of the chunks may have been put + * in the list in a previous invoke. + * + * - For all the chunks in the list that have been completely sent off, check + * for ACKs. If a chunk has been ACKed, it is removed from the linked + * list and the "acked" counter gets increased with that data amount. + * + * - Return TOTAL bytes acked so far. + * + * Caveats: + * - be careful: we must not return a higher number than what was given! + * + * TODO: + * Introduce an option that disables this sort of "speculative" ahead writing + * as there's a risk that it will do harm to some app. + */ + +static ssize_t sftp_write(LIBSSH2_SFTP_HANDLE *handle, const char *buffer, + size_t count) +{ + LIBSSH2_SFTP *sftp = handle->sftp; + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len; + uint32_t retcode; + uint32_t packet_len; + unsigned char *s, *data; + ssize_t rc; + struct sftp_pipeline_chunk *chunk; + struct sftp_pipeline_chunk *next; + size_t acked = 0; + size_t org_count = count; + size_t already; + + switch(sftp->write_state) { + default: + case libssh2_NB_state_idle: + + /* Number of bytes sent off that haven't been acked and therefor we + will get passed in here again. + + Also, add up the number of bytes that actually already have been + acked but we haven't been able to return as such yet, so we will + get that data as well passed in here again. + */ + already = (handle->u.file.offset_sent - handle->u.file.offset)+ + handle->u.file.acked; + + if(count >= already) { + /* skip the part already made into packets */ + buffer += already; + count -= already; + } + else + /* there is more data already fine than what we got in this call */ + count = 0; + + sftp->write_state = libssh2_NB_state_idle; + while(count) { + /* TODO: Possibly this should have some logic to prevent a very + very small fraction to be left but lets ignore that for now */ + uint32_t size = MIN(MAX_SFTP_OUTGOING_SIZE, count); + uint32_t request_id; + + /* 25 = packet_len(4) + packet_type(1) + request_id(4) + + handle_len(4) + offset(8) + count(4) */ + packet_len = handle->handle_len + size + 25; + + chunk = LIBSSH2_ALLOC(session, packet_len + + sizeof(struct sftp_pipeline_chunk)); + if (!chunk) + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "malloc fail for FXP_WRITE"); + + chunk->len = size; + chunk->sent = 0; + chunk->lefttosend = packet_len; + + s = chunk->packet; + _libssh2_store_u32(&s, packet_len - 4); + + *(s++) = SSH_FXP_WRITE; + request_id = sftp->request_id++; + chunk->request_id = request_id; + _libssh2_store_u32(&s, request_id); + _libssh2_store_str(&s, handle->handle, handle->handle_len); + _libssh2_store_u64(&s, handle->u.file.offset_sent); + handle->u.file.offset_sent += size; /* advance offset at once */ + _libssh2_store_str(&s, buffer, size); + + /* add this new entry LAST in the list */ + _libssh2_list_add(&handle->packet_list, &chunk->node); + + buffer += size; + count -= size; /* deduct the size we used, as we might have + to create more packets */ + } + + /* move through the WRITE packets that haven't been sent and send as many + as possible - remember that we don't block */ + chunk = _libssh2_list_first(&handle->packet_list); + + while(chunk) { + if(chunk->lefttosend) { + rc = _libssh2_channel_write(channel, 0, + &chunk->packet[chunk->sent], + chunk->lefttosend); + if(rc < 0) + /* remain in idle state */ + return rc; + + /* remember where to continue sending the next time */ + chunk->lefttosend -= rc; + chunk->sent += rc; + + if(chunk->lefttosend) + /* data left to send, get out of loop */ + break; + } + + /* move on to the next chunk with data to send */ + chunk = _libssh2_list_next(&chunk->node); + } + + /* fall-through */ + case libssh2_NB_state_sent: + + sftp->write_state = libssh2_NB_state_idle; + /* + * Count all ACKed packets + */ + chunk = _libssh2_list_first(&handle->packet_list); + + while(chunk) { + if(chunk->lefttosend) + /* if the chunk still has data left to send, we shouldn't wait + for an ACK for it just yet */ + break; + + else if(acked) + /* if we have sent data that is acked, we must return that + info before we call a function that might return EAGAIN */ + break; + + /* we check the packets in order */ + rc = sftp_packet_require(sftp, SSH_FXP_STATUS, + chunk->request_id, &data, &data_len); + if (rc < 0) { + if (rc == LIBSSH2_ERROR_EAGAIN) + sftp->write_state = libssh2_NB_state_sent; + return rc; + } + + retcode = _libssh2_ntohu32(data + 5); + LIBSSH2_FREE(session, data); + + sftp->last_errno = retcode; + if (retcode == LIBSSH2_FX_OK) { + acked += chunk->len; /* number of payload data that was acked + here */ + + /* we increase the offset value for all acks */ + handle->u.file.offset += chunk->len; + + next = _libssh2_list_next(&chunk->node); + + _libssh2_list_remove(&chunk->node); /* remove from list */ + LIBSSH2_FREE(session, chunk); /* free memory */ + + chunk = next; + } + else { + /* flush all pending packets from the outgoing list */ + sftp_packetlist_flush(handle); + + /* since we return error now, the applicaton will not get any + outstanding data acked, so we need to rewind the offset to + where the application knows it has reached with acked data */ + handle->u.file.offset -= handle->u.file.acked; + + /* then reset the offset_sent to be the same as the offset */ + handle->u.file.offset_sent = handle->u.file.offset; + + /* clear the acked counter since we can have no pending data to + ack after an error */ + handle->u.file.acked = 0; + + /* the server returned an error for that written chunk, propagate + this back to our parent function */ + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "FXP write failed"); + } + } + break; + } + + /* if there were acked data in a previous call that wasn't returned then, + add that up and try to return it all now. This can happen if the app + first sends a huge buffer of data, and then in a second call it sends a + smaller one. */ + acked += handle->u.file.acked; + + if(acked) { + ssize_t ret = MIN(acked, org_count); + /* we got data acked so return that amount, but no more than what + was asked to get sent! */ + + /* store the remainder. 'ret' is always equal to or less than 'acked' + here */ + handle->u.file.acked = acked - ret; + + return ret; + } + + else + return 0; /* nothing was acked, and no EAGAIN was received! */ +} + +/* libssh2_sftp_write + * Write data to a file handle + */ +LIBSSH2_API ssize_t +libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *hnd, const char *buffer, + size_t count) +{ + ssize_t rc; + if(!hnd) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, hnd->sftp->channel->session, + sftp_write(hnd, buffer, count)); + return rc; + +} + +/* + * sftp_fstat + * + * Get or Set stat on a file + */ +static int sftp_fstat(LIBSSH2_SFTP_HANDLE *handle, + LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat) +{ + LIBSSH2_SFTP *sftp = handle->sftp; + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len; + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ + uint32_t packet_len = + handle->handle_len + 13 + (setstat ? sftp_attrsize(attrs->flags) : 0); + unsigned char *s, *data; + static const unsigned char fstat_responses[2] = + { SSH_FXP_ATTRS, SSH_FXP_STATUS }; + ssize_t rc; + + if (sftp->fstat_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Issuing %s command", + setstat ? "set-stat" : "stat"); + s = sftp->fstat_packet = LIBSSH2_ALLOC(session, packet_len); + if (!sftp->fstat_packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "FSTAT/FSETSTAT packet"); + } + + _libssh2_store_u32(&s, packet_len - 4); + *(s++) = setstat ? SSH_FXP_FSETSTAT : SSH_FXP_FSTAT; + sftp->fstat_request_id = sftp->request_id++; + _libssh2_store_u32(&s, sftp->fstat_request_id); + _libssh2_store_str(&s, handle->handle, handle->handle_len); + + if (setstat) { + s += sftp_attr2bin(s, attrs); + } + + sftp->fstat_state = libssh2_NB_state_created; + } + + if (sftp->fstat_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, sftp->fstat_packet, + packet_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + else if ((ssize_t)packet_len != rc) { + LIBSSH2_FREE(session, sftp->fstat_packet); + sftp->fstat_packet = NULL; + sftp->fstat_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + (setstat ? "Unable to send FXP_FSETSTAT" + : "Unable to send FXP_FSTAT command")); + } + LIBSSH2_FREE(session, sftp->fstat_packet); + sftp->fstat_packet = NULL; + + sftp->fstat_state = libssh2_NB_state_sent; + } + + rc = sftp_packet_requirev(sftp, 2, fstat_responses, + sftp->fstat_request_id, &data, + &data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + else if (rc) { + sftp->fstat_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Timeout waiting for status message"); + } + + sftp->fstat_state = libssh2_NB_state_idle; + + if (data[0] == SSH_FXP_STATUS) { + uint32_t retcode; + + retcode = _libssh2_ntohu32(data + 5); + LIBSSH2_FREE(session, data); + if (retcode == LIBSSH2_FX_OK) { + return 0; + } else { + sftp->last_errno = retcode; + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error"); + } + } + + sftp_bin2attr(attrs, data + 5); + LIBSSH2_FREE(session, data); + + return 0; +} + +/* libssh2_sftp_fstat_ex + * Get or Set stat on a file + */ +LIBSSH2_API int +libssh2_sftp_fstat_ex(LIBSSH2_SFTP_HANDLE *hnd, + LIBSSH2_SFTP_ATTRIBUTES *attrs, int setstat) +{ + int rc; + if(!hnd || !attrs) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, hnd->sftp->channel->session, + sftp_fstat(hnd, attrs, setstat)); + return rc; +} + + +/* libssh2_sftp_seek64 + * Set the read/write pointer to an arbitrary position within the file + */ +LIBSSH2_API void +libssh2_sftp_seek64(LIBSSH2_SFTP_HANDLE *handle, libssh2_uint64_t offset) +{ + if(handle) { + handle->u.file.offset = handle->u.file.offset_sent = offset; + /* discard all pending requests and currently read data */ + sftp_packetlist_flush(handle); + + /* free the left received buffered data */ + if (handle->u.file.data_left) { + LIBSSH2_FREE(handle->sftp->channel->session, handle->u.file.data); + handle->u.file.data_left = handle->u.file.data_len = 0; + handle->u.file.data = NULL; + } + + /* reset EOF to False */ + handle->u.file.eof = FALSE; + } +} + +/* libssh2_sftp_seek + * Set the read/write pointer to an arbitrary position within the file + */ +LIBSSH2_API void +libssh2_sftp_seek(LIBSSH2_SFTP_HANDLE *handle, size_t offset) +{ + libssh2_sftp_seek64(handle, (libssh2_uint64_t)offset); +} + +/* libssh2_sftp_tell + * Return the current read/write pointer's offset + */ +LIBSSH2_API size_t +libssh2_sftp_tell(LIBSSH2_SFTP_HANDLE *handle) +{ + if(!handle) + return 0; /* no handle, no size */ + + /* NOTE: this may very well truncate the size if it is larger than what + size_t can hold, so libssh2_sftp_tell64() is really the function you + should use */ + return (size_t)(handle->u.file.offset); +} + +/* libssh2_sftp_tell64 + * Return the current read/write pointer's offset + */ +LIBSSH2_API libssh2_uint64_t +libssh2_sftp_tell64(LIBSSH2_SFTP_HANDLE *handle) +{ + if(!handle) + return 0; /* no handle, no size */ + + return handle->u.file.offset; +} + +/* + * Flush all remaining incoming SFTP packets and zombies. + */ +static void sftp_packet_flush(LIBSSH2_SFTP *sftp) +{ + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + LIBSSH2_SFTP_PACKET *packet = _libssh2_list_first(&sftp->packets); + struct sftp_zombie_requests *zombie = + _libssh2_list_first(&sftp->zombie_requests); + + while(packet) { + LIBSSH2_SFTP_PACKET *next; + + /* check next struct in the list */ + next = _libssh2_list_next(&packet->node); + _libssh2_list_remove(&packet->node); + LIBSSH2_FREE(session, packet->data); + LIBSSH2_FREE(session, packet); + + packet = next; + } + + while(zombie) { + /* figure out the next node */ + struct sftp_zombie_requests *next = _libssh2_list_next(&zombie->node); + /* unlink the current one */ + _libssh2_list_remove(&zombie->node); + /* free the memory */ + LIBSSH2_FREE(session, zombie); + zombie = next; + } + +} + +/* sftp_close_handle + * + * Close a file or directory handle + * Also frees handle resource and unlinks it from the SFTP structure + */ +static int +sftp_close_handle(LIBSSH2_SFTP_HANDLE *handle) +{ + LIBSSH2_SFTP *sftp = handle->sftp; + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len; + int retcode; + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + handle_len(4) */ + uint32_t packet_len = handle->handle_len + 13; + unsigned char *s, *data = NULL; + int rc; + + if (handle->close_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Closing handle"); + s = handle->close_packet = LIBSSH2_ALLOC(session, packet_len); + if (!handle->close_packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for FXP_CLOSE " + "packet"); + } + + _libssh2_store_u32(&s, packet_len - 4); + *(s++) = SSH_FXP_CLOSE; + handle->close_request_id = sftp->request_id++; + _libssh2_store_u32(&s, handle->close_request_id); + _libssh2_store_str(&s, handle->handle, handle->handle_len); + handle->close_state = libssh2_NB_state_created; + } + + if (handle->close_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, handle->close_packet, + packet_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if ((ssize_t)packet_len != rc) { + LIBSSH2_FREE(session, handle->close_packet); + handle->close_packet = NULL; + handle->close_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send FXP_CLOSE command"); + } + LIBSSH2_FREE(session, handle->close_packet); + handle->close_packet = NULL; + + handle->close_state = libssh2_NB_state_sent; + } + + if (handle->close_state == libssh2_NB_state_sent) { + rc = sftp_packet_require(sftp, SSH_FXP_STATUS, + handle->close_request_id, &data, + &data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + handle->close_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Error waiting for status message"); + } + + handle->close_state = libssh2_NB_state_sent1; + } + + if(!data) + /* if it reaches this point with data unset, something unwanted + happened (like this function is called again when in + libssh2_NB_state_sent1 state) and we just bail out */ + return LIBSSH2_ERROR_INVAL; + + retcode = _libssh2_ntohu32(data + 5); + LIBSSH2_FREE(session, data); + + if (retcode != LIBSSH2_FX_OK) { + sftp->last_errno = retcode; + handle->close_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error"); + } + + /* remove this handle from the parent's list */ + _libssh2_list_remove(&handle->node); + + if ((handle->handle_type == LIBSSH2_SFTP_HANDLE_DIR) + && handle->u.dir.names_left) { + LIBSSH2_FREE(session, handle->u.dir.names_packet); + } + else { + if(handle->u.file.data) + LIBSSH2_FREE(session, handle->u.file.data); + } + + sftp_packetlist_flush(handle); + sftp->read_state = libssh2_NB_state_idle; + + handle->close_state = libssh2_NB_state_idle; + + LIBSSH2_FREE(session, handle); + + return 0; +} + +/* libssh2_sftp_close_handle + * + * Close a file or directory handle + * Also frees handle resource and unlinks it from the SFTP structure + */ +LIBSSH2_API int +libssh2_sftp_close_handle(LIBSSH2_SFTP_HANDLE *hnd) +{ + int rc; + if(!hnd) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, hnd->sftp->channel->session, sftp_close_handle(hnd)); + return rc; +} + +/* sftp_unlink + * Delete a file from the remote server + */ +static int sftp_unlink(LIBSSH2_SFTP *sftp, const char *filename, + size_t filename_len) +{ + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len; + int retcode; + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + filename_len(4) */ + uint32_t packet_len = filename_len + 13; + unsigned char *s, *data; + int rc; + + if (sftp->unlink_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Unlinking %s", filename); + s = sftp->unlink_packet = LIBSSH2_ALLOC(session, packet_len); + if (!sftp->unlink_packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for FXP_REMOVE " + "packet"); + } + + _libssh2_store_u32(&s, packet_len - 4); + *(s++) = SSH_FXP_REMOVE; + sftp->unlink_request_id = sftp->request_id++; + _libssh2_store_u32(&s, sftp->unlink_request_id); + _libssh2_store_str(&s, filename, filename_len); + sftp->unlink_state = libssh2_NB_state_created; + } + + if (sftp->unlink_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, sftp->unlink_packet, + packet_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if ((ssize_t)packet_len != rc) { + LIBSSH2_FREE(session, sftp->unlink_packet); + sftp->unlink_packet = NULL; + sftp->unlink_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send FXP_REMOVE command"); + } + LIBSSH2_FREE(session, sftp->unlink_packet); + sftp->unlink_packet = NULL; + + sftp->unlink_state = libssh2_NB_state_sent; + } + + rc = sftp_packet_require(sftp, SSH_FXP_STATUS, + sftp->unlink_request_id, &data, + &data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } + else if (rc) { + sftp->unlink_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Error waiting for FXP STATUS"); + } + + sftp->unlink_state = libssh2_NB_state_idle; + + retcode = _libssh2_ntohu32(data + 5); + LIBSSH2_FREE(session, data); + + if (retcode == LIBSSH2_FX_OK) { + return 0; + } else { + sftp->last_errno = retcode; + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error"); + } +} + +/* libssh2_sftp_unlink_ex + * Delete a file from the remote server + */ +LIBSSH2_API int +libssh2_sftp_unlink_ex(LIBSSH2_SFTP *sftp, const char *filename, + unsigned int filename_len) +{ + int rc; + if(!sftp) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, sftp->channel->session, + sftp_unlink(sftp, filename, filename_len)); + return rc; +} + +/* + * sftp_rename + * + * Rename a file on the remote server + */ +static int sftp_rename(LIBSSH2_SFTP *sftp, const char *source_filename, + unsigned int source_filename_len, + const char *dest_filename, + unsigned int dest_filename_len, long flags) +{ + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len; + int retcode; + uint32_t packet_len = + source_filename_len + dest_filename_len + 17 + (sftp->version >= + 5 ? 4 : 0); + /* packet_len(4) + packet_type(1) + request_id(4) + + source_filename_len(4) + dest_filename_len(4) + flags(4){SFTP5+) */ + unsigned char *data; + ssize_t rc; + + if (sftp->version < 2) { + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "Server does not support RENAME"); + } + + if (sftp->rename_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Renaming %s to %s", + source_filename, dest_filename); + sftp->rename_s = sftp->rename_packet = + LIBSSH2_ALLOC(session, packet_len); + if (!sftp->rename_packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for FXP_RENAME " + "packet"); + } + + _libssh2_store_u32(&sftp->rename_s, packet_len - 4); + *(sftp->rename_s++) = SSH_FXP_RENAME; + sftp->rename_request_id = sftp->request_id++; + _libssh2_store_u32(&sftp->rename_s, sftp->rename_request_id); + _libssh2_store_str(&sftp->rename_s, source_filename, + source_filename_len); + _libssh2_store_str(&sftp->rename_s, dest_filename, dest_filename_len); + + if (sftp->version >= 5) + _libssh2_store_u32(&sftp->rename_s, flags); + + sftp->rename_state = libssh2_NB_state_created; + } + + if (sftp->rename_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, sftp->rename_packet, + sftp->rename_s - sftp->rename_packet); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if ((ssize_t)packet_len != rc) { + LIBSSH2_FREE(session, sftp->rename_packet); + sftp->rename_packet = NULL; + sftp->rename_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send FXP_RENAME command"); + } + LIBSSH2_FREE(session, sftp->rename_packet); + sftp->rename_packet = NULL; + + sftp->rename_state = libssh2_NB_state_sent; + } + + rc = sftp_packet_require(sftp, SSH_FXP_STATUS, + sftp->rename_request_id, &data, + &data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + sftp->rename_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Error waiting for FXP STATUS"); + } + + sftp->rename_state = libssh2_NB_state_idle; + + retcode = _libssh2_ntohu32(data + 5); + LIBSSH2_FREE(session, data); + + sftp->last_errno = retcode; + + /* now convert the SFTP error code to libssh2 return code or error + message */ + switch (retcode) { + case LIBSSH2_FX_OK: + retcode = LIBSSH2_ERROR_NONE; + break; + + case LIBSSH2_FX_FILE_ALREADY_EXISTS: + retcode = _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "File already exists and " + "SSH_FXP_RENAME_OVERWRITE not specified"); + break; + + case LIBSSH2_FX_OP_UNSUPPORTED: + retcode = _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "Operation Not Supported"); + break; + + default: + retcode = _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error"); + break; + } + + return retcode; +} + +/* libssh2_sftp_rename_ex + * Rename a file on the remote server + */ +LIBSSH2_API int +libssh2_sftp_rename_ex(LIBSSH2_SFTP *sftp, const char *source_filename, + unsigned int source_filename_len, + const char *dest_filename, + unsigned int dest_filename_len, long flags) +{ + int rc; + if(!sftp) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, sftp->channel->session, + sftp_rename(sftp, source_filename, source_filename_len, + dest_filename, dest_filename_len, flags)); + return rc; +} + +/* + * sftp_fstatvfs + * + * Get file system statistics + */ +static int sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) +{ + LIBSSH2_SFTP *sftp = handle->sftp; + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len; + /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) + + handle_len (4) */ + /* 20 = strlen ("fstatvfs@openssh.com") */ + uint32_t packet_len = handle->handle_len + 20 + 17; + unsigned char *packet, *s, *data; + ssize_t rc; + unsigned int flag; + + if (sftp->fstatvfs_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "Getting file system statistics"); + s = packet = LIBSSH2_ALLOC(session, packet_len); + if (!packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for FXP_EXTENDED " + "packet"); + } + + _libssh2_store_u32(&s, packet_len - 4); + *(s++) = SSH_FXP_EXTENDED; + sftp->fstatvfs_request_id = sftp->request_id++; + _libssh2_store_u32(&s, sftp->fstatvfs_request_id); + _libssh2_store_str(&s, "fstatvfs@openssh.com", 20); + _libssh2_store_str(&s, handle->handle, handle->handle_len); + + sftp->fstatvfs_state = libssh2_NB_state_created; + } + else { + packet = sftp->fstatvfs_packet; + } + + if (sftp->fstatvfs_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, packet, packet_len); + if (rc == LIBSSH2_ERROR_EAGAIN || + (0 <= rc && rc < (ssize_t)packet_len)) { + sftp->fstatvfs_packet = packet; + return LIBSSH2_ERROR_EAGAIN; + } + + LIBSSH2_FREE(session, packet); + sftp->fstatvfs_packet = NULL; + + if (rc < 0) { + sftp->fstatvfs_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "_libssh2_channel_write() failed"); + } + sftp->fstatvfs_state = libssh2_NB_state_sent; + } + + rc = sftp_packet_require(sftp, SSH_FXP_EXTENDED_REPLY, + sftp->fstatvfs_request_id, &data, &data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + sftp->fstatvfs_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Error waiting for FXP EXTENDED REPLY"); + } else if (data_len < 93) { + LIBSSH2_FREE(session, data); + sftp->fstatvfs_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error: short response"); + } + + sftp->fstatvfs_state = libssh2_NB_state_idle; + + st->f_bsize = _libssh2_ntohu64(data + 5); + st->f_frsize = _libssh2_ntohu64(data + 13); + st->f_blocks = _libssh2_ntohu64(data + 21); + st->f_bfree = _libssh2_ntohu64(data + 29); + st->f_bavail = _libssh2_ntohu64(data + 37); + st->f_files = _libssh2_ntohu64(data + 45); + st->f_ffree = _libssh2_ntohu64(data + 53); + st->f_favail = _libssh2_ntohu64(data + 61); + st->f_fsid = _libssh2_ntohu64(data + 69); + flag = _libssh2_ntohu64(data + 77); + st->f_namemax = _libssh2_ntohu64(data + 85); + + st->f_flag = (flag & SSH_FXE_STATVFS_ST_RDONLY) + ? LIBSSH2_SFTP_ST_RDONLY : 0; + st->f_flag |= (flag & SSH_FXE_STATVFS_ST_NOSUID) + ? LIBSSH2_SFTP_ST_NOSUID : 0; + + LIBSSH2_FREE(session, data); + return 0; +} + +/* libssh2_sftp_fstatvfs + * Get filesystem space and inode utilization (requires fstatvfs@openssh.com + * support on the server) + */ +LIBSSH2_API int +libssh2_sftp_fstatvfs(LIBSSH2_SFTP_HANDLE *handle, LIBSSH2_SFTP_STATVFS *st) +{ + int rc; + if(!handle || !st) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, handle->sftp->channel->session, sftp_fstatvfs(handle, st)); + return rc; +} + +/* + * sftp_statvfs + * + * Get file system statistics + */ +static int sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, + unsigned int path_len, LIBSSH2_SFTP_STATVFS *st) +{ + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len; + /* 17 = packet_len(4) + packet_type(1) + request_id(4) + ext_len(4) + + path_len (4) */ + /* 19 = strlen ("statvfs@openssh.com") */ + uint32_t packet_len = path_len + 19 + 17; + unsigned char *packet, *s, *data; + ssize_t rc; + unsigned int flag; + + if (sftp->statvfs_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "Getting file system statistics of %s", path); + s = packet = LIBSSH2_ALLOC(session, packet_len); + if (!packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for FXP_EXTENDED " + "packet"); + } + + _libssh2_store_u32(&s, packet_len - 4); + *(s++) = SSH_FXP_EXTENDED; + sftp->statvfs_request_id = sftp->request_id++; + _libssh2_store_u32(&s, sftp->statvfs_request_id); + _libssh2_store_str(&s, "statvfs@openssh.com", 19); + _libssh2_store_str(&s, path, path_len); + + sftp->statvfs_state = libssh2_NB_state_created; + } + else { + packet = sftp->statvfs_packet; + } + + if (sftp->statvfs_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, packet, packet_len); + if (rc == LIBSSH2_ERROR_EAGAIN || + (0 <= rc && rc < (ssize_t)packet_len)) { + sftp->statvfs_packet = packet; + return LIBSSH2_ERROR_EAGAIN; + } + + LIBSSH2_FREE(session, packet); + sftp->statvfs_packet = NULL; + + if (rc < 0) { + sftp->statvfs_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "_libssh2_channel_write() failed"); + } + sftp->statvfs_state = libssh2_NB_state_sent; + } + + rc = sftp_packet_require(sftp, SSH_FXP_EXTENDED_REPLY, + sftp->statvfs_request_id, &data, &data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + sftp->statvfs_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Error waiting for FXP EXTENDED REPLY"); + } else if (data_len < 93) { + LIBSSH2_FREE(session, data); + sftp->fstatvfs_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error: short response"); + } + + sftp->statvfs_state = libssh2_NB_state_idle; + + st->f_bsize = _libssh2_ntohu64(data + 5); + st->f_frsize = _libssh2_ntohu64(data + 13); + st->f_blocks = _libssh2_ntohu64(data + 21); + st->f_bfree = _libssh2_ntohu64(data + 29); + st->f_bavail = _libssh2_ntohu64(data + 37); + st->f_files = _libssh2_ntohu64(data + 45); + st->f_ffree = _libssh2_ntohu64(data + 53); + st->f_favail = _libssh2_ntohu64(data + 61); + st->f_fsid = _libssh2_ntohu64(data + 69); + flag = _libssh2_ntohu64(data + 77); + st->f_namemax = _libssh2_ntohu64(data + 85); + + st->f_flag = (flag & SSH_FXE_STATVFS_ST_RDONLY) + ? LIBSSH2_SFTP_ST_RDONLY : 0; + st->f_flag |= (flag & SSH_FXE_STATVFS_ST_NOSUID) + ? LIBSSH2_SFTP_ST_NOSUID : 0; + + LIBSSH2_FREE(session, data); + return 0; +} + +/* libssh2_sftp_statvfs_ex + * Get filesystem space and inode utilization (requires statvfs@openssh.com + * support on the server) + */ +LIBSSH2_API int +libssh2_sftp_statvfs(LIBSSH2_SFTP *sftp, const char *path, + size_t path_len, LIBSSH2_SFTP_STATVFS *st) +{ + int rc; + if(!sftp || !st) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, sftp->channel->session, sftp_statvfs(sftp, path, path_len, + st)); + return rc; +} + + +/* + * sftp_mkdir + * + * Create an SFTP directory + */ +static int sftp_mkdir(LIBSSH2_SFTP *sftp, const char *path, + unsigned int path_len, long mode) +{ + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + LIBSSH2_SFTP_ATTRIBUTES attrs = { + LIBSSH2_SFTP_ATTR_PERMISSIONS, 0, 0, 0, 0, 0, 0 + }; + size_t data_len; + int retcode; + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ + ssize_t packet_len = path_len + 13 + + sftp_attrsize(LIBSSH2_SFTP_ATTR_PERMISSIONS); + unsigned char *packet, *s, *data; + int rc; + + if (sftp->mkdir_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, + "Creating directory %s with mode 0%lo", path, mode); + s = packet = LIBSSH2_ALLOC(session, packet_len); + if (!packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for FXP_MKDIR " + "packet"); + } + /* Filetype in SFTP 3 and earlier */ + attrs.permissions = mode | LIBSSH2_SFTP_ATTR_PFILETYPE_DIR; + + _libssh2_store_u32(&s, packet_len - 4); + *(s++) = SSH_FXP_MKDIR; + sftp->mkdir_request_id = sftp->request_id++; + _libssh2_store_u32(&s, sftp->mkdir_request_id); + _libssh2_store_str(&s, path, path_len); + + s += sftp_attr2bin(s, &attrs); + + sftp->mkdir_state = libssh2_NB_state_created; + } + else { + packet = sftp->mkdir_packet; + } + + if (sftp->mkdir_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, packet, packet_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + sftp->mkdir_packet = packet; + return rc; + } + if (packet_len != rc) { + LIBSSH2_FREE(session, packet); + sftp->mkdir_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "_libssh2_channel_write() failed"); + } + LIBSSH2_FREE(session, packet); + sftp->mkdir_state = libssh2_NB_state_sent; + sftp->mkdir_packet = NULL; + } + + rc = sftp_packet_require(sftp, SSH_FXP_STATUS, sftp->mkdir_request_id, + &data, &data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + sftp->mkdir_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Error waiting for FXP STATUS"); + } + + sftp->mkdir_state = libssh2_NB_state_idle; + + retcode = _libssh2_ntohu32(data + 5); + LIBSSH2_FREE(session, data); + + if (retcode == LIBSSH2_FX_OK) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "OK!"); + return 0; + } else { + sftp->last_errno = retcode; + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error"); + } +} + +/* + * libssh2_sftp_mkdir_ex + * + * Create an SFTP directory + */ +LIBSSH2_API int +libssh2_sftp_mkdir_ex(LIBSSH2_SFTP *sftp, const char *path, + unsigned int path_len, long mode) +{ + int rc; + if(!sftp) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, sftp->channel->session, + sftp_mkdir(sftp, path, path_len, mode)); + return rc; +} + +/* sftp_rmdir + * Remove a directory + */ +static int sftp_rmdir(LIBSSH2_SFTP *sftp, const char *path, + unsigned int path_len) +{ + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len; + int retcode; + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ + ssize_t packet_len = path_len + 13; + unsigned char *s, *data; + int rc; + + if (sftp->rmdir_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "Removing directory: %s", + path); + s = sftp->rmdir_packet = LIBSSH2_ALLOC(session, packet_len); + if (!sftp->rmdir_packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for FXP_RMDIR " + "packet"); + } + + _libssh2_store_u32(&s, packet_len - 4); + *(s++) = SSH_FXP_RMDIR; + sftp->rmdir_request_id = sftp->request_id++; + _libssh2_store_u32(&s, sftp->rmdir_request_id); + _libssh2_store_str(&s, path, path_len); + + sftp->rmdir_state = libssh2_NB_state_created; + } + + if (sftp->rmdir_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, sftp->rmdir_packet, + packet_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (packet_len != rc) { + LIBSSH2_FREE(session, sftp->rmdir_packet); + sftp->rmdir_packet = NULL; + sftp->rmdir_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send FXP_RMDIR command"); + } + LIBSSH2_FREE(session, sftp->rmdir_packet); + sftp->rmdir_packet = NULL; + + sftp->rmdir_state = libssh2_NB_state_sent; + } + + rc = sftp_packet_require(sftp, SSH_FXP_STATUS, + sftp->rmdir_request_id, &data, &data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (rc) { + sftp->rmdir_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Error waiting for FXP STATUS"); + } + + sftp->rmdir_state = libssh2_NB_state_idle; + + retcode = _libssh2_ntohu32(data + 5); + LIBSSH2_FREE(session, data); + + if (retcode == LIBSSH2_FX_OK) { + return 0; + } else { + sftp->last_errno = retcode; + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error"); + } +} + +/* libssh2_sftp_rmdir_ex + * Remove a directory + */ +LIBSSH2_API int +libssh2_sftp_rmdir_ex(LIBSSH2_SFTP *sftp, const char *path, + unsigned int path_len) +{ + int rc; + if(!sftp) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, sftp->channel->session, + sftp_rmdir(sftp, path, path_len)); + return rc; +} + +/* sftp_stat + * Stat a file or symbolic link + */ +static int sftp_stat(LIBSSH2_SFTP *sftp, const char *path, + unsigned int path_len, int stat_type, + LIBSSH2_SFTP_ATTRIBUTES * attrs) +{ + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len; + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ + ssize_t packet_len = + path_len + 13 + + ((stat_type == + LIBSSH2_SFTP_SETSTAT) ? sftp_attrsize(attrs->flags) : 0); + unsigned char *s, *data; + static const unsigned char stat_responses[2] = + { SSH_FXP_ATTRS, SSH_FXP_STATUS }; + int rc; + + if (sftp->stat_state == libssh2_NB_state_idle) { + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%s %s", + (stat_type == LIBSSH2_SFTP_SETSTAT) ? "Set-statting" : + (stat_type == + LIBSSH2_SFTP_LSTAT ? "LStatting" : "Statting"), path); + s = sftp->stat_packet = LIBSSH2_ALLOC(session, packet_len); + if (!sftp->stat_packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for FXP_*STAT " + "packet"); + } + + _libssh2_store_u32(&s, packet_len - 4); + + switch (stat_type) { + case LIBSSH2_SFTP_SETSTAT: + *(s++) = SSH_FXP_SETSTAT; + break; + + case LIBSSH2_SFTP_LSTAT: + *(s++) = SSH_FXP_LSTAT; + break; + + case LIBSSH2_SFTP_STAT: + default: + *(s++) = SSH_FXP_STAT; + } + sftp->stat_request_id = sftp->request_id++; + _libssh2_store_u32(&s, sftp->stat_request_id); + _libssh2_store_str(&s, path, path_len); + + if (stat_type == LIBSSH2_SFTP_SETSTAT) + s += sftp_attr2bin(s, attrs); + + sftp->stat_state = libssh2_NB_state_created; + } + + if (sftp->stat_state == libssh2_NB_state_created) { + rc = _libssh2_channel_write(channel, 0, sftp->stat_packet, packet_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return rc; + } else if (packet_len != rc) { + LIBSSH2_FREE(session, sftp->stat_packet); + sftp->stat_packet = NULL; + sftp->stat_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send STAT/LSTAT/SETSTAT command"); + } + LIBSSH2_FREE(session, sftp->stat_packet); + sftp->stat_packet = NULL; + + sftp->stat_state = libssh2_NB_state_sent; + } + + rc = sftp_packet_requirev(sftp, 2, stat_responses, + sftp->stat_request_id, &data, &data_len); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + else if (rc) { + sftp->stat_state = libssh2_NB_state_idle; + return _libssh2_error(session, rc, + "Timeout waiting for status message"); + } + + sftp->stat_state = libssh2_NB_state_idle; + + if (data[0] == SSH_FXP_STATUS) { + int retcode; + + retcode = _libssh2_ntohu32(data + 5); + LIBSSH2_FREE(session, data); + if (retcode == LIBSSH2_FX_OK) { + return 0; + } else { + sftp->last_errno = retcode; + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error"); + } + } + + memset(attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES)); + sftp_bin2attr(attrs, data + 5); + LIBSSH2_FREE(session, data); + + return 0; +} + +/* libssh2_sftp_stat_ex + * Stat a file or symbolic link + */ +LIBSSH2_API int +libssh2_sftp_stat_ex(LIBSSH2_SFTP *sftp, const char *path, + unsigned int path_len, int stat_type, + LIBSSH2_SFTP_ATTRIBUTES *attrs) +{ + int rc; + if(!sftp) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, sftp->channel->session, + sftp_stat(sftp, path, path_len, stat_type, attrs)); + return rc; +} + +/* sftp_symlink + * Read or set a symlink + */ +static int sftp_symlink(LIBSSH2_SFTP *sftp, const char *path, + unsigned int path_len, char *target, + unsigned int target_len, int link_type) +{ + LIBSSH2_CHANNEL *channel = sftp->channel; + LIBSSH2_SESSION *session = channel->session; + size_t data_len, link_len; + /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */ + ssize_t packet_len = + path_len + 13 + + ((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0); + unsigned char *s, *data; + static const unsigned char link_responses[2] = + { SSH_FXP_NAME, SSH_FXP_STATUS }; + int retcode; + + if ((sftp->version < 3) && (link_type != LIBSSH2_SFTP_REALPATH)) { + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "Server does not support SYMLINK or READLINK"); + } + + if (sftp->symlink_state == libssh2_NB_state_idle) { + s = sftp->symlink_packet = LIBSSH2_ALLOC(session, packet_len); + if (!sftp->symlink_packet) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "SYMLINK/READLINK/REALPATH packet"); + } + + _libssh2_debug(session, LIBSSH2_TRACE_SFTP, "%s %s on %s", + (link_type == + LIBSSH2_SFTP_SYMLINK) ? "Creating" : "Reading", + (link_type == + LIBSSH2_SFTP_REALPATH) ? "realpath" : "symlink", path); + + _libssh2_store_u32(&s, packet_len - 4); + + switch (link_type) { + case LIBSSH2_SFTP_REALPATH: + *(s++) = SSH_FXP_REALPATH; + break; + + case LIBSSH2_SFTP_SYMLINK: + *(s++) = SSH_FXP_SYMLINK; + break; + + case LIBSSH2_SFTP_READLINK: + default: + *(s++) = SSH_FXP_READLINK; + } + sftp->symlink_request_id = sftp->request_id++; + _libssh2_store_u32(&s, sftp->symlink_request_id); + _libssh2_store_str(&s, path, path_len); + + if (link_type == LIBSSH2_SFTP_SYMLINK) + _libssh2_store_str(&s, target, target_len); + + sftp->symlink_state = libssh2_NB_state_created; + } + + if (sftp->symlink_state == libssh2_NB_state_created) { + ssize_t rc = _libssh2_channel_write(channel, 0, sftp->symlink_packet, + packet_len); + if (rc == LIBSSH2_ERROR_EAGAIN) + return rc; + else if (packet_len != rc) { + LIBSSH2_FREE(session, sftp->symlink_packet); + sftp->symlink_packet = NULL; + sftp->symlink_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send SYMLINK/READLINK command"); + } + LIBSSH2_FREE(session, sftp->symlink_packet); + sftp->symlink_packet = NULL; + + sftp->symlink_state = libssh2_NB_state_sent; + } + + retcode = sftp_packet_requirev(sftp, 2, link_responses, + sftp->symlink_request_id, &data, + &data_len); + if (retcode == LIBSSH2_ERROR_EAGAIN) + return retcode; + else if (retcode) { + sftp->symlink_state = libssh2_NB_state_idle; + return _libssh2_error(session, retcode, + "Error waiting for status message"); + } + + sftp->symlink_state = libssh2_NB_state_idle; + + if (data[0] == SSH_FXP_STATUS) { + int retcode; + + retcode = _libssh2_ntohu32(data + 5); + LIBSSH2_FREE(session, data); + if (retcode == LIBSSH2_FX_OK) + return LIBSSH2_ERROR_NONE; + else { + sftp->last_errno = retcode; + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "SFTP Protocol Error"); + } + } + + if (_libssh2_ntohu32(data + 5) < 1) { + LIBSSH2_FREE(session, data); + return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL, + "Invalid READLINK/REALPATH response, " + "no name entries"); + } + + /* this reads a u32 and stores it into a signed 32bit value */ + link_len = _libssh2_ntohu32(data + 9); + if (link_len < target_len) { + memcpy(target, data + 13, link_len); + target[link_len] = 0; + retcode = (int)link_len; + } + else + retcode = LIBSSH2_ERROR_BUFFER_TOO_SMALL; + LIBSSH2_FREE(session, data); + + return retcode; +} + +/* libssh2_sftp_symlink_ex + * Read or set a symlink + */ +LIBSSH2_API int +libssh2_sftp_symlink_ex(LIBSSH2_SFTP *sftp, const char *path, + unsigned int path_len, char *target, + unsigned int target_len, int link_type) +{ + int rc; + if(!sftp) + return LIBSSH2_ERROR_BAD_USE; + BLOCK_ADJUST(rc, sftp->channel->session, + sftp_symlink(sftp, path, path_len, target, target_len, + link_type)); + return rc; +} + +/* libssh2_sftp_last_error + * Returns the last error code reported by SFTP + */ +LIBSSH2_API unsigned long +libssh2_sftp_last_error(LIBSSH2_SFTP *sftp) +{ + if(!sftp) + return 0; + + return sftp->last_errno; +} + +/* libssh2_sftp_get_channel + * Return the channel of sftp, then caller can control the channel's behavior. + */ +LIBSSH2_API LIBSSH2_CHANNEL * +libssh2_sftp_get_channel(LIBSSH2_SFTP *sftp) +{ + if (!sftp) + return NULL; + + return sftp->channel; +} diff --git a/vendor/libssh2-1.4.2/src/sftp.h b/vendor/libssh2-1.4.2/src/sftp.h new file mode 100644 index 0000000..55bdb46 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/sftp.h @@ -0,0 +1,230 @@ +#ifndef _LIBSSH2_SFTP_H +#define _LIBSSH2_SFTP_H +/* + * Copyright (C) 2010 - 2012 by Daniel Stenberg + * Author: Daniel Stenberg + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +/* + * MAX_SFTP_OUTGOING_SIZE MUST not be larger than 32500 or so. This is the + * amount of data sent in each FXP_WRITE packet + */ +#define MAX_SFTP_OUTGOING_SIZE 30000 + +/* MAX_SFTP_READ_SIZE is how much data is asked for at max in each FXP_READ + * packets. + */ +#define MAX_SFTP_READ_SIZE 2000 + +struct sftp_pipeline_chunk { + struct list_node node; + size_t len; /* WRITE: size of the data to write + READ: how many bytes that was asked for */ + size_t sent; + ssize_t lefttosend; /* if 0, the entire packet has been sent off */ + uint32_t request_id; + unsigned char packet[1]; /* data */ +}; + +struct sftp_zombie_requests { + struct list_node node; + uint32_t request_id; +}; + +#ifndef MIN +#define MIN(x,y) ((x)<(y)?(x):(y)) +#endif + +struct _LIBSSH2_SFTP_PACKET +{ + struct list_node node; /* linked list header */ + uint32_t request_id; + unsigned char *data; + size_t data_len; /* payload size */ +}; + +typedef struct _LIBSSH2_SFTP_PACKET LIBSSH2_SFTP_PACKET; + +#define SFTP_HANDLE_MAXLEN 256 /* according to spec! */ + +struct _LIBSSH2_SFTP_HANDLE +{ + struct list_node node; + + LIBSSH2_SFTP *sftp; + + char handle[SFTP_HANDLE_MAXLEN]; + size_t handle_len; + + enum { + LIBSSH2_SFTP_HANDLE_FILE, + LIBSSH2_SFTP_HANDLE_DIR + } handle_type; + + union _libssh2_sftp_handle_data + { + struct _libssh2_sftp_handle_file_data + { + libssh2_uint64_t offset; + libssh2_uint64_t offset_sent; + size_t acked; /* container for acked data that hasn't been + returned to caller yet, used for sftp_write */ + + /* 'data' is used by sftp_read() and is allocated data that has + been received already from the server but wasn't returned to + the caller yet. It is of size 'data_len' and 'data_left is the + number of bytes not yet returned, counted from the end of the + buffer. */ + unsigned char *data; + size_t data_len; + size_t data_left; + + char eof; /* we have read to the end */ + } file; + struct _libssh2_sftp_handle_dir_data + { + uint32_t names_left; + void *names_packet; + char *next_name; + } dir; + } u; + + /* State variables used in libssh2_sftp_close_handle() */ + libssh2_nonblocking_states close_state; + uint32_t close_request_id; + unsigned char *close_packet; + + /* list of outstanding packets sent to server */ + struct list_head packet_list; + +}; + +struct _LIBSSH2_SFTP +{ + LIBSSH2_CHANNEL *channel; + + uint32_t request_id, version; + + struct list_head packets; + + /* List of FXP_READ responses to ignore because EOF already received. */ + struct list_head zombie_requests; + + /* a list of _LIBSSH2_SFTP_HANDLE structs */ + struct list_head sftp_handles; + + uint32_t last_errno; + + /* Holder for partial packet, use in libssh2_sftp_packet_read() */ + unsigned char partial_size[4]; /* buffer for size field */ + size_t partial_size_len; /* size field length */ + unsigned char *partial_packet; /* The data */ + uint32_t partial_len; /* Desired number of bytes */ + size_t partial_received; /* Bytes received so far */ + + /* Time that libssh2_sftp_packet_requirev() started reading */ + time_t requirev_start; + + /* State variables used in libssh2_sftp_open_ex() */ + libssh2_nonblocking_states open_state; + unsigned char *open_packet; + uint32_t open_packet_len; /* 32 bit on the wire */ + size_t open_packet_sent; + uint32_t open_request_id; + + /* State variable used in sftp_read() */ + libssh2_nonblocking_states read_state; + + /* State variable used in sftp_packet_read() */ + libssh2_nonblocking_states packet_state; + + /* State variable used in sftp_write() */ + libssh2_nonblocking_states write_state; + + /* State variables used in libssh2_sftp_readdir() */ + libssh2_nonblocking_states readdir_state; + unsigned char *readdir_packet; + uint32_t readdir_request_id; + + /* State variables used in libssh2_sftp_fstat_ex() */ + libssh2_nonblocking_states fstat_state; + unsigned char *fstat_packet; + uint32_t fstat_request_id; + + /* State variables used in libssh2_sftp_unlink_ex() */ + libssh2_nonblocking_states unlink_state; + unsigned char *unlink_packet; + uint32_t unlink_request_id; + + /* State variables used in libssh2_sftp_rename_ex() */ + libssh2_nonblocking_states rename_state; + unsigned char *rename_packet; + unsigned char *rename_s; + uint32_t rename_request_id; + + /* State variables used in libssh2_sftp_fstatvfs() */ + libssh2_nonblocking_states fstatvfs_state; + unsigned char *fstatvfs_packet; + uint32_t fstatvfs_request_id; + + /* State variables used in libssh2_sftp_statvfs() */ + libssh2_nonblocking_states statvfs_state; + unsigned char *statvfs_packet; + uint32_t statvfs_request_id; + + /* State variables used in libssh2_sftp_mkdir() */ + libssh2_nonblocking_states mkdir_state; + unsigned char *mkdir_packet; + uint32_t mkdir_request_id; + + /* State variables used in libssh2_sftp_rmdir() */ + libssh2_nonblocking_states rmdir_state; + unsigned char *rmdir_packet; + uint32_t rmdir_request_id; + + /* State variables used in libssh2_sftp_stat() */ + libssh2_nonblocking_states stat_state; + unsigned char *stat_packet; + uint32_t stat_request_id; + + /* State variables used in libssh2_sftp_symlink() */ + libssh2_nonblocking_states symlink_state; + unsigned char *symlink_packet; + uint32_t symlink_request_id; +}; + +#endif diff --git a/vendor/libssh2-1.4.2/src/transport.c b/vendor/libssh2-1.4.2/src/transport.c new file mode 100644 index 0000000..95b9a3a --- /dev/null +++ b/vendor/libssh2-1.4.2/src/transport.c @@ -0,0 +1,873 @@ +/* Copyright (C) 2007 The Written Word, Inc. All rights reserved. + * Copyright (C) 2009-2010 by Daniel Stenberg + * Author: Daniel Stenberg + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file handles reading and writing to the SECSH transport layer. RFC4253. + */ + +#include "libssh2_priv.h" +#include +#include +#include +#ifdef LIBSSH2DEBUG +#include +#endif + +#include + +#include "transport.h" +#include "mac.h" + +#define MAX_BLOCKSIZE 32 /* MUST fit biggest crypto block size we use/get */ +#define MAX_MACSIZE 20 /* MUST fit biggest MAC length we support */ + +#ifdef LIBSSH2DEBUG +#define UNPRINTABLE_CHAR '.' +static void +debugdump(LIBSSH2_SESSION * session, + const char *desc, const unsigned char *ptr, size_t size) +{ + size_t i; + size_t c; + unsigned int width = 0x10; + char buffer[256]; /* Must be enough for width*4 + about 30 or so */ + size_t used; + static const char* hex_chars = "0123456789ABCDEF"; + + if (!(session->showmask & LIBSSH2_TRACE_TRANS)) { + /* not asked for, bail out */ + return; + } + + used = snprintf(buffer, sizeof(buffer), "=> %s (%d bytes)\n", + desc, (int) size); + if (session->tracehandler) + (session->tracehandler)(session, session->tracehandler_context, + buffer, used); + else + fprintf(stderr, "%s", buffer); + + for(i = 0; i < size; i += width) { + + used = snprintf(buffer, sizeof(buffer), "%04lx: ", (long)i); + + /* hex not disabled, show it */ + for(c = 0; c < width; c++) { + if (i + c < size) { + buffer[used++] = hex_chars[(ptr[i+c] >> 4) & 0xF]; + buffer[used++] = hex_chars[ptr[i+c] & 0xF]; + } + else { + buffer[used++] = ' '; + buffer[used++] = ' '; + } + + buffer[used++] = ' '; + if ((width/2) - 1 == c) + buffer[used++] = ' '; + } + + buffer[used++] = ':'; + buffer[used++] = ' '; + + for(c = 0; (c < width) && (i + c < size); c++) { + buffer[used++] = isprint(ptr[i + c]) ? + ptr[i + c] : UNPRINTABLE_CHAR; + } + buffer[used++] = '\n'; + buffer[used] = 0; + + if (session->tracehandler) + (session->tracehandler)(session, session->tracehandler_context, + buffer, used); + else + fprintf(stderr, "%s", buffer); + } +} +#else +#define debugdump(a,x,y,z) +#endif + + +/* decrypt() decrypts 'len' bytes from 'source' to 'dest'. + * + * returns 0 on success and negative on failure + */ + +static int +decrypt(LIBSSH2_SESSION * session, unsigned char *source, + unsigned char *dest, int len) +{ + struct transportpacket *p = &session->packet; + int blocksize = session->remote.crypt->blocksize; + + /* if we get called with a len that isn't an even number of blocksizes + we risk losing those extra bytes */ + assert((len % blocksize) == 0); + + while (len >= blocksize) { + if (session->remote.crypt->crypt(session, source, + &session->remote.crypt_abstract)) { + LIBSSH2_FREE(session, p->payload); + return LIBSSH2_ERROR_DECRYPT; + } + + /* if the crypt() function would write to a given address it + wouldn't have to memcpy() and we could avoid this memcpy() + too */ + memcpy(dest, source, blocksize); + + len -= blocksize; /* less bytes left */ + dest += blocksize; /* advance write pointer */ + source += blocksize; /* advance read pointer */ + } + return LIBSSH2_ERROR_NONE; /* all is fine */ +} + +/* + * fullpacket() gets called when a full packet has been received and properly + * collected. + */ +static int +fullpacket(LIBSSH2_SESSION * session, int encrypted /* 1 or 0 */ ) +{ + unsigned char macbuf[MAX_MACSIZE]; + struct transportpacket *p = &session->packet; + int rc; + + if (session->fullpacket_state == libssh2_NB_state_idle) { + session->fullpacket_macstate = LIBSSH2_MAC_CONFIRMED; + session->fullpacket_payload_len = p->packet_length - 1; + + if (encrypted) { + + /* Calculate MAC hash */ + session->remote.mac->hash(session, macbuf, /* store hash here */ + session->remote.seqno, + p->init, 5, + p->payload, + session->fullpacket_payload_len, + &session->remote.mac_abstract); + + /* Compare the calculated hash with the MAC we just read from + * the network. The read one is at the very end of the payload + * buffer. Note that 'payload_len' here is the packet_length + * field which includes the padding but not the MAC. + */ + if (memcmp(macbuf, p->payload + session->fullpacket_payload_len, + session->remote.mac->mac_len)) { + session->fullpacket_macstate = LIBSSH2_MAC_INVALID; + } + } + + session->remote.seqno++; + + /* ignore the padding */ + session->fullpacket_payload_len -= p->padding_length; + + /* Check for and deal with decompression */ + if (session->remote.comp && + session->remote.comp->compress && + session->remote.comp_abstract) { + /* + * The buffer for the decompression (remote.comp_abstract) is + * initialised in time when it is needed so as long it is NULL we + * cannot decompress. + */ + + unsigned char *data; + size_t data_len; + rc = session->remote.comp->decomp(session, + &data, &data_len, + LIBSSH2_PACKET_MAXDECOMP, + p->payload, + session->fullpacket_payload_len, + &session->remote.comp_abstract); + LIBSSH2_FREE(session, p->payload); + if(rc) + return rc; + + p->payload = data; + session->fullpacket_payload_len = data_len; + } + + session->fullpacket_packet_type = p->payload[0]; + + debugdump(session, "libssh2_transport_read() plain", + p->payload, session->fullpacket_payload_len); + + session->fullpacket_state = libssh2_NB_state_created; + } + + if (session->fullpacket_state == libssh2_NB_state_created) { + rc = _libssh2_packet_add(session, p->payload, + session->fullpacket_payload_len, + session->fullpacket_macstate); + if (rc) + return rc; + } + + session->fullpacket_state = libssh2_NB_state_idle; + + return session->fullpacket_packet_type; +} + + +/* + * _libssh2_transport_read + * + * Collect a packet into the input queue. + * + * Returns packet type added to input queue (0 if nothing added), or a + * negative error number. + */ + +/* + * This function reads the binary stream as specified in chapter 6 of RFC4253 + * "The Secure Shell (SSH) Transport Layer Protocol" + * + * DOES NOT call _libssh2_error() for ANY error case. + */ +int _libssh2_transport_read(LIBSSH2_SESSION * session) +{ + int rc; + struct transportpacket *p = &session->packet; + int remainbuf; + int remainpack; + int numbytes; + int numdecrypt; + unsigned char block[MAX_BLOCKSIZE]; + int blocksize; + int encrypted = 1; + size_t total_num; + + /* default clear the bit */ + session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_INBOUND; + + /* + * All channels, systems, subsystems, etc eventually make it down here + * when looking for more incoming data. If a key exchange is going on + * (LIBSSH2_STATE_EXCHANGING_KEYS bit is set) then the remote end will + * ONLY send key exchange related traffic. In non-blocking mode, there is + * a chance to break out of the kex_exchange function with an EAGAIN + * status, and never come back to it. If LIBSSH2_STATE_EXCHANGING_KEYS is + * active, then we must redirect to the key exchange. However, if + * kex_exchange is active (as in it is the one that calls this execution + * of packet_read, then don't redirect, as that would be an infinite loop! + */ + + if (session->state & LIBSSH2_STATE_EXCHANGING_KEYS && + !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) { + + /* Whoever wants a packet won't get anything until the key re-exchange + * is done! + */ + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the" + " key re-exchange from _libssh2_transport_read"); + rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state); + if (rc) + return rc; + } + + /* + * =============================== NOTE =============================== + * I know this is very ugly and not a really good use of "goto", but + * this case statement would be even uglier to do it any other way + */ + if (session->readPack_state == libssh2_NB_state_jump1) { + session->readPack_state = libssh2_NB_state_idle; + encrypted = session->readPack_encrypted; + goto libssh2_transport_read_point1; + } + + do { + if (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) { + return LIBSSH2_ERROR_NONE; + } + + if (session->state & LIBSSH2_STATE_NEWKEYS) { + blocksize = session->remote.crypt->blocksize; + } else { + encrypted = 0; /* not encrypted */ + blocksize = 5; /* not strictly true, but we can use 5 here to + make the checks below work fine still */ + } + + /* read/use a whole big chunk into a temporary area stored in + the LIBSSH2_SESSION struct. We will decrypt data from that + buffer into the packet buffer so this temp one doesn't have + to be able to keep a whole SSH packet, just be large enough + so that we can read big chunks from the network layer. */ + + /* how much data there is remaining in the buffer to deal with + before we should read more from the network */ + remainbuf = p->writeidx - p->readidx; + + /* if remainbuf turns negative we have a bad internal error */ + assert(remainbuf >= 0); + + if (remainbuf < blocksize) { + /* If we have less than a blocksize left, it is too + little data to deal with, read more */ + ssize_t nread; + + /* move any remainder to the start of the buffer so + that we can do a full refill */ + if (remainbuf) { + memmove(p->buf, &p->buf[p->readidx], remainbuf); + p->readidx = 0; + p->writeidx = remainbuf; + } else { + /* nothing to move, just zero the indexes */ + p->readidx = p->writeidx = 0; + } + + /* now read a big chunk from the network into the temp buffer */ + nread = + LIBSSH2_RECV(session, &p->buf[remainbuf], + PACKETBUFSIZE - remainbuf, + LIBSSH2_SOCKET_RECV_FLAGS(session)); + if (nread <= 0) { + /* check if this is due to EAGAIN and return the special + return code if so, error out normally otherwise */ + if ((nread < 0) && (nread == -EAGAIN)) { + session->socket_block_directions |= + LIBSSH2_SESSION_BLOCK_INBOUND; + return LIBSSH2_ERROR_EAGAIN; + } + _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + "Error recving %d bytes (got %d)", + PACKETBUFSIZE - remainbuf, -nread); + return LIBSSH2_ERROR_SOCKET_RECV; + } + _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + "Recved %d/%d bytes to %p+%d", nread, + PACKETBUFSIZE - remainbuf, p->buf, remainbuf); + + debugdump(session, "libssh2_transport_read() raw", + &p->buf[remainbuf], nread); + /* advance write pointer */ + p->writeidx += nread; + + /* update remainbuf counter */ + remainbuf = p->writeidx - p->readidx; + } + + /* how much data to deal with from the buffer */ + numbytes = remainbuf; + + if (!p->total_num) { + /* No payload package area allocated yet. To know the + size of this payload, we need to decrypt the first + blocksize data. */ + + if (numbytes < blocksize) { + /* we can't act on anything less than blocksize, but this + check is only done for the initial block since once we have + got the start of a block we can in fact deal with fractions + */ + session->socket_block_directions |= + LIBSSH2_SESSION_BLOCK_INBOUND; + return LIBSSH2_ERROR_EAGAIN; + } + + if (encrypted) { + rc = decrypt(session, &p->buf[p->readidx], block, blocksize); + if (rc != LIBSSH2_ERROR_NONE) { + return rc; + } + /* save the first 5 bytes of the decrypted package, to be + used in the hash calculation later down. */ + memcpy(p->init, &p->buf[p->readidx], 5); + } else { + /* the data is plain, just copy it verbatim to + the working block buffer */ + memcpy(block, &p->buf[p->readidx], blocksize); + } + + /* advance the read pointer */ + p->readidx += blocksize; + + /* we now have the initial blocksize bytes decrypted, + * and we can extract packet and padding length from it + */ + p->packet_length = _libssh2_ntohu32(block); + if (p->packet_length < 1) + return LIBSSH2_ERROR_DECRYPT; + + p->padding_length = block[4]; + + /* total_num is the number of bytes following the initial + (5 bytes) packet length and padding length fields */ + total_num = + p->packet_length - 1 + + (encrypted ? session->remote.mac->mac_len : 0); + + /* RFC4253 section 6.1 Maximum Packet Length says: + * + * "All implementations MUST be able to process + * packets with uncompressed payload length of 32768 + * bytes or less and total packet size of 35000 bytes + * or less (including length, padding length, payload, + * padding, and MAC.)." + */ + if (total_num > LIBSSH2_PACKET_MAXPAYLOAD) { + return LIBSSH2_ERROR_OUT_OF_BOUNDARY; + } + + /* Get a packet handle put data into. We get one to + hold all data, including padding and MAC. */ + p->payload = LIBSSH2_ALLOC(session, total_num); + if (!p->payload) { + return LIBSSH2_ERROR_ALLOC; + } + p->total_num = total_num; + /* init write pointer to start of payload buffer */ + p->wptr = p->payload; + + if (blocksize > 5) { + /* copy the data from index 5 to the end of + the blocksize from the temporary buffer to + the start of the decrypted buffer */ + memcpy(p->wptr, &block[5], blocksize - 5); + p->wptr += blocksize - 5; /* advance write pointer */ + } + + /* init the data_num field to the number of bytes of + the package read so far */ + p->data_num = p->wptr - p->payload; + + /* we already dealt with a blocksize worth of data */ + numbytes -= blocksize; + } + + /* how much there is left to add to the current payload + package */ + remainpack = p->total_num - p->data_num; + + if (numbytes > remainpack) { + /* if we have more data in the buffer than what is going into this + particular packet, we limit this round to this packet only */ + numbytes = remainpack; + } + + if (encrypted) { + /* At the end of the incoming stream, there is a MAC, + and we don't want to decrypt that since we need it + "raw". We MUST however decrypt the padding data + since it is used for the hash later on. */ + int skip = session->remote.mac->mac_len; + + /* if what we have plus numbytes is bigger than the + total minus the skip margin, we should lower the + amount to decrypt even more */ + if ((p->data_num + numbytes) > (p->total_num - skip)) { + numdecrypt = (p->total_num - skip) - p->data_num; + } else { + int frac; + numdecrypt = numbytes; + frac = numdecrypt % blocksize; + if (frac) { + /* not an aligned amount of blocks, + align it */ + numdecrypt -= frac; + /* and make it no unencrypted data + after it */ + numbytes = 0; + } + } + } else { + /* unencrypted data should not be decrypted at all */ + numdecrypt = 0; + } + + /* if there are bytes to decrypt, do that */ + if (numdecrypt > 0) { + /* now decrypt the lot */ + rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt); + if (rc != LIBSSH2_ERROR_NONE) { + return rc; + } + + /* advance the read pointer */ + p->readidx += numdecrypt; + /* advance write pointer */ + p->wptr += numdecrypt; + /* increse data_num */ + p->data_num += numdecrypt; + + /* bytes left to take care of without decryption */ + numbytes -= numdecrypt; + } + + /* if there are bytes to copy that aren't decrypted, simply + copy them as-is to the target buffer */ + if (numbytes > 0) { + memcpy(p->wptr, &p->buf[p->readidx], numbytes); + + /* advance the read pointer */ + p->readidx += numbytes; + /* advance write pointer */ + p->wptr += numbytes; + /* increse data_num */ + p->data_num += numbytes; + } + + /* now check how much data there's left to read to finish the + current packet */ + remainpack = p->total_num - p->data_num; + + if (!remainpack) { + /* we have a full packet */ + libssh2_transport_read_point1: + rc = fullpacket(session, encrypted); + if (rc == LIBSSH2_ERROR_EAGAIN) { + + if (session->packAdd_state != libssh2_NB_state_idle) + { + /* fullpacket only returns LIBSSH2_ERROR_EAGAIN if + * libssh2_packet_add returns LIBSSH2_ERROR_EAGAIN. If that + * returns LIBSSH2_ERROR_EAGAIN but the packAdd_state is idle, + * then the packet has been added to the brigade, but some + * immediate action that was taken based on the packet + * type (such as key re-exchange) is not yet complete. + * Clear the way for a new packet to be read in. + */ + session->readPack_encrypted = encrypted; + session->readPack_state = libssh2_NB_state_jump1; + } + + return rc; + } + + p->total_num = 0; /* no packet buffer available */ + + return rc; + } + } while (1); /* loop */ + + return LIBSSH2_ERROR_SOCKET_RECV; /* we never reach this point */ +} + +static int +send_existing(LIBSSH2_SESSION *session, const unsigned char *data, + size_t data_len, ssize_t *ret) +{ + ssize_t rc; + ssize_t length; + struct transportpacket *p = &session->packet; + + if (!p->olen) { + *ret = 0; + return LIBSSH2_ERROR_NONE; + } + + /* send as much as possible of the existing packet */ + if ((data != p->odata) || (data_len != p->olen)) { + /* When we are about to complete the sending of a packet, it is vital + that the caller doesn't try to send a new/different packet since + we don't add this one up until the previous one has been sent. To + make the caller really notice his/hers flaw, we return error for + this case */ + return LIBSSH2_ERROR_BAD_USE; + } + + *ret = 1; /* set to make our parent return */ + + /* number of bytes left to send */ + length = p->ototal_num - p->osent; + + rc = LIBSSH2_SEND(session, &p->outbuf[p->osent], length, + LIBSSH2_SOCKET_SEND_FLAGS(session)); + if (rc < 0) + _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + "Error sending %d bytes: %d", length, -rc); + else { + _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + "Sent %d/%d bytes at %p+%d", rc, length, p->outbuf, + p->osent); + debugdump(session, "libssh2_transport_write send()", + &p->outbuf[p->osent], rc); + } + + if (rc == length) { + /* the remainder of the package was sent */ + p->ototal_num = 0; + p->olen = 0; + /* we leave *ret set so that the parent returns as we MUST return back + a send success now, so that we don't risk sending EAGAIN later + which then would confuse the parent function */ + return LIBSSH2_ERROR_NONE; + + } + else if (rc < 0) { + /* nothing was sent */ + if (rc != -EAGAIN) + /* send failure! */ + return LIBSSH2_ERROR_SOCKET_SEND; + + session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND; + return LIBSSH2_ERROR_EAGAIN; + } + + p->osent += rc; /* we sent away this much data */ + + return rc < length ? LIBSSH2_ERROR_EAGAIN : LIBSSH2_ERROR_NONE; +} + +/* + * libssh2_transport_send + * + * Send a packet, encrypting it and adding a MAC code if necessary + * Returns 0 on success, non-zero on failure. + * + * The data is provided as _two_ data areas that are combined by this + * function. The 'data' part is sent immediately before 'data2'. 'data2' may + * be set to NULL to only use a single part. + * + * Returns LIBSSH2_ERROR_EAGAIN if it would block or if the whole packet was + * not sent yet. If it does so, the caller should call this function again as + * soon as it is likely that more data can be sent, and this function MUST + * then be called with the same argument set (same data pointer and same + * data_len) until ERROR_NONE or failure is returned. + * + * This function DOES NOT call _libssh2_error() on any errors. + */ +int _libssh2_transport_send(LIBSSH2_SESSION *session, + const unsigned char *data, size_t data_len, + const unsigned char *data2, size_t data2_len) +{ + int blocksize = + (session->state & LIBSSH2_STATE_NEWKEYS) ? + session->local.crypt->blocksize : 8; + int padding_length; + size_t packet_length; + int total_length; +#ifdef RANDOM_PADDING + int rand_max; + int seed = data[0]; /* FIXME: make this random */ +#endif + struct transportpacket *p = &session->packet; + int encrypted; + ssize_t ret; + int rc; + const unsigned char *orgdata = data; + size_t orgdata_len = data_len; + + /* + * If the last read operation was interrupted in the middle of a key + * exchange, we must complete that key exchange before continuing to write + * further data. + * + * See the similar block in _libssh2_transport_read for more details. + */ + if (session->state & LIBSSH2_STATE_EXCHANGING_KEYS && + !(session->state & LIBSSH2_STATE_KEX_ACTIVE)) { + /* Don't write any new packets if we're still in the middle of a key + * exchange. */ + _libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Redirecting into the" + " key re-exchange from _libssh2_transport_send"); + rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state); + if (rc) + return rc; + } + + debugdump(session, "libssh2_transport_write plain", data, data_len); + if(data2) + debugdump(session, "libssh2_transport_write plain2", data2, data2_len); + + /* FIRST, check if we have a pending write to complete. send_existing + only sanity-check data and data_len and not data2 and data2_len!! */ + rc = send_existing(session, data, data_len, &ret); + if (rc) + return rc; + + session->socket_block_directions &= ~LIBSSH2_SESSION_BLOCK_OUTBOUND; + + if (ret) + /* set by send_existing if data was sent */ + return rc; + + encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0; + + if (encrypted && session->local.comp->compress) { + /* the idea here is that these function must fail if the output gets + larger than what fits in the assigned buffer so thus they don't + check the input size as we don't know how much it compresses */ + size_t dest_len = MAX_SSH_PACKET_LEN-5-256; + size_t dest2_len = dest_len; + + /* compress directly to the target buffer */ + rc = session->local.comp->comp(session, + &p->outbuf[5], &dest_len, + data, data_len, + &session->local.comp_abstract); + if(rc) + return rc; /* compression failure */ + + if(data2 && data2_len) { + /* compress directly to the target buffer right after where the + previous call put data */ + dest2_len -= dest_len; + + rc = session->local.comp->comp(session, + &p->outbuf[5+dest_len], &dest2_len, + data2, data2_len, + &session->local.comp_abstract); + } + else + dest2_len = 0; + if(rc) + return rc; /* compression failure */ + + data_len = dest_len + dest2_len; /* use the combined length */ + } + else { + if((data_len + data2_len) >= (MAX_SSH_PACKET_LEN-0x100)) + /* too large packet, return error for this until we make this + function split it up and send multiple SSH packets */ + return LIBSSH2_ERROR_INVAL; + + /* copy the payload data */ + memcpy(&p->outbuf[5], data, data_len); + if(data2 && data2_len) + memcpy(&p->outbuf[5+data_len], data2, data2_len); + data_len += data2_len; /* use the combined length */ + } + + + /* RFC4253 says: Note that the length of the concatenation of + 'packet_length', 'padding_length', 'payload', and 'random padding' + MUST be a multiple of the cipher block size or 8, whichever is + larger. */ + + /* Plain math: (4 + 1 + packet_length + padding_length) % blocksize == 0 */ + + packet_length = data_len + 1 + 4; /* 1 is for padding_length field + 4 for the packet_length field */ + + /* at this point we have it all except the padding */ + + /* first figure out our minimum padding amount to make it an even + block size */ + padding_length = blocksize - (packet_length % blocksize); + + /* if the padding becomes too small we add another blocksize worth + of it (taken from the original libssh2 where it didn't have any + real explanation) */ + if (padding_length < 4) { + padding_length += blocksize; + } +#ifdef RANDOM_PADDING + /* FIXME: we can add padding here, but that also makes the packets + bigger etc */ + + /* now we can add 'blocksize' to the padding_length N number of times + (to "help thwart traffic analysis") but it must be less than 255 in + total */ + rand_max = (255 - padding_length) / blocksize + 1; + padding_length += blocksize * (seed % rand_max); +#endif + + packet_length += padding_length; + + /* append the MAC length to the total_length size */ + total_length = + packet_length + (encrypted ? session->local.mac->mac_len : 0); + + /* store packet_length, which is the size of the whole packet except + the MAC and the packet_length field itself */ + _libssh2_htonu32(p->outbuf, packet_length - 4); + /* store padding_length */ + p->outbuf[4] = padding_length; + + /* fill the padding area with random junk */ + _libssh2_random(p->outbuf + 5 + data_len, padding_length); + + if (encrypted) { + size_t i; + + /* Calculate MAC hash. Put the output at index packet_length, + since that size includes the whole packet. The MAC is + calculated on the entire unencrypted packet, including all + fields except the MAC field itself. */ + session->local.mac->hash(session, p->outbuf + packet_length, + session->local.seqno, p->outbuf, + packet_length, NULL, 0, + &session->local.mac_abstract); + + /* Encrypt the whole packet data, one block size at a time. + The MAC field is not encrypted. */ + for(i = 0; i < packet_length; i += session->local.crypt->blocksize) { + unsigned char *ptr = &p->outbuf[i]; + if (session->local.crypt->crypt(session, ptr, + &session->local.crypt_abstract)) + return LIBSSH2_ERROR_ENCRYPT; /* encryption failure */ + } + } + + session->local.seqno++; + + ret = LIBSSH2_SEND(session, p->outbuf, total_length, + LIBSSH2_SOCKET_SEND_FLAGS(session)); + if (ret < 0) + _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, + "Error sending %d bytes: %d", total_length, -ret); + else { + _libssh2_debug(session, LIBSSH2_TRACE_SOCKET, "Sent %d/%d bytes at %p", + ret, total_length, p->outbuf); + debugdump(session, "libssh2_transport_write send()", p->outbuf, ret); + } + + if (ret != total_length) { + if (ret >= 0 || ret == -EAGAIN) { + /* the whole packet could not be sent, save the rest */ + session->socket_block_directions |= LIBSSH2_SESSION_BLOCK_OUTBOUND; + p->odata = orgdata; + p->olen = orgdata_len; + p->osent = ret <= 0 ? 0 : ret; + p->ototal_num = total_length; + return LIBSSH2_ERROR_EAGAIN; + } + return LIBSSH2_ERROR_SOCKET_SEND; + } + + /* the whole thing got sent away */ + p->odata = NULL; + p->olen = 0; + + return LIBSSH2_ERROR_NONE; /* all is good */ +} diff --git a/vendor/libssh2-1.4.2/src/transport.h b/vendor/libssh2-1.4.2/src/transport.h new file mode 100644 index 0000000..89982a6 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/transport.h @@ -0,0 +1,87 @@ +#ifndef __LIBSSH2_TRANSPORT_H +#define __LIBSSH2_TRANSPORT_H + +/* Copyright (C) 2007 The Written Word, Inc. All rights reserved. + * Copyright (C) 2009-2010 by Daniel Stenberg + * Author: Daniel Stenberg + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file handles reading and writing to the SECSH transport layer. RFC4253. + */ + +#include "libssh2_priv.h" +#include "packet.h" + + +/* + * libssh2_transport_send + * + * Send a packet, encrypting it and adding a MAC code if necessary + * Returns 0 on success, non-zero on failure. + * + * The data is provided as _two_ data areas that are combined by this + * function. The 'data' part is sent immediately before 'data2'. 'data2' can + * be set to NULL (or data2_len to 0) to only use a single part. + * + * Returns LIBSSH2_ERROR_EAGAIN if it would block or if the whole packet was + * not sent yet. If it does so, the caller should call this function again as + * soon as it is likely that more data can be sent, and this function MUST + * then be called with the same argument set (same data pointer and same + * data_len) until ERROR_NONE or failure is returned. + * + * This function DOES NOT call _libssh2_error() on any errors. + */ +int _libssh2_transport_send(LIBSSH2_SESSION *session, + const unsigned char *data, size_t data_len, + const unsigned char *data2, size_t data2_len); + +/* + * _libssh2_transport_read + * + * Collect a packet into the input brigade block only controls whether or not + * to wait for a packet to start. + * + * Returns packet type added to input brigade (PACKET_NONE if nothing added), + * or PACKET_FAIL on failure and PACKET_EAGAIN if it couldn't process a full + * packet. + */ + +/* + * This function reads the binary stream as specified in chapter 6 of RFC4253 + * "The Secure Shell (SSH) Transport Layer Protocol" + */ +int _libssh2_transport_read(LIBSSH2_SESSION * session); + +#endif /* __LIBSSH2_TRANSPORT_H */ diff --git a/vendor/libssh2-1.4.2/src/userauth.c b/vendor/libssh2-1.4.2/src/userauth.c new file mode 100644 index 0000000..a0733d5 --- /dev/null +++ b/vendor/libssh2-1.4.2/src/userauth.c @@ -0,0 +1,1687 @@ +/* Copyright (c) 2004-2007, Sara Golemon + * Copyright (c) 2005 Mikhail Gusarov + * Copyright (c) 2009-2011 by Daniel Stenberg + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +#include "libssh2_priv.h" + +#include +#include + +#include + +/* Needed for struct iovec on some platforms */ +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#include "transport.h" +#include "session.h" +#include "userauth.h" + +/* libssh2_userauth_list + * + * List authentication methods + * Will yield successful login if "none" happens to be allowable for this user + * Not a common configuration for any SSH server though + * username should be NULL, or a null terminated string + */ +static char *userauth_list(LIBSSH2_SESSION *session, const char *username, + unsigned int username_len) +{ + static const unsigned char reply_codes[3] = + { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 }; + /* packet_type(1) + username_len(4) + service_len(4) + + service(14)"ssh-connection" + method_len(4) = 27 */ + unsigned long methods_len; + unsigned char *s; + int rc; + + if (session->userauth_list_state == libssh2_NB_state_idle) { + /* Zero the whole thing out */ + memset(&session->userauth_list_packet_requirev_state, 0, + sizeof(session->userauth_list_packet_requirev_state)); + + session->userauth_list_data_len = username_len + 27; + + s = session->userauth_list_data = + LIBSSH2_ALLOC(session, session->userauth_list_data_len); + if (!session->userauth_list_data) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for userauth_list"); + return NULL; + } + + *(s++) = SSH_MSG_USERAUTH_REQUEST; + _libssh2_store_str(&s, username, username_len); + _libssh2_store_str(&s, "ssh-connection", 14); + _libssh2_store_u32(&s, 4); /* send "none" separately */ + + session->userauth_list_state = libssh2_NB_state_created; + } + + if (session->userauth_list_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, session->userauth_list_data, + session->userauth_list_data_len, + (unsigned char *)"none", 4); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block requesting userauth list"); + return NULL; + } + /* now free the packet that was sent */ + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + + if (rc) { + _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send userauth-none request"); + session->userauth_list_state = libssh2_NB_state_idle; + return NULL; + } + + session->userauth_list_state = libssh2_NB_state_sent; + } + + if (session->userauth_list_state == libssh2_NB_state_sent) { + rc = _libssh2_packet_requirev(session, reply_codes, + &session->userauth_list_data, + &session->userauth_list_data_len, 0, + NULL, 0, + &session->userauth_list_packet_requirev_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block requesting userauth list"); + return NULL; + } else if (rc) { + _libssh2_error(session, rc, "Failed getting response"); + session->userauth_list_state = libssh2_NB_state_idle; + return NULL; + } + + if (session->userauth_list_data[0] == SSH_MSG_USERAUTH_SUCCESS) { + /* Wow, who'dve thought... */ + _libssh2_error(session, LIBSSH2_ERROR_NONE, "No error"); + LIBSSH2_FREE(session, session->userauth_list_data); + session->userauth_list_data = NULL; + session->state |= LIBSSH2_STATE_AUTHENTICATED; + session->userauth_list_state = libssh2_NB_state_idle; + return NULL; + } + + methods_len = _libssh2_ntohu32(session->userauth_list_data + 1); + + /* Do note that the memory areas overlap! */ + memmove(session->userauth_list_data, session->userauth_list_data + 5, + methods_len); + session->userauth_list_data[methods_len] = '\0'; + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Permitted auth methods: %s", + session->userauth_list_data); + } + + session->userauth_list_state = libssh2_NB_state_idle; + return (char *) session->userauth_list_data; +} + +/* libssh2_userauth_list + * + * List authentication methods + * Will yield successful login if "none" happens to be allowable for this user + * Not a common configuration for any SSH server though + * username should be NULL, or a null terminated string + */ +LIBSSH2_API char * +libssh2_userauth_list(LIBSSH2_SESSION * session, const char *user, + unsigned int user_len) +{ + char *ptr; + BLOCK_ADJUST_ERRNO(ptr, session, + userauth_list(session, user, user_len)); + return ptr; +} + +/* + * libssh2_userauth_authenticated + * + * Returns: 0 if not yet authenticated + * 1 if already authenticated + */ +LIBSSH2_API int +libssh2_userauth_authenticated(LIBSSH2_SESSION * session) +{ + return (session->state & LIBSSH2_STATE_AUTHENTICATED)?1:0; +} + + + +/* userauth_password + * Plain ol' login + */ +static int +userauth_password(LIBSSH2_SESSION *session, + const char *username, unsigned int username_len, + const unsigned char *password, unsigned int password_len, + LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb))) +{ + unsigned char *s; + static const unsigned char reply_codes[4] = + { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, + SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0 + }; + int rc; + + if (session->userauth_pswd_state == libssh2_NB_state_idle) { + /* Zero the whole thing out */ + memset(&session->userauth_pswd_packet_requirev_state, 0, + sizeof(session->userauth_pswd_packet_requirev_state)); + + /* + * 40 = acket_type(1) + username_len(4) + service_len(4) + + * service(14)"ssh-connection" + method_len(4) + method(8)"password" + + * chgpwdbool(1) + password_len(4) */ + session->userauth_pswd_data_len = username_len + 40; + + session->userauth_pswd_data0 = ~SSH_MSG_USERAUTH_PASSWD_CHANGEREQ; + + /* TODO: remove this alloc with a fixed buffer in the session + struct */ + s = session->userauth_pswd_data = + LIBSSH2_ALLOC(session, session->userauth_pswd_data_len); + if (!session->userauth_pswd_data) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "userauth-password request"); + } + + *(s++) = SSH_MSG_USERAUTH_REQUEST; + _libssh2_store_str(&s, username, username_len); + _libssh2_store_str(&s, "ssh-connection", sizeof("ssh-connection") - 1); + _libssh2_store_str(&s, "password", sizeof("password") - 1); + *s++ = '\0'; + _libssh2_store_u32(&s, password_len); + /* 'password' is sent separately */ + + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Attempting to login using password authentication"); + + session->userauth_pswd_state = libssh2_NB_state_created; + } + + if (session->userauth_pswd_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, session->userauth_pswd_data, + session->userauth_pswd_data_len, + password, password_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block writing password request"); + } + + /* now free the sent packet */ + LIBSSH2_FREE(session, session->userauth_pswd_data); + session->userauth_pswd_data = NULL; + + if (rc) { + session->userauth_pswd_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send userauth-password request"); + } + + session->userauth_pswd_state = libssh2_NB_state_sent; + } + + password_response: + + if ((session->userauth_pswd_state == libssh2_NB_state_sent) + || (session->userauth_pswd_state == libssh2_NB_state_sent1) + || (session->userauth_pswd_state == libssh2_NB_state_sent2)) { + if (session->userauth_pswd_state == libssh2_NB_state_sent) { + rc = _libssh2_packet_requirev(session, reply_codes, + &session->userauth_pswd_data, + &session->userauth_pswd_data_len, + 0, NULL, 0, + &session-> + userauth_pswd_packet_requirev_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block waiting"); + } else if (rc) { + session->userauth_pswd_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, + "Would block waiting"); + } + + if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_SUCCESS) { + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Password authentication successful"); + LIBSSH2_FREE(session, session->userauth_pswd_data); + session->userauth_pswd_data = NULL; + session->state |= LIBSSH2_STATE_AUTHENTICATED; + session->userauth_pswd_state = libssh2_NB_state_idle; + return 0; + } else if (session->userauth_pswd_data[0] == SSH_MSG_USERAUTH_FAILURE) { + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Password authentication failed"); + LIBSSH2_FREE(session, session->userauth_pswd_data); + session->userauth_pswd_data = NULL; + session->userauth_pswd_state = libssh2_NB_state_idle; + return _libssh2_error(session, + LIBSSH2_ERROR_AUTHENTICATION_FAILED, + "Authentication failed " + "(username/password)"); + } + + session->userauth_pswd_newpw = NULL; + session->userauth_pswd_newpw_len = 0; + + session->userauth_pswd_state = libssh2_NB_state_sent1; + } + + if ((session->userauth_pswd_data[0] == + SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) + || (session->userauth_pswd_data0 == + SSH_MSG_USERAUTH_PASSWD_CHANGEREQ)) { + session->userauth_pswd_data0 = SSH_MSG_USERAUTH_PASSWD_CHANGEREQ; + + if ((session->userauth_pswd_state == libssh2_NB_state_sent1) || + (session->userauth_pswd_state == libssh2_NB_state_sent2)) { + if (session->userauth_pswd_state == libssh2_NB_state_sent1) { + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Password change required"); + LIBSSH2_FREE(session, session->userauth_pswd_data); + session->userauth_pswd_data = NULL; + } + if (passwd_change_cb) { + if (session->userauth_pswd_state == libssh2_NB_state_sent1) { + passwd_change_cb(session, + &session->userauth_pswd_newpw, + &session->userauth_pswd_newpw_len, + &session->abstract); + if (!session->userauth_pswd_newpw) { + return _libssh2_error(session, + LIBSSH2_ERROR_PASSWORD_EXPIRED, + "Password expired, and " + "callback failed"); + } + + /* basic data_len + newpw_len(4) */ + session->userauth_pswd_data_len = + username_len + password_len + 44; + + s = session->userauth_pswd_data = + LIBSSH2_ALLOC(session, + session->userauth_pswd_data_len); + if (!session->userauth_pswd_data) { + LIBSSH2_FREE(session, + session->userauth_pswd_newpw); + session->userauth_pswd_newpw = NULL; + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory " + "for userauth password " + "change request"); + } + + *(s++) = SSH_MSG_USERAUTH_REQUEST; + _libssh2_store_str(&s, username, username_len); + _libssh2_store_str(&s, "ssh-connection", + sizeof("ssh-connection") - 1); + _libssh2_store_str(&s, "password", + sizeof("password") - 1); + *s++ = 0x01; + _libssh2_store_str(&s, (char *)password, password_len); + _libssh2_store_u32(&s, + session->userauth_pswd_newpw_len); + /* send session->userauth_pswd_newpw separately */ + + session->userauth_pswd_state = libssh2_NB_state_sent2; + } + + if (session->userauth_pswd_state == libssh2_NB_state_sent2) { + rc = _libssh2_transport_send(session, + session->userauth_pswd_data, + session->userauth_pswd_data_len, + (unsigned char *) + session->userauth_pswd_newpw, + session->userauth_pswd_newpw_len); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block waiting"); + } + + /* free the allocated packets again */ + LIBSSH2_FREE(session, session->userauth_pswd_data); + session->userauth_pswd_data = NULL; + LIBSSH2_FREE(session, session->userauth_pswd_newpw); + session->userauth_pswd_newpw = NULL; + + if (rc) { + return _libssh2_error(session, + LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send userauth " + "password-change request"); + } + + /* + * Ugliest use of goto ever. Blame it on the + * askN => requirev migration. + */ + session->userauth_pswd_state = libssh2_NB_state_sent; + goto password_response; + } + } + } else { + session->userauth_pswd_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, + "Password Expired, and no callback " + "specified"); + } + } + } + + /* FAILURE */ + LIBSSH2_FREE(session, session->userauth_pswd_data); + session->userauth_pswd_data = NULL; + session->userauth_pswd_state = libssh2_NB_state_idle; + + return _libssh2_error(session, LIBSSH2_ERROR_AUTHENTICATION_FAILED, + "Authentication failed"); +} + +/* + * libssh2_userauth_password_ex + * + * Plain ol' login + */ + +LIBSSH2_API int +libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, + unsigned int username_len, const char *password, + unsigned int password_len, + LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb))) +{ + int rc; + BLOCK_ADJUST(rc, session, + userauth_password(session, username, username_len, + (unsigned char *)password, password_len, + passwd_change_cb)); + return rc; +} + +/* + * file_read_publickey + * + * Read a public key from an id_???.pub style file + * + * Returns an allocated string containing the decoded key in *pubkeydata + * on success. + * Returns an allocated string containing the key method (e.g. "ssh-dss") + * in method on success. + */ +static int +file_read_publickey(LIBSSH2_SESSION * session, unsigned char **method, + size_t *method_len, + unsigned char **pubkeydata, + size_t *pubkeydata_len, + const char *pubkeyfile) +{ + FILE *fd; + char c; + unsigned char *pubkey = NULL, *sp1, *sp2, *tmp; + size_t pubkey_len = 0; + unsigned int tmp_len; + + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading public key file: %s", + pubkeyfile); + /* Read Public Key */ + fd = fopen(pubkeyfile, "r"); + if (!fd) { + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to open public key file"); + } + while (!feof(fd) && 1 == fread(&c, 1, 1, fd) && c != '\r' && c != '\n') + pubkey_len++; + if (feof(fd)) { + /* the last character was EOF */ + pubkey_len--; + } + rewind(fd); + + if (pubkey_len <= 1) { + fclose(fd); + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Invalid data in public key file"); + } + + pubkey = LIBSSH2_ALLOC(session, pubkey_len); + if (!pubkey) { + fclose(fd); + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for public key data"); + } + if (fread(pubkey, 1, pubkey_len, fd) != pubkey_len) { + LIBSSH2_FREE(session, pubkey); + fclose(fd); + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to read public key from file"); + } + fclose(fd); + /* + * Remove trailing whitespace + */ + while (pubkey_len && isspace(pubkey[pubkey_len - 1])) + pubkey_len--; + + if (!pubkey_len) { + LIBSSH2_FREE(session, pubkey); + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Missing public key data"); + } + + if ((sp1 = memchr(pubkey, ' ', pubkey_len)) == NULL) { + LIBSSH2_FREE(session, pubkey); + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Invalid public key data"); + } + + sp1++; + + if ((sp2 = memchr(sp1, ' ', pubkey_len - (sp1 - pubkey - 1))) == NULL) { + /* Assume that the id string is missing, but that it's okay */ + sp2 = pubkey + pubkey_len; + } + + if (libssh2_base64_decode(session, (char **) &tmp, &tmp_len, + (char *) sp1, sp2 - sp1)) { + LIBSSH2_FREE(session, pubkey); + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Invalid key data, not base64 encoded"); + } + + /* Wasting some bytes here (okay, more than some), but since it's likely + * to be freed soon anyway, we'll just avoid the extra free/alloc and call + * it a wash */ + *method = pubkey; + *method_len = sp1 - pubkey - 1; + + *pubkeydata = tmp; + *pubkeydata_len = tmp_len; + + return 0; +} + + + +/* libssh2_file_read_privatekey + * Read a PEM encoded private key from an id_??? style file + */ +static int +file_read_privatekey(LIBSSH2_SESSION * session, + const LIBSSH2_HOSTKEY_METHOD ** hostkey_method, + void **hostkey_abstract, + const unsigned char *method, int method_len, + const char *privkeyfile, const char *passphrase) +{ + const LIBSSH2_HOSTKEY_METHOD **hostkey_methods_avail = + libssh2_hostkey_methods(); + + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, "Loading private key file: %s", + privkeyfile); + *hostkey_method = NULL; + *hostkey_abstract = NULL; + while (*hostkey_methods_avail && (*hostkey_methods_avail)->name) { + if ((*hostkey_methods_avail)->initPEM + && strncmp((*hostkey_methods_avail)->name, (const char *) method, + method_len) == 0) { + *hostkey_method = *hostkey_methods_avail; + break; + } + hostkey_methods_avail++; + } + if (!*hostkey_method) { + return _libssh2_error(session, LIBSSH2_ERROR_METHOD_NONE, + "No handler for specified private key"); + } + + if ((*hostkey_method)-> + initPEM(session, privkeyfile, (unsigned char *) passphrase, + hostkey_abstract)) { + return _libssh2_error(session, LIBSSH2_ERROR_FILE, + "Unable to initialize private key from file"); + } + + return 0; +} + +struct privkey_file { + const char *filename; + const char *passphrase; +}; + +static int +sign_fromfile(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, + const unsigned char *data, size_t data_len, void **abstract) +{ + struct privkey_file *privkey_file = (struct privkey_file *) (*abstract); + const LIBSSH2_HOSTKEY_METHOD *privkeyobj; + void *hostkey_abstract; + struct iovec datavec; + int rc; + + rc = file_read_privatekey(session, &privkeyobj, &hostkey_abstract, + session->userauth_pblc_method, + session->userauth_pblc_method_len, + privkey_file->filename, + privkey_file->passphrase); + if(rc) + return rc; + + datavec.iov_base = (void *)data; + datavec.iov_len = data_len; + + if (privkeyobj->signv(session, sig, sig_len, 1, &datavec, + &hostkey_abstract)) { + if (privkeyobj->dtor) { + privkeyobj->dtor(session, abstract); + } + return -1; + } + + if (privkeyobj->dtor) { + privkeyobj->dtor(session, &hostkey_abstract); + } + return 0; +} + + + +/* userauth_hostbased_fromfile + * Authenticate using a keypair found in the named files + */ +static int +userauth_hostbased_fromfile(LIBSSH2_SESSION *session, + const char *username, size_t username_len, + const char *publickey, const char *privatekey, + const char *passphrase, const char *hostname, + size_t hostname_len, + const char *local_username, + size_t local_username_len) +{ + int rc; + + if (session->userauth_host_state == libssh2_NB_state_idle) { + const LIBSSH2_HOSTKEY_METHOD *privkeyobj; + unsigned char *pubkeydata, *sig; + size_t pubkeydata_len; + size_t sig_len; + void *abstract; + unsigned char buf[5]; + struct iovec datavec[4]; + + /* Zero the whole thing out */ + memset(&session->userauth_host_packet_requirev_state, 0, + sizeof(session->userauth_host_packet_requirev_state)); + + if (publickey) { + rc = file_read_publickey(session, &session->userauth_host_method, + &session->userauth_host_method_len, + &pubkeydata, &pubkeydata_len, publickey); + if(rc) + /* Note: file_read_publickey() calls _libssh2_error() */ + return rc; + } + else { + /* Compute public key from private key. */ + rc = _libssh2_pub_priv_keyfile(session, + &session->userauth_host_method, + &session->userauth_host_method_len, + &pubkeydata, &pubkeydata_len, + privatekey, passphrase); + if (rc) + /* libssh2_pub_priv_keyfile calls _libssh2_error() */ + return rc; + } + + /* + * 52 = packet_type(1) + username_len(4) + servicename_len(4) + + * service_name(14)"ssh-connection" + authmethod_len(4) + + * authmethod(9)"hostbased" + method_len(4) + pubkeydata_len(4) + + * hostname_len(4) + local_username_len(4) + */ + session->userauth_host_packet_len = + username_len + session->userauth_host_method_len + hostname_len + + local_username_len + pubkeydata_len + 52; + + /* + * Preallocate space for an overall length, method name again, + * and the signature, which won't be any larger than the size of + * the publickeydata itself + */ + session->userauth_host_s = session->userauth_host_packet = + LIBSSH2_ALLOC(session, + session->userauth_host_packet_len + 4 + + (4 + session->userauth_host_method_len) + + (4 + pubkeydata_len)); + if (!session->userauth_host_packet) { + LIBSSH2_FREE(session, session->userauth_host_method); + session->userauth_host_method = NULL; + LIBSSH2_FREE(session, pubkeydata); + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Out of memory"); + } + + *(session->userauth_host_s++) = SSH_MSG_USERAUTH_REQUEST; + _libssh2_store_str(&session->userauth_host_s, username, username_len); + _libssh2_store_str(&session->userauth_host_s, "ssh-connection", 14); + _libssh2_store_str(&session->userauth_host_s, "hostbased", 9); + _libssh2_store_str(&session->userauth_host_s, + (const char *)session->userauth_host_method, + session->userauth_host_method_len); + _libssh2_store_str(&session->userauth_host_s, (const char *)pubkeydata, + pubkeydata_len); + LIBSSH2_FREE(session, pubkeydata); + _libssh2_store_str(&session->userauth_host_s, hostname, hostname_len); + _libssh2_store_str(&session->userauth_host_s, local_username, + local_username_len); + + rc = file_read_privatekey(session, &privkeyobj, &abstract, + session->userauth_host_method, + session->userauth_host_method_len, + privatekey, passphrase); + if(rc) { + /* Note: file_read_privatekey() calls _libssh2_error() */ + LIBSSH2_FREE(session, session->userauth_host_method); + session->userauth_host_method = NULL; + LIBSSH2_FREE(session, session->userauth_host_packet); + session->userauth_host_packet = NULL; + return rc; + } + + _libssh2_htonu32(buf, session->session_id_len); + datavec[0].iov_base = (void *)buf; + datavec[0].iov_len = 4; + datavec[1].iov_base = (void *)session->session_id; + datavec[1].iov_len = session->session_id_len; + datavec[2].iov_base = (void *)session->userauth_host_packet; + datavec[2].iov_len = session->userauth_host_packet_len; + + if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) { + LIBSSH2_FREE(session, session->userauth_host_method); + session->userauth_host_method = NULL; + LIBSSH2_FREE(session, session->userauth_host_packet); + session->userauth_host_packet = NULL; + if (privkeyobj->dtor) { + privkeyobj->dtor(session, &abstract); + } + return -1; + } + + if (privkeyobj->dtor) { + privkeyobj->dtor(session, &abstract); + } + + if (sig_len > pubkeydata_len) { + unsigned char *newpacket; + /* Should *NEVER* happen, but...well.. better safe than sorry */ + newpacket = LIBSSH2_REALLOC(session, session->userauth_host_packet, + session->userauth_host_packet_len + 4 + + (4 + session->userauth_host_method_len) + + (4 + sig_len)); /* PK sigblob */ + if (!newpacket) { + LIBSSH2_FREE(session, sig); + LIBSSH2_FREE(session, session->userauth_host_packet); + session->userauth_host_packet = NULL; + LIBSSH2_FREE(session, session->userauth_host_method); + session->userauth_host_method = NULL; + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed allocating additional space for " + "userauth-hostbased packet"); + } + session->userauth_host_packet = newpacket; + } + + session->userauth_host_s = + session->userauth_host_packet + session->userauth_host_packet_len; + + _libssh2_store_u32(&session->userauth_host_s, + 4 + session->userauth_host_method_len + 4 + sig_len); + _libssh2_store_str(&session->userauth_host_s, + (const char *)session->userauth_host_method, + session->userauth_host_method_len); + LIBSSH2_FREE(session, session->userauth_host_method); + session->userauth_host_method = NULL; + + _libssh2_store_str(&session->userauth_host_s, (const char *)sig, + sig_len); + LIBSSH2_FREE(session, sig); + + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Attempting hostbased authentication"); + + session->userauth_host_state = libssh2_NB_state_created; + } + + if (session->userauth_host_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, session->userauth_host_packet, + session->userauth_host_s - + session->userauth_host_packet, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); + } + else if (rc) { + LIBSSH2_FREE(session, session->userauth_host_packet); + session->userauth_host_packet = NULL; + session->userauth_host_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send userauth-hostbased request"); + } + LIBSSH2_FREE(session, session->userauth_host_packet); + session->userauth_host_packet = NULL; + + session->userauth_host_state = libssh2_NB_state_sent; + } + + if (session->userauth_host_state == libssh2_NB_state_sent) { + static const unsigned char reply_codes[3] = + { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 }; + size_t data_len; + rc = _libssh2_packet_requirev(session, reply_codes, + &session->userauth_host_data, + &data_len, 0, NULL, 0, + &session-> + userauth_host_packet_requirev_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); + } + + session->userauth_host_state = libssh2_NB_state_idle; + if (rc) { + return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, + "Auth failed"); + } + + if (session->userauth_host_data[0] == SSH_MSG_USERAUTH_SUCCESS) { + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Hostbased authentication successful"); + /* We are us and we've proved it. */ + LIBSSH2_FREE(session, session->userauth_host_data); + session->userauth_host_data = NULL; + session->state |= LIBSSH2_STATE_AUTHENTICATED; + return 0; + } + } + + /* This public key is not allowed for this user on this server */ + LIBSSH2_FREE(session, session->userauth_host_data); + session->userauth_host_data = NULL; + return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, + "Invalid signature for supplied public key, or bad " + "username/public key combination"); +} + +/* libssh2_userauth_hostbased_fromfile_ex + * Authenticate using a keypair found in the named files + */ +LIBSSH2_API int +libssh2_userauth_hostbased_fromfile_ex(LIBSSH2_SESSION *session, + const char *user, + unsigned int user_len, + const char *publickey, + const char *privatekey, + const char *passphrase, + const char *host, + unsigned int host_len, + const char *localuser, + unsigned int localuser_len) +{ + int rc; + BLOCK_ADJUST(rc, session, + userauth_hostbased_fromfile(session, user, user_len, + publickey, privatekey, + passphrase, host, host_len, + localuser, localuser_len)); + return rc; +} + + + +int +_libssh2_userauth_publickey(LIBSSH2_SESSION *session, + const char *username, + unsigned int username_len, + const unsigned char *pubkeydata, + unsigned long pubkeydata_len, + LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), + void *abstract) +{ + unsigned char reply_codes[4] = + { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, + SSH_MSG_USERAUTH_PK_OK, 0 + }; + int rc; + unsigned char *s; + + if (session->userauth_pblc_state == libssh2_NB_state_idle) { + + /* + * The call to _libssh2_ntohu32 later relies on pubkeydata having at + * least 4 valid bytes containing the length of the method name. + */ + if (pubkeydata_len < 4) + return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, + "Invalid public key, too short"); + + /* Zero the whole thing out */ + memset(&session->userauth_pblc_packet_requirev_state, 0, + sizeof(session->userauth_pblc_packet_requirev_state)); + + /* + * As an optimisation, userauth_publickey_fromfile reuses a + * previously allocated copy of the method name to avoid an extra + * allocation/free. + * For other uses, we allocate and populate it here. + */ + if (!session->userauth_pblc_method) { + session->userauth_pblc_method_len = _libssh2_ntohu32(pubkeydata); + + if(session->userauth_pblc_method_len > pubkeydata_len) + /* the method length simply cannot be longer than the entire + passed in data, so we use this to detect crazy input + data */ + return _libssh2_error(session, + LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, + "Invalid public key"); + + session->userauth_pblc_method = + LIBSSH2_ALLOC(session, session->userauth_pblc_method_len); + if (!session->userauth_pblc_method) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for public key " + "data"); + } + memcpy(session->userauth_pblc_method, pubkeydata + 4, + session->userauth_pblc_method_len); + } + /* + * The length of the method name read from plaintext prefix in the + * file must match length embedded in the key. + * TODO: The data should match too but we don't check that. Should we? + */ + else if (session->userauth_pblc_method_len != + _libssh2_ntohu32(pubkeydata)) + return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, + "Invalid public key"); + + /* + * 45 = packet_type(1) + username_len(4) + servicename_len(4) + + * service_name(14)"ssh-connection" + authmethod_len(4) + + * authmethod(9)"publickey" + sig_included(1)'\0' + algmethod_len(4) + + * publickey_len(4) + */ + session->userauth_pblc_packet_len = + username_len + session->userauth_pblc_method_len + pubkeydata_len + + 45; + + /* + * Preallocate space for an overall length, method name again, and the + * signature, which won't be any larger than the size of the + * publickeydata itself. + * + * Note that the 'pubkeydata_len' extra bytes allocated here will not + * be used in this first send, but will be used in the later one where + * this same allocation is re-used. + */ + s = session->userauth_pblc_packet = + LIBSSH2_ALLOC(session, + session->userauth_pblc_packet_len + 4 + + (4 + session->userauth_pblc_method_len) + + (4 + pubkeydata_len)); + if (!session->userauth_pblc_packet) { + LIBSSH2_FREE(session, session->userauth_pblc_method); + session->userauth_pblc_method = NULL; + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Out of memory"); + } + + *s++ = SSH_MSG_USERAUTH_REQUEST; + _libssh2_store_str(&s, username, username_len); + _libssh2_store_str(&s, "ssh-connection", 14); + _libssh2_store_str(&s, "publickey", 9); + + session->userauth_pblc_b = s; + /* Not sending signature with *this* packet */ + *s++ = 0; + + _libssh2_store_str(&s, (const char *)session->userauth_pblc_method, + session->userauth_pblc_method_len); + _libssh2_store_str(&s, (const char *)pubkeydata, pubkeydata_len); + + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Attempting publickey authentication"); + + session->userauth_pblc_state = libssh2_NB_state_created; + } + + if (session->userauth_pblc_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, session->userauth_pblc_packet, + session->userauth_pblc_packet_len, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) + return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); + else if (rc) { + LIBSSH2_FREE(session, session->userauth_pblc_packet); + session->userauth_pblc_packet = NULL; + LIBSSH2_FREE(session, session->userauth_pblc_method); + session->userauth_pblc_method = NULL; + session->userauth_pblc_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send userauth-publickey request"); + } + + session->userauth_pblc_state = libssh2_NB_state_sent; + } + + if (session->userauth_pblc_state == libssh2_NB_state_sent) { + rc = _libssh2_packet_requirev(session, reply_codes, + &session->userauth_pblc_data, + &session->userauth_pblc_data_len, 0, + NULL, 0, + &session-> + userauth_pblc_packet_requirev_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); + } + else if (rc) { + LIBSSH2_FREE(session, session->userauth_pblc_packet); + session->userauth_pblc_packet = NULL; + LIBSSH2_FREE(session, session->userauth_pblc_method); + session->userauth_pblc_method = NULL; + session->userauth_pblc_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, + "Waiting for USERAUTH response"); + } + + if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) { + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Pubkey authentication prematurely successful"); + /* + * God help any SSH server that allows an UNVERIFIED + * public key to validate the user + */ + LIBSSH2_FREE(session, session->userauth_pblc_data); + session->userauth_pblc_data = NULL; + LIBSSH2_FREE(session, session->userauth_pblc_packet); + session->userauth_pblc_packet = NULL; + LIBSSH2_FREE(session, session->userauth_pblc_method); + session->userauth_pblc_method = NULL; + session->state |= LIBSSH2_STATE_AUTHENTICATED; + session->userauth_pblc_state = libssh2_NB_state_idle; + return 0; + } + + if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_FAILURE) { + /* This public key is not allowed for this user on this server */ + LIBSSH2_FREE(session, session->userauth_pblc_data); + session->userauth_pblc_data = NULL; + LIBSSH2_FREE(session, session->userauth_pblc_packet); + session->userauth_pblc_packet = NULL; + LIBSSH2_FREE(session, session->userauth_pblc_method); + session->userauth_pblc_method = NULL; + session->userauth_pblc_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_AUTHENTICATION_FAILED, + "Username/PublicKey combination invalid"); + } + + /* Semi-Success! */ + LIBSSH2_FREE(session, session->userauth_pblc_data); + session->userauth_pblc_data = NULL; + + *session->userauth_pblc_b = 0x01; + session->userauth_pblc_state = libssh2_NB_state_sent1; + } + + if (session->userauth_pblc_state == libssh2_NB_state_sent1) { + unsigned char *buf; + unsigned char *sig; + size_t sig_len; + + s = buf = LIBSSH2_ALLOC(session, 4 + session->session_id_len + + session->userauth_pblc_packet_len); + if (!buf) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "userauth-publickey signed data"); + } + + _libssh2_store_str(&s, (const char *)session->session_id, + session->session_id_len); + + memcpy (s, session->userauth_pblc_packet, + session->userauth_pblc_packet_len); + s += session->userauth_pblc_packet_len; + + rc = sign_callback(session, &sig, &sig_len, buf, s - buf, abstract); + LIBSSH2_FREE(session, buf); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); + } else if (rc) { + LIBSSH2_FREE(session, session->userauth_pblc_method); + session->userauth_pblc_method = NULL; + LIBSSH2_FREE(session, session->userauth_pblc_packet); + session->userauth_pblc_packet = NULL; + session->userauth_pblc_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, + "Callback returned error"); + } + + /* + * If this function was restarted, pubkeydata_len might still be 0 + * which will cause an unnecessary but harmless realloc here. + */ + if (sig_len > pubkeydata_len) { + unsigned char *newpacket; + /* Should *NEVER* happen, but...well.. better safe than sorry */ + newpacket = LIBSSH2_REALLOC(session, + session->userauth_pblc_packet, + session->userauth_pblc_packet_len + 4 + + (4 + session->userauth_pblc_method_len) + + (4 + sig_len)); /* PK sigblob */ + if (!newpacket) { + LIBSSH2_FREE(session, sig); + LIBSSH2_FREE(session, session->userauth_pblc_packet); + session->userauth_pblc_packet = NULL; + LIBSSH2_FREE(session, session->userauth_pblc_method); + session->userauth_pblc_method = NULL; + session->userauth_pblc_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Failed allocating additional space for " + "userauth-publickey packet"); + } + session->userauth_pblc_packet = newpacket; + } + + s = session->userauth_pblc_packet + session->userauth_pblc_packet_len; + session->userauth_pblc_b = NULL; + + _libssh2_store_u32(&s, + 4 + session->userauth_pblc_method_len + 4 + sig_len); + _libssh2_store_str(&s, (const char *)session->userauth_pblc_method, + session->userauth_pblc_method_len); + + LIBSSH2_FREE(session, session->userauth_pblc_method); + session->userauth_pblc_method = NULL; + + _libssh2_store_str(&s, (const char *)sig, sig_len); + LIBSSH2_FREE(session, sig); + + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Attempting publickey authentication -- phase 2"); + + session->userauth_pblc_s = s; + session->userauth_pblc_state = libssh2_NB_state_sent2; + } + + if (session->userauth_pblc_state == libssh2_NB_state_sent2) { + rc = _libssh2_transport_send(session, session->userauth_pblc_packet, + session->userauth_pblc_s - + session->userauth_pblc_packet, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); + } else if (rc) { + LIBSSH2_FREE(session, session->userauth_pblc_packet); + session->userauth_pblc_packet = NULL; + session->userauth_pblc_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send userauth-publickey request"); + } + LIBSSH2_FREE(session, session->userauth_pblc_packet); + session->userauth_pblc_packet = NULL; + + session->userauth_pblc_state = libssh2_NB_state_sent3; + } + + /* PK_OK is no longer valid */ + reply_codes[2] = 0; + + rc = _libssh2_packet_requirev(session, reply_codes, + &session->userauth_pblc_data, + &session->userauth_pblc_data_len, 0, NULL, 0, + &session->userauth_pblc_packet_requirev_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block requesting userauth list"); + } else if (rc) { + session->userauth_pblc_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, + "Waiting for publickey USERAUTH response"); + } + + if (session->userauth_pblc_data[0] == SSH_MSG_USERAUTH_SUCCESS) { + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Publickey authentication successful"); + /* We are us and we've proved it. */ + LIBSSH2_FREE(session, session->userauth_pblc_data); + session->userauth_pblc_data = NULL; + session->state |= LIBSSH2_STATE_AUTHENTICATED; + session->userauth_pblc_state = libssh2_NB_state_idle; + return 0; + } + + /* This public key is not allowed for this user on this server */ + LIBSSH2_FREE(session, session->userauth_pblc_data); + session->userauth_pblc_data = NULL; + session->userauth_pblc_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, + "Invalid signature for supplied public key, or bad " + "username/public key combination"); +} + +/* + * userauth_publickey_fromfile + * Authenticate using a keypair found in the named files + */ +static int +userauth_publickey_fromfile(LIBSSH2_SESSION *session, + const char *username, + size_t username_len, + const char *publickey, + const char *privatekey, + const char *passphrase) +{ + unsigned char *pubkeydata = NULL; + size_t pubkeydata_len = 0; + struct privkey_file privkey_file; + void *abstract = &privkey_file; + int rc; + + privkey_file.filename = privatekey; + privkey_file.passphrase = passphrase; + + if (session->userauth_pblc_state == libssh2_NB_state_idle) { + if (publickey) { + rc = file_read_publickey(session, &session->userauth_pblc_method, + &session->userauth_pblc_method_len, + &pubkeydata, &pubkeydata_len,publickey); + if (rc) + return rc; + } + else { + /* Compute public key from private key. */ + rc = _libssh2_pub_priv_keyfile(session, + &session->userauth_pblc_method, + &session->userauth_pblc_method_len, + &pubkeydata, &pubkeydata_len, + privatekey, passphrase); + + /* _libssh2_pub_priv_keyfile calls _libssh2_error() */ + if (rc) + return rc; + } + } + + rc = _libssh2_userauth_publickey(session, username, username_len, + pubkeydata, pubkeydata_len, + sign_fromfile, &abstract); + if(pubkeydata) + LIBSSH2_FREE(session, pubkeydata); + + return rc; +} + +/* libssh2_userauth_publickey_fromfile_ex + * Authenticate using a keypair found in the named files + */ +LIBSSH2_API int +libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, + const char *user, + unsigned int user_len, + const char *publickey, + const char *privatekey, + const char *passphrase) +{ + int rc; + + if(NULL == passphrase) + /* if given a NULL pointer, make it point to a zero-length + string to save us from having to check this all over */ + passphrase=""; + + BLOCK_ADJUST(rc, session, + userauth_publickey_fromfile(session, user, user_len, + publickey, privatekey, + passphrase)); + return rc; +} + +/* libssh2_userauth_publickey_ex + * Authenticate using an external callback function + */ +LIBSSH2_API int +libssh2_userauth_publickey(LIBSSH2_SESSION *session, + const char *user, + const unsigned char *pubkeydata, + size_t pubkeydata_len, + LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), + void **abstract) +{ + int rc; + + if(!session) + return LIBSSH2_ERROR_BAD_USE; + + BLOCK_ADJUST(rc, session, + _libssh2_userauth_publickey(session, user, strlen(user), + pubkeydata, pubkeydata_len, + sign_callback, abstract)); + return rc; +} + + + +/* + * userauth_keyboard_interactive + * + * Authenticate using a challenge-response authentication + */ +static int +userauth_keyboard_interactive(LIBSSH2_SESSION * session, + const char *username, + unsigned int username_len, + LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback))) +{ + unsigned char *s; + int rc; + + static const unsigned char reply_codes[4] = { + SSH_MSG_USERAUTH_SUCCESS, + SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 + }; + unsigned int language_tag_len; + unsigned int i; + + if (session->userauth_kybd_state == libssh2_NB_state_idle) { + session->userauth_kybd_auth_name = NULL; + session->userauth_kybd_auth_instruction = NULL; + session->userauth_kybd_num_prompts = 0; + session->userauth_kybd_auth_failure = 1; + session->userauth_kybd_prompts = NULL; + session->userauth_kybd_responses = NULL; + + /* Zero the whole thing out */ + memset(&session->userauth_kybd_packet_requirev_state, 0, + sizeof(session->userauth_kybd_packet_requirev_state)); + + session->userauth_kybd_packet_len = + 1 /* byte SSH_MSG_USERAUTH_REQUEST */ + + 4 + username_len /* string user name (ISO-10646 UTF-8, as + defined in [RFC-3629]) */ + + 4 + 14 /* string service name (US-ASCII) */ + + 4 + 20 /* string "keyboard-interactive" (US-ASCII) */ + + 4 + 0 /* string language tag (as defined in + [RFC-3066]) */ + + 4 + 0 /* string submethods (ISO-10646 UTF-8) */ + ; + + session->userauth_kybd_data = s = + LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len); + if (!s) { + return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "keyboard-interactive authentication"); + } + + *s++ = SSH_MSG_USERAUTH_REQUEST; + + /* user name */ + _libssh2_store_str(&s, username, username_len); + + /* service name */ + _libssh2_store_str(&s, "ssh-connection", sizeof("ssh-connection") - 1); + + /* "keyboard-interactive" */ + _libssh2_store_str(&s, "keyboard-interactive", + sizeof("keyboard-interactive") - 1); + /* language tag */ + _libssh2_store_u32(&s, 0); + + /* submethods */ + _libssh2_store_u32(&s, 0); + + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Attempting keyboard-interactive authentication"); + + session->userauth_kybd_state = libssh2_NB_state_created; + } + + if (session->userauth_kybd_state == libssh2_NB_state_created) { + rc = _libssh2_transport_send(session, session->userauth_kybd_data, + session->userauth_kybd_packet_len, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block"); + } else if (rc) { + LIBSSH2_FREE(session, session->userauth_kybd_data); + session->userauth_kybd_data = NULL; + session->userauth_kybd_state = libssh2_NB_state_idle; + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send keyboard-interactive request"); + } + LIBSSH2_FREE(session, session->userauth_kybd_data); + session->userauth_kybd_data = NULL; + + session->userauth_kybd_state = libssh2_NB_state_sent; + } + + for(;;) { + if (session->userauth_kybd_state == libssh2_NB_state_sent) { + rc = _libssh2_packet_requirev(session, reply_codes, + &session->userauth_kybd_data, + &session->userauth_kybd_data_len, + 0, NULL, 0, + &session-> + userauth_kybd_packet_requirev_state); + if (rc == LIBSSH2_ERROR_EAGAIN) { + return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block"); + } else if (rc) { + session->userauth_kybd_state = libssh2_NB_state_idle; + return _libssh2_error(session, + LIBSSH2_ERROR_AUTHENTICATION_FAILED, + "Waiting for keyboard USERAUTH response"); + } + + if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_SUCCESS) { + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Keyboard-interactive authentication successful"); + LIBSSH2_FREE(session, session->userauth_kybd_data); + session->userauth_kybd_data = NULL; + session->state |= LIBSSH2_STATE_AUTHENTICATED; + session->userauth_kybd_state = libssh2_NB_state_idle; + return 0; + } + + if (session->userauth_kybd_data[0] == SSH_MSG_USERAUTH_FAILURE) { + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Keyboard-interactive authentication failed"); + LIBSSH2_FREE(session, session->userauth_kybd_data); + session->userauth_kybd_data = NULL; + session->userauth_kybd_state = libssh2_NB_state_idle; + return _libssh2_error(session, + LIBSSH2_ERROR_AUTHENTICATION_FAILED, + "Authentication failed " + "(keyboard-interactive)"); + } + + /* server requested PAM-like conversation */ + s = session->userauth_kybd_data + 1; + + /* string name (ISO-10646 UTF-8) */ + session->userauth_kybd_auth_name_len = _libssh2_ntohu32(s); + s += 4; + if(session->userauth_kybd_auth_name_len) { + session->userauth_kybd_auth_name = + LIBSSH2_ALLOC(session, + session->userauth_kybd_auth_name_len); + if (!session->userauth_kybd_auth_name) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "keyboard-interactive 'name' " + "request field"); + goto cleanup; + } + memcpy(session->userauth_kybd_auth_name, s, + session->userauth_kybd_auth_name_len); + s += session->userauth_kybd_auth_name_len; + } + + /* string instruction (ISO-10646 UTF-8) */ + session->userauth_kybd_auth_instruction_len = _libssh2_ntohu32(s); + s += 4; + if(session->userauth_kybd_auth_instruction_len) { + session->userauth_kybd_auth_instruction = + LIBSSH2_ALLOC(session, + session->userauth_kybd_auth_instruction_len); + if (!session->userauth_kybd_auth_instruction) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "keyboard-interactive 'instruction' " + "request field"); + goto cleanup; + } + memcpy(session->userauth_kybd_auth_instruction, s, + session->userauth_kybd_auth_instruction_len); + s += session->userauth_kybd_auth_instruction_len; + } + + /* string language tag (as defined in [RFC-3066]) */ + language_tag_len = _libssh2_ntohu32(s); + s += 4; + + /* ignoring this field as deprecated */ + s += language_tag_len; + + /* int num-prompts */ + session->userauth_kybd_num_prompts = _libssh2_ntohu32(s); + s += 4; + + if(session->userauth_kybd_num_prompts) { + session->userauth_kybd_prompts = + LIBSSH2_ALLOC(session, + sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * + session->userauth_kybd_num_prompts); + if (!session->userauth_kybd_prompts) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "keyboard-interactive prompts array"); + goto cleanup; + } + memset(session->userauth_kybd_prompts, 0, + sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * + session->userauth_kybd_num_prompts); + + session->userauth_kybd_responses = + LIBSSH2_ALLOC(session, + sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * + session->userauth_kybd_num_prompts); + if (!session->userauth_kybd_responses) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "keyboard-interactive responses array"); + goto cleanup; + } + memset(session->userauth_kybd_responses, 0, + sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * + session->userauth_kybd_num_prompts); + + for(i = 0; i != session->userauth_kybd_num_prompts; ++i) { + /* string prompt[1] (ISO-10646 UTF-8) */ + session->userauth_kybd_prompts[i].length = + _libssh2_ntohu32(s); + s += 4; + session->userauth_kybd_prompts[i].text = + LIBSSH2_ALLOC(session, + session->userauth_kybd_prompts[i].length); + if (!session->userauth_kybd_prompts[i].text) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for " + "keyboard-interactive prompt message"); + goto cleanup; + } + memcpy(session->userauth_kybd_prompts[i].text, s, + session->userauth_kybd_prompts[i].length); + s += session->userauth_kybd_prompts[i].length; + + /* boolean echo[1] */ + session->userauth_kybd_prompts[i].echo = *s++; + } + } + + response_callback(session->userauth_kybd_auth_name, + session->userauth_kybd_auth_name_len, + session->userauth_kybd_auth_instruction, + session->userauth_kybd_auth_instruction_len, + session->userauth_kybd_num_prompts, + session->userauth_kybd_prompts, + session->userauth_kybd_responses, + &session->abstract); + + _libssh2_debug(session, LIBSSH2_TRACE_AUTH, + "Keyboard-interactive response callback function" + " invoked"); + + session->userauth_kybd_packet_len = + 1 /* byte SSH_MSG_USERAUTH_INFO_RESPONSE */ + + 4 /* int num-responses */ + ; + + for(i = 0; i != session->userauth_kybd_num_prompts; ++i) { + /* string response[1] (ISO-10646 UTF-8) */ + session->userauth_kybd_packet_len += + 4 + session->userauth_kybd_responses[i].length; + } + + /* A new userauth_kybd_data area is to be allocated, free the + former one. */ + LIBSSH2_FREE(session, session->userauth_kybd_data); + + session->userauth_kybd_data = s = + LIBSSH2_ALLOC(session, session->userauth_kybd_packet_len); + if (!s) { + _libssh2_error(session, LIBSSH2_ERROR_ALLOC, + "Unable to allocate memory for keyboard-" + "interactive response packet"); + goto cleanup; + } + + *s = SSH_MSG_USERAUTH_INFO_RESPONSE; + s++; + _libssh2_store_u32(&s, session->userauth_kybd_num_prompts); + + for(i = 0; i != session->userauth_kybd_num_prompts; ++i) { + _libssh2_store_str(&s, + session->userauth_kybd_responses[i].text, + session->userauth_kybd_responses[i].length); + } + + session->userauth_kybd_state = libssh2_NB_state_sent1; + } + + if (session->userauth_kybd_state == libssh2_NB_state_sent1) { + rc = _libssh2_transport_send(session, session->userauth_kybd_data, + session->userauth_kybd_packet_len, + NULL, 0); + if (rc == LIBSSH2_ERROR_EAGAIN) + return _libssh2_error(session, LIBSSH2_ERROR_EAGAIN, + "Would block"); + if (rc) { + _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, + "Unable to send userauth-keyboard-interactive" + " request"); + goto cleanup; + } + + session->userauth_kybd_auth_failure = 0; + } + + cleanup: + /* + * It's safe to clean all the data here, because unallocated pointers + * are filled by zeroes + */ + + LIBSSH2_FREE(session, session->userauth_kybd_data); + session->userauth_kybd_data = NULL; + + if (session->userauth_kybd_prompts) { + for(i = 0; i != session->userauth_kybd_num_prompts; ++i) { + LIBSSH2_FREE(session, session->userauth_kybd_prompts[i].text); + session->userauth_kybd_prompts[i].text = NULL; + } + } + + if (session->userauth_kybd_responses) { + for(i = 0; i != session->userauth_kybd_num_prompts; ++i) { + LIBSSH2_FREE(session, + session->userauth_kybd_responses[i].text); + session->userauth_kybd_responses[i].text = NULL; + } + } + + if(session->userauth_kybd_prompts) { + LIBSSH2_FREE(session, session->userauth_kybd_prompts); + session->userauth_kybd_prompts = NULL; + } + if(session->userauth_kybd_responses) { + LIBSSH2_FREE(session, session->userauth_kybd_responses); + session->userauth_kybd_responses = NULL; + } + if(session->userauth_kybd_auth_name) { + LIBSSH2_FREE(session, session->userauth_kybd_auth_name); + session->userauth_kybd_auth_name = NULL; + } + if(session->userauth_kybd_auth_instruction) { + LIBSSH2_FREE(session, session->userauth_kybd_auth_instruction); + session->userauth_kybd_auth_instruction = NULL; + } + + if (session->userauth_kybd_auth_failure) { + session->userauth_kybd_state = libssh2_NB_state_idle; + return -1; + } + + session->userauth_kybd_state = libssh2_NB_state_sent; + } +} + +/* + * libssh2_userauth_keyboard_interactive_ex + * + * Authenticate using a challenge-response authentication + */ +LIBSSH2_API int +libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, + const char *user, + unsigned int user_len, + LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback))) +{ + int rc; + BLOCK_ADJUST(rc, session, + userauth_keyboard_interactive(session, user, user_len, + response_callback)); + return rc; +} diff --git a/vendor/libssh2-1.4.2/src/userauth.h b/vendor/libssh2-1.4.2/src/userauth.h new file mode 100644 index 0000000..c0442ae --- /dev/null +++ b/vendor/libssh2-1.4.2/src/userauth.h @@ -0,0 +1,50 @@ +#ifndef LIBSSH2_USERAUTH_H +#define LIBSSH2_USERAUTH_H +/* Copyright (c) 2004-2007, Sara Golemon + * Copyright (c) 2009-2010 by Daniel Stenberg + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + */ + +int +_libssh2_userauth_publickey(LIBSSH2_SESSION *session, + const char *username, + unsigned int username_len, + const unsigned char *pubkeydata, + unsigned long pubkeydata_len, + LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*sign_callback)), + void *abstract); + +#endif /* LIBSSH2_USERAUTH_H */ diff --git a/vendor/libssh2-1.4.2/src/version.c b/vendor/libssh2-1.4.2/src/version.c new file mode 100644 index 0000000..408f83a --- /dev/null +++ b/vendor/libssh2-1.4.2/src/version.c @@ -0,0 +1,54 @@ +/* Copyright (C) 2009 Daniel Stenberg. All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * Neither the name of the copyright holder nor the names + * of any other contributors may be used to endorse or + * promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + */ + +#include "libssh2_priv.h" + +/* + libssh2_version() can be used like this: + + if (!libssh2_version(LIBSSH2_VERSION_NUM)) { + fprintf (stderr, "Runtime libssh2 version too old!\n"); + exit(1); + } +*/ +LIBSSH2_API +const char *libssh2_version(int req_version_num) +{ + if(req_version_num <= LIBSSH2_VERSION_NUM) + return LIBSSH2_VERSION; + return NULL; /* this is not a suitable library! */ +} diff --git a/vendor/sigar/CMakeFiles/CMakeDirectoryInformation.cmake b/vendor/sigar/CMakeFiles/CMakeDirectoryInformation.cmake new file mode 100644 index 0000000..040550b --- /dev/null +++ b/vendor/sigar/CMakeFiles/CMakeDirectoryInformation.cmake @@ -0,0 +1,16 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Relative path conversion top directories. +SET(CMAKE_RELATIVE_PATH_TOP_SOURCE "/Users/dlarimer/projects/AthenaRuntime") +SET(CMAKE_RELATIVE_PATH_TOP_BINARY "/Users/dlarimer/projects/AthenaRuntime") + +# Force unix paths in dependencies. +SET(CMAKE_FORCE_UNIX_PATHS 1) + + +# The C and CXX include file regular expressions for this directory. +SET(CMAKE_C_INCLUDE_REGEX_SCAN "^.*$") +SET(CMAKE_C_INCLUDE_REGEX_COMPLAIN "^$") +SET(CMAKE_CXX_INCLUDE_REGEX_SCAN ${CMAKE_C_INCLUDE_REGEX_SCAN}) +SET(CMAKE_CXX_INCLUDE_REGEX_COMPLAIN ${CMAKE_C_INCLUDE_REGEX_COMPLAIN}) diff --git a/vendor/sigar/CMakeFiles/progress.marks b/vendor/sigar/CMakeFiles/progress.marks new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/vendor/sigar/CMakeFiles/progress.marks @@ -0,0 +1 @@ +5 diff --git a/vendor/sigar/CMakeFiles/sigar.dir/C.includecache b/vendor/sigar/CMakeFiles/sigar.dir/C.includecache new file mode 100644 index 0000000..b84d7a1 --- /dev/null +++ b/vendor/sigar/CMakeFiles/sigar.dir/C.includecache @@ -0,0 +1,8 @@ +#IncludeRegexLine: ^[ ]*#[ ]*(include|import)[ ]*[<"]([^">]+)([">]) + +#IncludeRegexScan: ^.*$ + +#IncludeRegexComplain: ^$ + +#IncludeRegexTransform: + diff --git a/vendor/sigar/CMakeFiles/sigar.dir/DependInfo.cmake b/vendor/sigar/CMakeFiles/sigar.dir/DependInfo.cmake new file mode 100644 index 0000000..2f2e387 --- /dev/null +++ b/vendor/sigar/CMakeFiles/sigar.dir/DependInfo.cmake @@ -0,0 +1,43 @@ +# The set of languages for which implicit dependencies are needed: +SET(CMAKE_DEPENDS_LANGUAGES + "C" + ) +# The set of files for implicit dependencies of each language: +SET(CMAKE_DEPENDS_CHECK_C + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/os/darwin/darwin_sigar.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_cache.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_fileinfo.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_format.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_getline.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_ptql.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_signal.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_util.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o" + "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_version_autoconf.c" "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o" + ) +SET(CMAKE_C_COMPILER_ID "GNU") + +# Preprocessor definitions for this target. +SET(CMAKE_TARGET_DEFINITIONS + "DARWIN_HAS_LIBPROC_H" + ) + +# Targets to which this target links. +SET(CMAKE_TARGET_LINKED_INFO_FILES + ) + +# The include file search paths: +SET(CMAKE_C_TARGET_INCLUDE_PATH + "." + "/usr/local/include" + "vendor/fc/include" + "libs/cpparchive/include" + "/opt/local/include" + "libs/fa/include" + "vendor/fc/vendor/libssh2-1.4.2/include" + "vendor/fc/vendor/sigar/include" + "vendor/fc/vendor/sigar/src/os/darwin" + ) +SET(CMAKE_CXX_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_Fortran_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) +SET(CMAKE_ASM_TARGET_INCLUDE_PATH ${CMAKE_C_TARGET_INCLUDE_PATH}) diff --git a/vendor/sigar/CMakeFiles/sigar.dir/build.make b/vendor/sigar/CMakeFiles/sigar.dir/build.make new file mode 100644 index 0000000..b23c70a --- /dev/null +++ b/vendor/sigar/CMakeFiles/sigar.dir/build.make @@ -0,0 +1,337 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/dlarimer/projects/AthenaRuntime + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/dlarimer/projects/AthenaRuntime + +# Include any dependencies generated for this target. +include vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/depend.make + +# Include the progress variables for this target. +include vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/progress.make + +# Include the compile flags for this target's objects. +include vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/flags.make + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/flags.make +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o: vendor/fc/vendor/sigar/src/os/darwin/darwin_sigar.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_1) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/os/darwin/darwin_sigar.c + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/os/darwin/darwin_sigar.c > CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.i + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/os/darwin/darwin_sigar.c -o CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.s + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o.requires: +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o.requires + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o.provides: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o.requires + $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o.provides.build +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o.provides + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o.provides.build: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/flags.make +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: vendor/fc/vendor/sigar/src/sigar.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_2) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/sigar.dir/src/sigar.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar.c + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/sigar.dir/src/sigar.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar.c > CMakeFiles/sigar.dir/src/sigar.c.i + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/sigar.dir/src/sigar.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar.c -o CMakeFiles/sigar.dir/src/sigar.c.s + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o.requires: +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o.requires + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o.provides: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o.requires + $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o.provides.build +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o.provides + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o.provides.build: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/flags.make +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o: vendor/fc/vendor/sigar/src/sigar_cache.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_3) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/sigar.dir/src/sigar_cache.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_cache.c + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/sigar.dir/src/sigar_cache.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_cache.c > CMakeFiles/sigar.dir/src/sigar_cache.c.i + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/sigar.dir/src/sigar_cache.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_cache.c -o CMakeFiles/sigar.dir/src/sigar_cache.c.s + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o.requires: +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o.requires + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o.provides: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o.requires + $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o.provides.build +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o.provides + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o.provides.build: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/flags.make +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o: vendor/fc/vendor/sigar/src/sigar_fileinfo.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_4) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_fileinfo.c + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/sigar.dir/src/sigar_fileinfo.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_fileinfo.c > CMakeFiles/sigar.dir/src/sigar_fileinfo.c.i + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/sigar.dir/src/sigar_fileinfo.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_fileinfo.c -o CMakeFiles/sigar.dir/src/sigar_fileinfo.c.s + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o.requires: +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o.requires + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o.provides: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o.requires + $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o.provides.build +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o.provides + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o.provides.build: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/flags.make +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: vendor/fc/vendor/sigar/src/sigar_format.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_5) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/sigar.dir/src/sigar_format.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_format.c + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/sigar.dir/src/sigar_format.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_format.c > CMakeFiles/sigar.dir/src/sigar_format.c.i + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/sigar.dir/src/sigar_format.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_format.c -o CMakeFiles/sigar.dir/src/sigar_format.c.s + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o.requires: +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o.requires + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o.provides: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o.requires + $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o.provides.build +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o.provides + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o.provides.build: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/flags.make +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o: vendor/fc/vendor/sigar/src/sigar_getline.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_6) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/sigar.dir/src/sigar_getline.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_getline.c + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/sigar.dir/src/sigar_getline.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_getline.c > CMakeFiles/sigar.dir/src/sigar_getline.c.i + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/sigar.dir/src/sigar_getline.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_getline.c -o CMakeFiles/sigar.dir/src/sigar_getline.c.s + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o.requires: +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o.requires + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o.provides: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o.requires + $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o.provides.build +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o.provides + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o.provides.build: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/flags.make +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o: vendor/fc/vendor/sigar/src/sigar_ptql.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_7) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/sigar.dir/src/sigar_ptql.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_ptql.c + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/sigar.dir/src/sigar_ptql.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_ptql.c > CMakeFiles/sigar.dir/src/sigar_ptql.c.i + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/sigar.dir/src/sigar_ptql.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_ptql.c -o CMakeFiles/sigar.dir/src/sigar_ptql.c.s + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o.requires: +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o.requires + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o.provides: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o.requires + $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o.provides.build +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o.provides + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o.provides.build: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/flags.make +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o: vendor/fc/vendor/sigar/src/sigar_signal.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_8) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/sigar.dir/src/sigar_signal.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_signal.c + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/sigar.dir/src/sigar_signal.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_signal.c > CMakeFiles/sigar.dir/src/sigar_signal.c.i + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/sigar.dir/src/sigar_signal.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_signal.c -o CMakeFiles/sigar.dir/src/sigar_signal.c.s + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o.requires: +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o.requires + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o.provides: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o.requires + $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o.provides.build +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o.provides + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o.provides.build: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/flags.make +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o: vendor/fc/vendor/sigar/src/sigar_util.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_9) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/sigar.dir/src/sigar_util.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_util.c + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/sigar.dir/src/sigar_util.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_util.c > CMakeFiles/sigar.dir/src/sigar_util.c.i + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/sigar.dir/src/sigar_util.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_util.c -o CMakeFiles/sigar.dir/src/sigar_util.c.s + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o.requires: +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o.requires + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o.provides: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o.requires + $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o.provides.build +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o.provides + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o.provides.build: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/flags.make +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o: vendor/fc/vendor/sigar/src/sigar_version_autoconf.c + $(CMAKE_COMMAND) -E cmake_progress_report /Users/dlarimer/projects/AthenaRuntime/CMakeFiles $(CMAKE_PROGRESS_10) + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Building C object vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -o CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o -c /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_version_autoconf.c + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.i: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Preprocessing C source to CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.i" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -E /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_version_autoconf.c > CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.i + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.s: cmake_force + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --green "Compiling C source to assembly CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.s" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && /opt/local/bin/gcc $(C_DEFINES) $(C_FLAGS) -S /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_version_autoconf.c -o CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.s + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o.requires: +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o.requires + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o.provides: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o.requires + $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o.provides.build +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o.provides + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o.provides.build: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o + +# Object files for target sigar +sigar_OBJECTS = \ +"CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o" \ +"CMakeFiles/sigar.dir/src/sigar.c.o" \ +"CMakeFiles/sigar.dir/src/sigar_cache.c.o" \ +"CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o" \ +"CMakeFiles/sigar.dir/src/sigar_format.c.o" \ +"CMakeFiles/sigar.dir/src/sigar_getline.c.o" \ +"CMakeFiles/sigar.dir/src/sigar_ptql.c.o" \ +"CMakeFiles/sigar.dir/src/sigar_signal.c.o" \ +"CMakeFiles/sigar.dir/src/sigar_util.c.o" \ +"CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o" + +# External object files for target sigar +sigar_EXTERNAL_OBJECTS = + +vendor/fc/vendor/sigar/libsigar.a: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o +vendor/fc/vendor/sigar/libsigar.a: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o +vendor/fc/vendor/sigar/libsigar.a: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o +vendor/fc/vendor/sigar/libsigar.a: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o +vendor/fc/vendor/sigar/libsigar.a: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o +vendor/fc/vendor/sigar/libsigar.a: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o +vendor/fc/vendor/sigar/libsigar.a: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o +vendor/fc/vendor/sigar/libsigar.a: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o +vendor/fc/vendor/sigar/libsigar.a: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o +vendor/fc/vendor/sigar/libsigar.a: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o +vendor/fc/vendor/sigar/libsigar.a: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make +vendor/fc/vendor/sigar/libsigar.a: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/link.txt + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --red --bold "Linking C static library libsigar.a" + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && $(CMAKE_COMMAND) -P CMakeFiles/sigar.dir/cmake_clean_target.cmake + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && $(CMAKE_COMMAND) -E cmake_link_script CMakeFiles/sigar.dir/link.txt --verbose=$(VERBOSE) + +# Rule to build all files generated by this target. +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build: vendor/fc/vendor/sigar/libsigar.a +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/requires: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o.requires +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/requires: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o.requires +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/requires: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o.requires +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/requires: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o.requires +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/requires: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o.requires +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/requires: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o.requires +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/requires: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o.requires +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/requires: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o.requires +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/requires: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o.requires +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/requires: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o.requires +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/requires + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/clean: + cd /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar && $(CMAKE_COMMAND) -P CMakeFiles/sigar.dir/cmake_clean.cmake +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/clean + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/depend: + cd /Users/dlarimer/projects/AthenaRuntime && $(CMAKE_COMMAND) -E cmake_depends "Unix Makefiles" /Users/dlarimer/projects/AthenaRuntime /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar /Users/dlarimer/projects/AthenaRuntime /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/DependInfo.cmake --color=$(COLOR) +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/depend + diff --git a/vendor/sigar/CMakeFiles/sigar.dir/cmake_clean.cmake b/vendor/sigar/CMakeFiles/sigar.dir/cmake_clean.cmake new file mode 100644 index 0000000..0d45de6 --- /dev/null +++ b/vendor/sigar/CMakeFiles/sigar.dir/cmake_clean.cmake @@ -0,0 +1,19 @@ +FILE(REMOVE_RECURSE + "CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o" + "CMakeFiles/sigar.dir/src/sigar.c.o" + "CMakeFiles/sigar.dir/src/sigar_cache.c.o" + "CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o" + "CMakeFiles/sigar.dir/src/sigar_format.c.o" + "CMakeFiles/sigar.dir/src/sigar_getline.c.o" + "CMakeFiles/sigar.dir/src/sigar_ptql.c.o" + "CMakeFiles/sigar.dir/src/sigar_signal.c.o" + "CMakeFiles/sigar.dir/src/sigar_util.c.o" + "CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o" + "libsigar.pdb" + "libsigar.a" +) + +# Per-language clean rules from dependency scanning. +FOREACH(lang C) + INCLUDE(CMakeFiles/sigar.dir/cmake_clean_${lang}.cmake OPTIONAL) +ENDFOREACH(lang) diff --git a/vendor/sigar/CMakeFiles/sigar.dir/cmake_clean_target.cmake b/vendor/sigar/CMakeFiles/sigar.dir/cmake_clean_target.cmake new file mode 100644 index 0000000..76b2e90 --- /dev/null +++ b/vendor/sigar/CMakeFiles/sigar.dir/cmake_clean_target.cmake @@ -0,0 +1,3 @@ +FILE(REMOVE_RECURSE + "libsigar.a" +) diff --git a/vendor/sigar/CMakeFiles/sigar.dir/depend.internal b/vendor/sigar/CMakeFiles/sigar.dir/depend.internal new file mode 100644 index 0000000..1c3ed09 --- /dev/null +++ b/vendor/sigar/CMakeFiles/sigar.dir/depend.internal @@ -0,0 +1,98 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/os/darwin/darwin_sigar.c + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/os/darwin/sigar_os.h + /opt/local/include/dlfcn.h + /opt/local/include/mach-o/dyld.h + /opt/local/include/mach-o/loader.h + /opt/local/include/mach/machine.h + /usr/local/include/sigar.h + /usr/local/include/sigar_log.h + /usr/local/include/sigar_private.h + /usr/local/include/sigar_ptql.h + /usr/local/include/sigar_util.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar.c + /opt/local/include/dlfcn.h + /opt/local/include/mach-o/dyld.h + /opt/local/include/mach-o/loader.h + /opt/local/include/mach/machine.h + /usr/local/include/sigar.h + /usr/local/include/sigar_format.h + /usr/local/include/sigar_log.h + /usr/local/include/sigar_private.h + /usr/local/include/sigar_ptql.h + /usr/local/include/sigar_util.h + vendor/fc/vendor/sigar/src/os/darwin/sigar_os.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_cache.c + /opt/local/include/dlfcn.h + /usr/local/include/sigar.h + /usr/local/include/sigar_log.h + /usr/local/include/sigar_private.h + /usr/local/include/sigar_ptql.h + /usr/local/include/sigar_util.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_fileinfo.c + /usr/local/include/sigar.h + /usr/local/include/sigar_fileinfo.h + /usr/local/include/sigar_log.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_format.c + /opt/local/include/dlfcn.h + /opt/local/include/mach-o/dyld.h + /opt/local/include/mach-o/loader.h + /opt/local/include/mach/machine.h + /usr/local/include/sigar.h + /usr/local/include/sigar_format.h + /usr/local/include/sigar_log.h + /usr/local/include/sigar_private.h + /usr/local/include/sigar_ptql.h + /usr/local/include/sigar_util.h + vendor/fc/vendor/sigar/src/os/darwin/sigar_os.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_getline.c + /opt/local/include/dlfcn.h + /usr/local/include/sigar.h + /usr/local/include/sigar_getline.h + /usr/local/include/sigar_log.h + /usr/local/include/sigar_private.h + /usr/local/include/sigar_ptql.h + /usr/local/include/sigar_util.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_ptql.c + /opt/local/include/dlfcn.h + /opt/local/include/mach-o/dyld.h + /opt/local/include/mach-o/loader.h + /opt/local/include/mach/machine.h + /usr/local/include/sigar.h + /usr/local/include/sigar_log.h + /usr/local/include/sigar_private.h + /usr/local/include/sigar_ptql.h + /usr/local/include/sigar_util.h + vendor/fc/vendor/sigar/src/os/darwin/sigar_os.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_signal.c + /opt/local/include/dlfcn.h + /usr/local/include/sigar.h + /usr/local/include/sigar_log.h + /usr/local/include/sigar_private.h + /usr/local/include/sigar_ptql.h + /usr/local/include/sigar_util.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_util.c + /opt/local/include/dlfcn.h + /opt/local/include/mach-o/dyld.h + /opt/local/include/mach-o/loader.h + /opt/local/include/mach/machine.h + /usr/local/include/sigar.h + /usr/local/include/sigar_log.h + /usr/local/include/sigar_private.h + /usr/local/include/sigar_ptql.h + /usr/local/include/sigar_util.h + vendor/fc/vendor/sigar/src/os/darwin/sigar_os.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o + /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/sigar_version_autoconf.c + /usr/local/include/sigar.h diff --git a/vendor/sigar/CMakeFiles/sigar.dir/depend.make b/vendor/sigar/CMakeFiles/sigar.dir/depend.make new file mode 100644 index 0000000..81a08c0 --- /dev/null +++ b/vendor/sigar/CMakeFiles/sigar.dir/depend.make @@ -0,0 +1,98 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o: vendor/fc/vendor/sigar/src/os/darwin/darwin_sigar.c +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o: vendor/fc/vendor/sigar/src/os/darwin/sigar_os.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o: /opt/local/include/dlfcn.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o: /opt/local/include/mach-o/dyld.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o: /opt/local/include/mach-o/loader.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o: /opt/local/include/mach/machine.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o: /usr/local/include/sigar.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o: /usr/local/include/sigar_log.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o: /usr/local/include/sigar_private.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o: /usr/local/include/sigar_ptql.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o: /usr/local/include/sigar_util.h + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: vendor/fc/vendor/sigar/src/sigar.c +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: /opt/local/include/dlfcn.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: /opt/local/include/mach-o/dyld.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: /opt/local/include/mach-o/loader.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: /opt/local/include/mach/machine.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: /usr/local/include/sigar.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: /usr/local/include/sigar_format.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: /usr/local/include/sigar_log.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: /usr/local/include/sigar_private.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: /usr/local/include/sigar_ptql.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: /usr/local/include/sigar_util.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o: vendor/fc/vendor/sigar/src/os/darwin/sigar_os.h + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o: vendor/fc/vendor/sigar/src/sigar_cache.c +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o: /opt/local/include/dlfcn.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o: /usr/local/include/sigar.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o: /usr/local/include/sigar_log.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o: /usr/local/include/sigar_private.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o: /usr/local/include/sigar_ptql.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o: /usr/local/include/sigar_util.h + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o: vendor/fc/vendor/sigar/src/sigar_fileinfo.c +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o: /usr/local/include/sigar.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o: /usr/local/include/sigar_fileinfo.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o: /usr/local/include/sigar_log.h + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: vendor/fc/vendor/sigar/src/sigar_format.c +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: /opt/local/include/dlfcn.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: /opt/local/include/mach-o/dyld.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: /opt/local/include/mach-o/loader.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: /opt/local/include/mach/machine.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: /usr/local/include/sigar.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: /usr/local/include/sigar_format.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: /usr/local/include/sigar_log.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: /usr/local/include/sigar_private.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: /usr/local/include/sigar_ptql.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: /usr/local/include/sigar_util.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o: vendor/fc/vendor/sigar/src/os/darwin/sigar_os.h + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o: vendor/fc/vendor/sigar/src/sigar_getline.c +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o: /opt/local/include/dlfcn.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o: /usr/local/include/sigar.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o: /usr/local/include/sigar_getline.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o: /usr/local/include/sigar_log.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o: /usr/local/include/sigar_private.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o: /usr/local/include/sigar_ptql.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o: /usr/local/include/sigar_util.h + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o: vendor/fc/vendor/sigar/src/sigar_ptql.c +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o: /opt/local/include/dlfcn.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o: /opt/local/include/mach-o/dyld.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o: /opt/local/include/mach-o/loader.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o: /opt/local/include/mach/machine.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o: /usr/local/include/sigar.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o: /usr/local/include/sigar_log.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o: /usr/local/include/sigar_private.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o: /usr/local/include/sigar_ptql.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o: /usr/local/include/sigar_util.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o: vendor/fc/vendor/sigar/src/os/darwin/sigar_os.h + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o: vendor/fc/vendor/sigar/src/sigar_signal.c +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o: /opt/local/include/dlfcn.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o: /usr/local/include/sigar.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o: /usr/local/include/sigar_log.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o: /usr/local/include/sigar_private.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o: /usr/local/include/sigar_ptql.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o: /usr/local/include/sigar_util.h + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o: vendor/fc/vendor/sigar/src/sigar_util.c +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o: /opt/local/include/dlfcn.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o: /opt/local/include/mach-o/dyld.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o: /opt/local/include/mach-o/loader.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o: /opt/local/include/mach/machine.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o: /usr/local/include/sigar.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o: /usr/local/include/sigar_log.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o: /usr/local/include/sigar_private.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o: /usr/local/include/sigar_ptql.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o: /usr/local/include/sigar_util.h +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o: vendor/fc/vendor/sigar/src/os/darwin/sigar_os.h + +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o: vendor/fc/vendor/sigar/src/sigar_version_autoconf.c +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o: /usr/local/include/sigar.h + diff --git a/vendor/sigar/CMakeFiles/sigar.dir/flags.make b/vendor/sigar/CMakeFiles/sigar.dir/flags.make new file mode 100644 index 0000000..6d778a7 --- /dev/null +++ b/vendor/sigar/CMakeFiles/sigar.dir/flags.make @@ -0,0 +1,8 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# compile C with /opt/local/bin/gcc +C_FLAGS = -O3 -DNDEBUG -I/Users/dlarimer/projects/AthenaRuntime -I/usr/local/include -I/Users/dlarimer/projects/AthenaRuntime/vendor/fc/include -I/Users/dlarimer/projects/AthenaRuntime/libs/cpparchive/include -I/opt/local/include -I/Users/dlarimer/projects/AthenaRuntime/libs/fa/include -I/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/libssh2-1.4.2/include -I/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/include -I/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/src/os/darwin + +C_DEFINES = -DDARWIN_HAS_LIBPROC_H + diff --git a/vendor/sigar/CMakeFiles/sigar.dir/link.txt b/vendor/sigar/CMakeFiles/sigar.dir/link.txt new file mode 100644 index 0000000..4ebd868 --- /dev/null +++ b/vendor/sigar/CMakeFiles/sigar.dir/link.txt @@ -0,0 +1,2 @@ +/opt/local/bin/ar cr libsigar.a CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o CMakeFiles/sigar.dir/src/sigar.c.o CMakeFiles/sigar.dir/src/sigar_cache.c.o CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o CMakeFiles/sigar.dir/src/sigar_format.c.o CMakeFiles/sigar.dir/src/sigar_getline.c.o CMakeFiles/sigar.dir/src/sigar_ptql.c.o CMakeFiles/sigar.dir/src/sigar_signal.c.o CMakeFiles/sigar.dir/src/sigar_util.c.o CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o +/opt/local/bin/ranlib libsigar.a diff --git a/vendor/sigar/CMakeFiles/sigar.dir/progress.make b/vendor/sigar/CMakeFiles/sigar.dir/progress.make new file mode 100644 index 0000000..d2520cf --- /dev/null +++ b/vendor/sigar/CMakeFiles/sigar.dir/progress.make @@ -0,0 +1,11 @@ +CMAKE_PROGRESS_1 = +CMAKE_PROGRESS_2 = 70 +CMAKE_PROGRESS_3 = +CMAKE_PROGRESS_4 = 71 +CMAKE_PROGRESS_5 = +CMAKE_PROGRESS_6 = 72 +CMAKE_PROGRESS_7 = +CMAKE_PROGRESS_8 = 73 +CMAKE_PROGRESS_9 = +CMAKE_PROGRESS_10 = 74 + diff --git a/vendor/sigar/CMakeLists.txt b/vendor/sigar/CMakeLists.txt new file mode 100644 index 0000000..671ac72 --- /dev/null +++ b/vendor/sigar/CMakeLists.txt @@ -0,0 +1,33 @@ +INCLUDE_DIRECTORIES(include) + + +IF(WIN32) + INCLUDE_DIRECTORIES(src/os/win32) + SET( os_sources src/os/win32/peb.c src/os/win32/wmi.cpp src/os/win32/win32_sigar.c ) +ELSE(WIN32) + IF( APPLE ) + ADD_DEFINITIONS( -DDARWIN_HAS_LIBPROC_H ) + INCLUDE_DIRECTORIES(src/os/darwin) + SET( os_sources src/os/darwin/darwin_sigar.c ) + ELSE( APPLE ) + INCLUDE_DIRECTORIES(src/os/linux) + SET( os_sources src/os/linux/linux_sigar.c ) + ENDIF( APPLE ) + +ENDIF(WIN32) + + +SET( sources + ${os_sources} + src/sigar.c + src/sigar_cache.c + src/sigar_fileinfo.c + src/sigar_format.c + src/sigar_getline.c + src/sigar_ptql.c + src/sigar_signal.c + src/sigar_util.c + src/sigar_version_autoconf.c +) + +SETUP_LIBRARY( sigar SOURCES ${sources} LIBRARIES ${libraries} LIBRARY_TYPE STATIC ) diff --git a/vendor/sigar/Makefile b/vendor/sigar/Makefile new file mode 100644 index 0000000..f705b79 --- /dev/null +++ b/vendor/sigar/Makefile @@ -0,0 +1,452 @@ +# CMAKE generated file: DO NOT EDIT! +# Generated by "Unix Makefiles" Generator, CMake Version 2.8 + +# Default target executed when no arguments are given to make. +default_target: all +.PHONY : default_target + +#============================================================================= +# Special targets provided by cmake. + +# Disable implicit rules so canonical targets will work. +.SUFFIXES: + +# Remove some rules from gmake that .SUFFIXES does not remove. +SUFFIXES = + +.SUFFIXES: .hpux_make_needs_suffix_list + +# Suppress display of executed commands. +$(VERBOSE).SILENT: + +# A target that is always out of date. +cmake_force: +.PHONY : cmake_force + +#============================================================================= +# Set environment variables for the build. + +# The shell in which to execute make rules. +SHELL = /bin/sh + +# The CMake executable. +CMAKE_COMMAND = /opt/local/bin/cmake + +# The command to remove a file. +RM = /opt/local/bin/cmake -E remove -f + +# The program to use to edit the cache. +CMAKE_EDIT_COMMAND = /opt/local/bin/ccmake + +# The top-level source directory on which CMake was run. +CMAKE_SOURCE_DIR = /Users/dlarimer/projects/AthenaRuntime + +# The top-level build directory on which CMake was run. +CMAKE_BINARY_DIR = /Users/dlarimer/projects/AthenaRuntime + +#============================================================================= +# Targets provided globally by CMake. + +# Special rule for the target edit_cache +edit_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake cache editor..." + /opt/local/bin/ccmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : edit_cache + +# Special rule for the target edit_cache +edit_cache/fast: edit_cache +.PHONY : edit_cache/fast + +# Special rule for the target install +install: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install + +# Special rule for the target install +install/fast: preinstall/fast + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Install the project..." + /opt/local/bin/cmake -P cmake_install.cmake +.PHONY : install/fast + +# Special rule for the target install/local +install/local: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing only the local directory..." + /opt/local/bin/cmake -DCMAKE_INSTALL_LOCAL_ONLY=1 -P cmake_install.cmake +.PHONY : install/local + +# Special rule for the target install/local +install/local/fast: install/local +.PHONY : install/local/fast + +# Special rule for the target install/strip +install/strip: preinstall + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Installing the project stripped..." + /opt/local/bin/cmake -DCMAKE_INSTALL_DO_STRIP=1 -P cmake_install.cmake +.PHONY : install/strip + +# Special rule for the target install/strip +install/strip/fast: install/strip +.PHONY : install/strip/fast + +# Special rule for the target list_install_components +list_install_components: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Available install components are: \"Unspecified\"" +.PHONY : list_install_components + +# Special rule for the target list_install_components +list_install_components/fast: list_install_components +.PHONY : list_install_components/fast + +# Special rule for the target rebuild_cache +rebuild_cache: + @$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..." + /opt/local/bin/cmake -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) +.PHONY : rebuild_cache + +# Special rule for the target rebuild_cache +rebuild_cache/fast: rebuild_cache +.PHONY : rebuild_cache/fast + +# The main all target +all: cmake_check_build_system + cd /Users/dlarimer/projects/AthenaRuntime && $(CMAKE_COMMAND) -E cmake_progress_start /Users/dlarimer/projects/AthenaRuntime/CMakeFiles /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/CMakeFiles/progress.marks + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f CMakeFiles/Makefile2 vendor/fc/vendor/sigar/all + $(CMAKE_COMMAND) -E cmake_progress_start /Users/dlarimer/projects/AthenaRuntime/CMakeFiles 0 +.PHONY : all + +# The main clean target +clean: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f CMakeFiles/Makefile2 vendor/fc/vendor/sigar/clean +.PHONY : clean + +# The main clean target +clean/fast: clean +.PHONY : clean/fast + +# Prepare targets for installation. +preinstall: all + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f CMakeFiles/Makefile2 vendor/fc/vendor/sigar/preinstall +.PHONY : preinstall + +# Prepare targets for installation. +preinstall/fast: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f CMakeFiles/Makefile2 vendor/fc/vendor/sigar/preinstall +.PHONY : preinstall/fast + +# clear depends +depend: + cd /Users/dlarimer/projects/AthenaRuntime && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1 +.PHONY : depend + +# Convenience name for target. +vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/rule: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f CMakeFiles/Makefile2 vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/rule +.PHONY : vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/rule + +# Convenience name for target. +sigar: vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/rule +.PHONY : sigar + +# fast build rule for target. +sigar/fast: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build +.PHONY : sigar/fast + +src/os/darwin/darwin_sigar.o: src/os/darwin/darwin_sigar.c.o +.PHONY : src/os/darwin/darwin_sigar.o + +# target to build an object file +src/os/darwin/darwin_sigar.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.o +.PHONY : src/os/darwin/darwin_sigar.c.o + +src/os/darwin/darwin_sigar.i: src/os/darwin/darwin_sigar.c.i +.PHONY : src/os/darwin/darwin_sigar.i + +# target to preprocess a source file +src/os/darwin/darwin_sigar.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.i +.PHONY : src/os/darwin/darwin_sigar.c.i + +src/os/darwin/darwin_sigar.s: src/os/darwin/darwin_sigar.c.s +.PHONY : src/os/darwin/darwin_sigar.s + +# target to generate assembly for a file +src/os/darwin/darwin_sigar.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/os/darwin/darwin_sigar.c.s +.PHONY : src/os/darwin/darwin_sigar.c.s + +src/sigar.o: src/sigar.c.o +.PHONY : src/sigar.o + +# target to build an object file +src/sigar.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.o +.PHONY : src/sigar.c.o + +src/sigar.i: src/sigar.c.i +.PHONY : src/sigar.i + +# target to preprocess a source file +src/sigar.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.i +.PHONY : src/sigar.c.i + +src/sigar.s: src/sigar.c.s +.PHONY : src/sigar.s + +# target to generate assembly for a file +src/sigar.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar.c.s +.PHONY : src/sigar.c.s + +src/sigar_cache.o: src/sigar_cache.c.o +.PHONY : src/sigar_cache.o + +# target to build an object file +src/sigar_cache.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.o +.PHONY : src/sigar_cache.c.o + +src/sigar_cache.i: src/sigar_cache.c.i +.PHONY : src/sigar_cache.i + +# target to preprocess a source file +src/sigar_cache.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.i +.PHONY : src/sigar_cache.c.i + +src/sigar_cache.s: src/sigar_cache.c.s +.PHONY : src/sigar_cache.s + +# target to generate assembly for a file +src/sigar_cache.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_cache.c.s +.PHONY : src/sigar_cache.c.s + +src/sigar_fileinfo.o: src/sigar_fileinfo.c.o +.PHONY : src/sigar_fileinfo.o + +# target to build an object file +src/sigar_fileinfo.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.o +.PHONY : src/sigar_fileinfo.c.o + +src/sigar_fileinfo.i: src/sigar_fileinfo.c.i +.PHONY : src/sigar_fileinfo.i + +# target to preprocess a source file +src/sigar_fileinfo.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.i +.PHONY : src/sigar_fileinfo.c.i + +src/sigar_fileinfo.s: src/sigar_fileinfo.c.s +.PHONY : src/sigar_fileinfo.s + +# target to generate assembly for a file +src/sigar_fileinfo.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_fileinfo.c.s +.PHONY : src/sigar_fileinfo.c.s + +src/sigar_format.o: src/sigar_format.c.o +.PHONY : src/sigar_format.o + +# target to build an object file +src/sigar_format.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.o +.PHONY : src/sigar_format.c.o + +src/sigar_format.i: src/sigar_format.c.i +.PHONY : src/sigar_format.i + +# target to preprocess a source file +src/sigar_format.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.i +.PHONY : src/sigar_format.c.i + +src/sigar_format.s: src/sigar_format.c.s +.PHONY : src/sigar_format.s + +# target to generate assembly for a file +src/sigar_format.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_format.c.s +.PHONY : src/sigar_format.c.s + +src/sigar_getline.o: src/sigar_getline.c.o +.PHONY : src/sigar_getline.o + +# target to build an object file +src/sigar_getline.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.o +.PHONY : src/sigar_getline.c.o + +src/sigar_getline.i: src/sigar_getline.c.i +.PHONY : src/sigar_getline.i + +# target to preprocess a source file +src/sigar_getline.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.i +.PHONY : src/sigar_getline.c.i + +src/sigar_getline.s: src/sigar_getline.c.s +.PHONY : src/sigar_getline.s + +# target to generate assembly for a file +src/sigar_getline.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_getline.c.s +.PHONY : src/sigar_getline.c.s + +src/sigar_ptql.o: src/sigar_ptql.c.o +.PHONY : src/sigar_ptql.o + +# target to build an object file +src/sigar_ptql.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.o +.PHONY : src/sigar_ptql.c.o + +src/sigar_ptql.i: src/sigar_ptql.c.i +.PHONY : src/sigar_ptql.i + +# target to preprocess a source file +src/sigar_ptql.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.i +.PHONY : src/sigar_ptql.c.i + +src/sigar_ptql.s: src/sigar_ptql.c.s +.PHONY : src/sigar_ptql.s + +# target to generate assembly for a file +src/sigar_ptql.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_ptql.c.s +.PHONY : src/sigar_ptql.c.s + +src/sigar_signal.o: src/sigar_signal.c.o +.PHONY : src/sigar_signal.o + +# target to build an object file +src/sigar_signal.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.o +.PHONY : src/sigar_signal.c.o + +src/sigar_signal.i: src/sigar_signal.c.i +.PHONY : src/sigar_signal.i + +# target to preprocess a source file +src/sigar_signal.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.i +.PHONY : src/sigar_signal.c.i + +src/sigar_signal.s: src/sigar_signal.c.s +.PHONY : src/sigar_signal.s + +# target to generate assembly for a file +src/sigar_signal.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_signal.c.s +.PHONY : src/sigar_signal.c.s + +src/sigar_util.o: src/sigar_util.c.o +.PHONY : src/sigar_util.o + +# target to build an object file +src/sigar_util.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.o +.PHONY : src/sigar_util.c.o + +src/sigar_util.i: src/sigar_util.c.i +.PHONY : src/sigar_util.i + +# target to preprocess a source file +src/sigar_util.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.i +.PHONY : src/sigar_util.c.i + +src/sigar_util.s: src/sigar_util.c.s +.PHONY : src/sigar_util.s + +# target to generate assembly for a file +src/sigar_util.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_util.c.s +.PHONY : src/sigar_util.c.s + +src/sigar_version_autoconf.o: src/sigar_version_autoconf.c.o +.PHONY : src/sigar_version_autoconf.o + +# target to build an object file +src/sigar_version_autoconf.c.o: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.o +.PHONY : src/sigar_version_autoconf.c.o + +src/sigar_version_autoconf.i: src/sigar_version_autoconf.c.i +.PHONY : src/sigar_version_autoconf.i + +# target to preprocess a source file +src/sigar_version_autoconf.c.i: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.i +.PHONY : src/sigar_version_autoconf.c.i + +src/sigar_version_autoconf.s: src/sigar_version_autoconf.c.s +.PHONY : src/sigar_version_autoconf.s + +# target to generate assembly for a file +src/sigar_version_autoconf.c.s: + cd /Users/dlarimer/projects/AthenaRuntime && $(MAKE) -f vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/build.make vendor/fc/vendor/sigar/CMakeFiles/sigar.dir/src/sigar_version_autoconf.c.s +.PHONY : src/sigar_version_autoconf.c.s + +# Help Target +help: + @echo "The following are some of the valid targets for this Makefile:" + @echo "... all (the default if no target is provided)" + @echo "... clean" + @echo "... depend" + @echo "... edit_cache" + @echo "... install" + @echo "... install/local" + @echo "... install/strip" + @echo "... list_install_components" + @echo "... rebuild_cache" + @echo "... sigar" + @echo "... src/os/darwin/darwin_sigar.o" + @echo "... src/os/darwin/darwin_sigar.i" + @echo "... src/os/darwin/darwin_sigar.s" + @echo "... src/sigar.o" + @echo "... src/sigar.i" + @echo "... src/sigar.s" + @echo "... src/sigar_cache.o" + @echo "... src/sigar_cache.i" + @echo "... src/sigar_cache.s" + @echo "... src/sigar_fileinfo.o" + @echo "... src/sigar_fileinfo.i" + @echo "... src/sigar_fileinfo.s" + @echo "... src/sigar_format.o" + @echo "... src/sigar_format.i" + @echo "... src/sigar_format.s" + @echo "... src/sigar_getline.o" + @echo "... src/sigar_getline.i" + @echo "... src/sigar_getline.s" + @echo "... src/sigar_ptql.o" + @echo "... src/sigar_ptql.i" + @echo "... src/sigar_ptql.s" + @echo "... src/sigar_signal.o" + @echo "... src/sigar_signal.i" + @echo "... src/sigar_signal.s" + @echo "... src/sigar_util.o" + @echo "... src/sigar_util.i" + @echo "... src/sigar_util.s" + @echo "... src/sigar_version_autoconf.o" + @echo "... src/sigar_version_autoconf.i" + @echo "... src/sigar_version_autoconf.s" +.PHONY : help + + + +#============================================================================= +# Special targets to cleanup operation of make. + +# Special rule to run CMake to check the build system integrity. +# No rule that depends on this can have commands that come from listfiles +# because they might be regenerated. +cmake_check_build_system: + cd /Users/dlarimer/projects/AthenaRuntime && $(CMAKE_COMMAND) -H$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0 +.PHONY : cmake_check_build_system + diff --git a/vendor/sigar/cmake_install.cmake b/vendor/sigar/cmake_install.cmake new file mode 100644 index 0000000..7c84f9f --- /dev/null +++ b/vendor/sigar/cmake_install.cmake @@ -0,0 +1,37 @@ +# Install script for directory: /Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar + +# Set the install prefix +IF(NOT DEFINED CMAKE_INSTALL_PREFIX) + SET(CMAKE_INSTALL_PREFIX "/usr/local") +ENDIF(NOT DEFINED CMAKE_INSTALL_PREFIX) +STRING(REGEX REPLACE "/$" "" CMAKE_INSTALL_PREFIX "${CMAKE_INSTALL_PREFIX}") + +# Set the install configuration name. +IF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + IF(BUILD_TYPE) + STRING(REGEX REPLACE "^[^A-Za-z0-9_]+" "" + CMAKE_INSTALL_CONFIG_NAME "${BUILD_TYPE}") + ELSE(BUILD_TYPE) + SET(CMAKE_INSTALL_CONFIG_NAME "Release") + ENDIF(BUILD_TYPE) + MESSAGE(STATUS "Install configuration: \"${CMAKE_INSTALL_CONFIG_NAME}\"") +ENDIF(NOT DEFINED CMAKE_INSTALL_CONFIG_NAME) + +# Set the component getting installed. +IF(NOT CMAKE_INSTALL_COMPONENT) + IF(COMPONENT) + MESSAGE(STATUS "Install component: \"${COMPONENT}\"") + SET(CMAKE_INSTALL_COMPONENT "${COMPONENT}") + ELSE(COMPONENT) + SET(CMAKE_INSTALL_COMPONENT) + ENDIF(COMPONENT) +ENDIF(NOT CMAKE_INSTALL_COMPONENT) + +IF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + FILE(INSTALL DESTINATION "${CMAKE_INSTALL_PREFIX}/lib" TYPE STATIC_LIBRARY FILES "/Users/dlarimer/projects/AthenaRuntime/vendor/fc/vendor/sigar/libsigar.a") + IF(EXISTS "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsigar.a" AND + NOT IS_SYMLINK "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsigar.a") + EXECUTE_PROCESS(COMMAND "/opt/local/bin/ranlib" "$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/lib/libsigar.a") + ENDIF() +ENDIF(NOT CMAKE_INSTALL_COMPONENT OR "${CMAKE_INSTALL_COMPONENT}" STREQUAL "Unspecified") + diff --git a/vendor/sigar/include/sigar.h b/vendor/sigar/include/sigar.h new file mode 100644 index 0000000..3b26cb8 --- /dev/null +++ b/vendor/sigar/include/sigar.h @@ -0,0 +1,943 @@ +/* + * Copyright (c) 2004-2008 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2009-2010 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGAR_H +#define SIGAR_H + +/* System Information Gatherer And Reporter */ + +#include + +#ifndef MAX_INTERFACE_NAME_LEN +#define MAX_INTERFACE_NAME_LEN 256 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(_LP64) || \ + defined(__LP64__) || \ + defined(__64BIT__) || \ + defined(__powerpc64__) || \ + defined(__osf__) +#define SIGAR_64BIT +#endif + +/* for printf sigar_uint64_t */ +#ifdef SIGAR_64BIT +# define SIGAR_F_U64 "%lu" +#else +# define SIGAR_F_U64 "%Lu" +#endif + +#if defined(WIN32) + +typedef unsigned __int32 sigar_uint32_t; + +typedef unsigned __int64 sigar_uint64_t; + +typedef __int32 sigar_int32_t; + +typedef __int64 sigar_int64_t; + +#elif ULONG_MAX > 4294967295UL + +typedef unsigned int sigar_uint32_t; + +typedef unsigned long sigar_uint64_t; + +typedef int sigar_int32_t; + +typedef long sigar_int64_t; + +#else + +typedef unsigned int sigar_uint32_t; + +typedef unsigned long long sigar_uint64_t; + +typedef int sigar_int32_t; + +typedef long long sigar_int64_t; + +#endif + +#define SIGAR_FIELD_NOTIMPL -1 + +#define SIGAR_OK 0 +#define SIGAR_START_ERROR 20000 +#define SIGAR_ENOTIMPL (SIGAR_START_ERROR + 1) +#define SIGAR_OS_START_ERROR (SIGAR_START_ERROR*2) + +#ifdef WIN32 +# define SIGAR_ENOENT ERROR_FILE_NOT_FOUND +# define SIGAR_EACCES ERROR_ACCESS_DENIED +# define SIGAR_ENXIO ERROR_BAD_DRIVER_LEVEL +#else +# define SIGAR_ENOENT ENOENT +# define SIGAR_EACCES EACCES +# define SIGAR_ENXIO ENXIO +#endif + +#ifdef WIN32 +# define SIGAR_DECLARE(type) \ + __declspec(dllexport) type __stdcall +#else +# define SIGAR_DECLARE(type) type +#endif + +#if defined(PATH_MAX) +# define SIGAR_PATH_MAX PATH_MAX +#elif defined(MAXPATHLEN) +# define SIGAR_PATH_MAX MAXPATHLEN +#else +# define SIGAR_PATH_MAX 4096 +#endif + +#ifdef WIN32 +typedef sigar_uint64_t sigar_pid_t; +typedef unsigned long sigar_uid_t; +typedef unsigned long sigar_gid_t; +#else +#include +typedef pid_t sigar_pid_t; +typedef uid_t sigar_uid_t; +typedef gid_t sigar_gid_t; +#endif + +typedef struct sigar_t sigar_t; + +SIGAR_DECLARE(int) sigar_open(sigar_t **sigar); + +SIGAR_DECLARE(int) sigar_close(sigar_t *sigar); + +SIGAR_DECLARE(sigar_pid_t) sigar_pid_get(sigar_t *sigar); + +SIGAR_DECLARE(int) sigar_proc_kill(sigar_pid_t pid, int signum); + +SIGAR_DECLARE(int) sigar_signum_get(char *name); + +SIGAR_DECLARE(char *) sigar_strerror(sigar_t *sigar, int err); + +/* system memory info */ + +typedef struct { + sigar_uint64_t + ram, + total, + used, + free, + actual_used, + actual_free; + double used_percent; + double free_percent; +} sigar_mem_t; + +SIGAR_DECLARE(int) sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem); + +typedef struct { + sigar_uint64_t + total, + used, + free, + page_in, + page_out; +} sigar_swap_t; + +SIGAR_DECLARE(int) sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap); + +typedef struct { + sigar_uint64_t + user, + sys, + nice, + idle, + wait, + irq, + soft_irq, + stolen, + total; +} sigar_cpu_t; + +SIGAR_DECLARE(int) sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu); + +typedef struct { + unsigned long number; + unsigned long size; + sigar_cpu_t *data; +} sigar_cpu_list_t; + +SIGAR_DECLARE(int) sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist); + +SIGAR_DECLARE(int) sigar_cpu_list_destroy(sigar_t *sigar, + sigar_cpu_list_t *cpulist); + +typedef struct { + char vendor[128]; + char model[128]; + int mhz; + int mhz_max; + int mhz_min; + sigar_uint64_t cache_size; + int total_sockets; + int total_cores; + int cores_per_socket; +} sigar_cpu_info_t; + +typedef struct { + unsigned long number; + unsigned long size; + sigar_cpu_info_t *data; +} sigar_cpu_info_list_t; + +SIGAR_DECLARE(int) +sigar_cpu_info_list_get(sigar_t *sigar, + sigar_cpu_info_list_t *cpu_infos); + +SIGAR_DECLARE(int) +sigar_cpu_info_list_destroy(sigar_t *sigar, + sigar_cpu_info_list_t *cpu_infos); + +typedef struct { + double uptime; +} sigar_uptime_t; + +SIGAR_DECLARE(int) sigar_uptime_get(sigar_t *sigar, + sigar_uptime_t *uptime); + +typedef struct { + double loadavg[3]; +} sigar_loadavg_t; + +SIGAR_DECLARE(int) sigar_loadavg_get(sigar_t *sigar, + sigar_loadavg_t *loadavg); + +typedef struct { + unsigned long number; + unsigned long size; + sigar_pid_t *data; +} sigar_proc_list_t; + +typedef struct { + /* RLIMIT_CPU */ + sigar_uint64_t cpu_cur, cpu_max; + /* RLIMIT_FSIZE */ + sigar_uint64_t file_size_cur, file_size_max; + /* PIPE_BUF */ + sigar_uint64_t pipe_size_cur, pipe_size_max; + /* RLIMIT_DATA */ + sigar_uint64_t data_cur, data_max; + /* RLIMIT_STACK */ + sigar_uint64_t stack_cur, stack_max; + /* RLIMIT_CORE */ + sigar_uint64_t core_cur, core_max; + /* RLIMIT_RSS */ + sigar_uint64_t memory_cur, memory_max; + /* RLIMIT_NPROC */ + sigar_uint64_t processes_cur, processes_max; + /* RLIMIT_NOFILE */ + sigar_uint64_t open_files_cur, open_files_max; + /* RLIMIT_AS */ + sigar_uint64_t virtual_memory_cur, virtual_memory_max; +} sigar_resource_limit_t; + +SIGAR_DECLARE(int) sigar_resource_limit_get(sigar_t *sigar, + sigar_resource_limit_t *rlimit); + +SIGAR_DECLARE(int) sigar_proc_list_get(sigar_t *sigar, + sigar_proc_list_t *proclist); + +SIGAR_DECLARE(int) sigar_proc_list_destroy(sigar_t *sigar, + sigar_proc_list_t *proclist); + +typedef struct { + sigar_uint64_t total; + sigar_uint64_t sleeping; + sigar_uint64_t running; + sigar_uint64_t zombie; + sigar_uint64_t stopped; + sigar_uint64_t idle; + sigar_uint64_t threads; +} sigar_proc_stat_t; + +SIGAR_DECLARE(int) sigar_proc_stat_get(sigar_t *sigar, + sigar_proc_stat_t *procstat); + +typedef struct { + sigar_uint64_t + size, + resident, + share, + minor_faults, + major_faults, + page_faults; +} sigar_proc_mem_t; + +SIGAR_DECLARE(int) sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_mem_t *procmem); + +typedef struct { + sigar_uid_t uid; + sigar_gid_t gid; + sigar_uid_t euid; + sigar_gid_t egid; +} sigar_proc_cred_t; + +SIGAR_DECLARE(int) sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_cred_t *proccred); + +#define SIGAR_CRED_NAME_MAX 512 + +typedef struct { + char user[SIGAR_CRED_NAME_MAX]; + char group[SIGAR_CRED_NAME_MAX]; +} sigar_proc_cred_name_t; + +SIGAR_DECLARE(int) +sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_cred_name_t *proccredname); + +typedef struct { + sigar_uint64_t + start_time, + user, + sys, + total; +} sigar_proc_time_t; + +SIGAR_DECLARE(int) sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_time_t *proctime); + +typedef struct { + /* must match sigar_proc_time_t fields */ + sigar_uint64_t + start_time, + user, + sys, + total; + sigar_uint64_t last_time; + double percent; +} sigar_proc_cpu_t; + +SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_cpu_t *proccpu); + +#define SIGAR_PROC_STATE_SLEEP 'S' +#define SIGAR_PROC_STATE_RUN 'R' +#define SIGAR_PROC_STATE_STOP 'T' +#define SIGAR_PROC_STATE_ZOMBIE 'Z' +#define SIGAR_PROC_STATE_IDLE 'D' + +#define SIGAR_PROC_NAME_LEN 128 + +typedef struct { + char name[SIGAR_PROC_NAME_LEN]; + char state; + sigar_pid_t ppid; + int tty; + int priority; + int nice; + int processor; + sigar_uint64_t threads; +} sigar_proc_state_t; + +SIGAR_DECLARE(int) sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_state_t *procstate); + +typedef struct { + unsigned long number; + unsigned long size; + char **data; +} sigar_proc_args_t; + +SIGAR_DECLARE(int) sigar_proc_args_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs); + +SIGAR_DECLARE(int) sigar_proc_args_destroy(sigar_t *sigar, + sigar_proc_args_t *procargs); + +typedef struct { + void *data; /* user data */ + + enum { + SIGAR_PROC_ENV_ALL, + SIGAR_PROC_ENV_KEY + } type; + + /* used for SIGAR_PROC_ENV_KEY */ + const char *key; + int klen; + + int (*env_getter)(void *, const char *, int, char *, int); +} sigar_proc_env_t; + +SIGAR_DECLARE(int) sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_env_t *procenv); + +typedef struct { + sigar_uint64_t total; + /* XXX - which are files, sockets, etc. */ +} sigar_proc_fd_t; + +SIGAR_DECLARE(int) sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_fd_t *procfd); + +typedef struct { + char name[SIGAR_PATH_MAX+1]; + char cwd[SIGAR_PATH_MAX+1]; + char root[SIGAR_PATH_MAX+1]; +} sigar_proc_exe_t; + +SIGAR_DECLARE(int) sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_exe_t *procexe); + +typedef struct { + void *data; /* user data */ + + int (*module_getter)(void *, char *, int); +} sigar_proc_modules_t; + +SIGAR_DECLARE(int) sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_modules_t *procmods); + +typedef struct { + sigar_uint64_t user; + sigar_uint64_t sys; + sigar_uint64_t total; +} sigar_thread_cpu_t; + +SIGAR_DECLARE(int) sigar_thread_cpu_get(sigar_t *sigar, + sigar_uint64_t id, + sigar_thread_cpu_t *cpu); + +typedef enum { + SIGAR_FSTYPE_UNKNOWN, + SIGAR_FSTYPE_NONE, + SIGAR_FSTYPE_LOCAL_DISK, + SIGAR_FSTYPE_NETWORK, + SIGAR_FSTYPE_RAM_DISK, + SIGAR_FSTYPE_CDROM, + SIGAR_FSTYPE_SWAP, + SIGAR_FSTYPE_MAX +} sigar_file_system_type_e; + +#define SIGAR_FS_NAME_LEN SIGAR_PATH_MAX +#define SIGAR_FS_INFO_LEN 256 + +typedef struct { + char dir_name[SIGAR_FS_NAME_LEN]; + char dev_name[SIGAR_FS_NAME_LEN]; + char type_name[SIGAR_FS_INFO_LEN]; /* e.g. "local" */ + char sys_type_name[SIGAR_FS_INFO_LEN]; /* e.g. "ext3" */ + char options[SIGAR_FS_INFO_LEN]; + sigar_file_system_type_e type; + unsigned long flags; +} sigar_file_system_t; + +typedef struct { + unsigned long number; + unsigned long size; + sigar_file_system_t *data; +} sigar_file_system_list_t; + +SIGAR_DECLARE(int) +sigar_file_system_list_get(sigar_t *sigar, + sigar_file_system_list_t *fslist); + +SIGAR_DECLARE(int) +sigar_file_system_list_destroy(sigar_t *sigar, + sigar_file_system_list_t *fslist); + +typedef struct { + sigar_uint64_t reads; + sigar_uint64_t writes; + sigar_uint64_t write_bytes; + sigar_uint64_t read_bytes; + sigar_uint64_t rtime; + sigar_uint64_t wtime; + sigar_uint64_t qtime; + sigar_uint64_t time; + sigar_uint64_t snaptime; + double service_time; + double queue; +} sigar_disk_usage_t; + +/* XXX for sigar_file_system_usage_t compat */ +#define disk_reads disk.reads +#define disk_writes disk.writes +#define disk_write_bytes disk.write_bytes +#define disk_read_bytes disk.read_bytes +#define disk_queue disk.queue +#define disk_service_time disk.service_time + +typedef struct { + sigar_disk_usage_t disk; + double use_percent; + sigar_uint64_t total; + sigar_uint64_t free; + sigar_uint64_t used; + sigar_uint64_t avail; + sigar_uint64_t files; + sigar_uint64_t free_files; +} sigar_file_system_usage_t; + +#undef SIGAR_DISK_USAGE_T + +SIGAR_DECLARE(int) +sigar_file_system_usage_get(sigar_t *sigar, + const char *dirname, + sigar_file_system_usage_t *fsusage); + +SIGAR_DECLARE(int) sigar_disk_usage_get(sigar_t *sigar, + const char *name, + sigar_disk_usage_t *disk); + +SIGAR_DECLARE(int) +sigar_file_system_ping(sigar_t *sigar, + sigar_file_system_t *fs); + +typedef struct { + enum { + SIGAR_AF_UNSPEC, + SIGAR_AF_INET, + SIGAR_AF_INET6, + SIGAR_AF_LINK + } family; + union { + sigar_uint32_t in; + sigar_uint32_t in6[4]; + unsigned char mac[8]; + } addr; +} sigar_net_address_t; + +#define SIGAR_INET6_ADDRSTRLEN 46 + +#define SIGAR_MAXDOMAINNAMELEN 256 +#define SIGAR_MAXHOSTNAMELEN 256 + +typedef struct { + char default_gateway[SIGAR_INET6_ADDRSTRLEN]; + char default_gateway_interface[MAX_INTERFACE_NAME_LEN]; + char host_name[SIGAR_MAXHOSTNAMELEN]; + char domain_name[SIGAR_MAXDOMAINNAMELEN]; + char primary_dns[SIGAR_INET6_ADDRSTRLEN]; + char secondary_dns[SIGAR_INET6_ADDRSTRLEN]; +} sigar_net_info_t; + +SIGAR_DECLARE(int) +sigar_net_info_get(sigar_t *sigar, + sigar_net_info_t *netinfo); + +#define SIGAR_RTF_UP 0x1 +#define SIGAR_RTF_GATEWAY 0x2 +#define SIGAR_RTF_HOST 0x4 + +typedef struct { + sigar_net_address_t destination; + sigar_net_address_t gateway; + sigar_net_address_t mask; + sigar_uint64_t + flags, + refcnt, + use, + metric, + mtu, + window, + irtt; + char ifname[MAX_INTERFACE_NAME_LEN]; +} sigar_net_route_t; + +typedef struct { + unsigned long number; + unsigned long size; + sigar_net_route_t *data; +} sigar_net_route_list_t; + +SIGAR_DECLARE(int) sigar_net_route_list_get(sigar_t *sigar, + sigar_net_route_list_t *routelist); + +SIGAR_DECLARE(int) sigar_net_route_list_destroy(sigar_t *sigar, + sigar_net_route_list_t *routelist); + +/* + * platforms define most of these "standard" flags, + * but of course, with different values in some cases. + */ +#define SIGAR_IFF_UP 0x1 +#define SIGAR_IFF_BROADCAST 0x2 +#define SIGAR_IFF_DEBUG 0x4 +#define SIGAR_IFF_LOOPBACK 0x8 +#define SIGAR_IFF_POINTOPOINT 0x10 +#define SIGAR_IFF_NOTRAILERS 0x20 +#define SIGAR_IFF_RUNNING 0x40 +#define SIGAR_IFF_NOARP 0x80 +#define SIGAR_IFF_PROMISC 0x100 +#define SIGAR_IFF_ALLMULTI 0x200 +#define SIGAR_IFF_MULTICAST 0x800 +#define SIGAR_IFF_SLAVE 0x1000 +#define SIGAR_IFF_MASTER 0x2000 +#define SIGAR_IFF_DYNAMIC 0x4000 + +#define SIGAR_NULL_HWADDR "00:00:00:00:00:00" + +/* scope values from linux-2.6/include/net/ipv6.h */ +#define SIGAR_IPV6_ADDR_ANY 0x0000 +#define SIGAR_IPV6_ADDR_UNICAST 0x0001 +#define SIGAR_IPV6_ADDR_MULTICAST 0x0002 +#define SIGAR_IPV6_ADDR_LOOPBACK 0x0010 +#define SIGAR_IPV6_ADDR_LINKLOCAL 0x0020 +#define SIGAR_IPV6_ADDR_SITELOCAL 0x0040 +#define SIGAR_IPV6_ADDR_COMPATv4 0x0080 + +typedef struct { + char name[MAX_INTERFACE_NAME_LEN]; + char type[64]; + char description[256]; + sigar_net_address_t hwaddr; + sigar_net_address_t address; + sigar_net_address_t destination; + sigar_net_address_t broadcast; + sigar_net_address_t netmask; + sigar_net_address_t address6; + int prefix6_length; + int scope6; + sigar_uint64_t + flags, + mtu, + metric; + int tx_queue_len; +} sigar_net_interface_config_t; + +SIGAR_DECLARE(int) +sigar_net_interface_config_get(sigar_t *sigar, + const char *name, + sigar_net_interface_config_t *ifconfig); + +SIGAR_DECLARE(int) +sigar_net_interface_config_primary_get(sigar_t *sigar, + sigar_net_interface_config_t *ifconfig); + +typedef struct { + sigar_uint64_t + /* received */ + rx_packets, + rx_bytes, + rx_errors, + rx_dropped, + rx_overruns, + rx_frame, + /* transmitted */ + tx_packets, + tx_bytes, + tx_errors, + tx_dropped, + tx_overruns, + tx_collisions, + tx_carrier, + speed; +} sigar_net_interface_stat_t; + +SIGAR_DECLARE(int) +sigar_net_interface_stat_get(sigar_t *sigar, + const char *name, + sigar_net_interface_stat_t *ifstat); + +typedef struct { + unsigned long number; + unsigned long size; + char **data; +} sigar_net_interface_list_t; + +SIGAR_DECLARE(int) +sigar_net_interface_list_get(sigar_t *sigar, + sigar_net_interface_list_t *iflist); + +SIGAR_DECLARE(int) +sigar_net_interface_list_destroy(sigar_t *sigar, + sigar_net_interface_list_t *iflist); + +#define SIGAR_NETCONN_CLIENT 0x01 +#define SIGAR_NETCONN_SERVER 0x02 + +#define SIGAR_NETCONN_TCP 0x10 +#define SIGAR_NETCONN_UDP 0x20 +#define SIGAR_NETCONN_RAW 0x40 +#define SIGAR_NETCONN_UNIX 0x80 + +enum { + SIGAR_TCP_ESTABLISHED = 1, + SIGAR_TCP_SYN_SENT, + SIGAR_TCP_SYN_RECV, + SIGAR_TCP_FIN_WAIT1, + SIGAR_TCP_FIN_WAIT2, + SIGAR_TCP_TIME_WAIT, + SIGAR_TCP_CLOSE, + SIGAR_TCP_CLOSE_WAIT, + SIGAR_TCP_LAST_ACK, + SIGAR_TCP_LISTEN, + SIGAR_TCP_CLOSING, + SIGAR_TCP_IDLE, + SIGAR_TCP_BOUND, + SIGAR_TCP_UNKNOWN +}; + +typedef struct { + unsigned long local_port; + sigar_net_address_t local_address; + unsigned long remote_port; + sigar_net_address_t remote_address; + sigar_uid_t uid; + unsigned long inode; + int type; + int state; + unsigned long send_queue; + unsigned long receive_queue; +} sigar_net_connection_t; + +typedef struct { + unsigned long number; + unsigned long size; + sigar_net_connection_t *data; +} sigar_net_connection_list_t; + +SIGAR_DECLARE(int) +sigar_net_connection_list_get(sigar_t *sigar, + sigar_net_connection_list_t *connlist, + int flags); + +SIGAR_DECLARE(int) +sigar_net_connection_list_destroy(sigar_t *sigar, + sigar_net_connection_list_t *connlist); + +typedef struct sigar_net_connection_walker_t sigar_net_connection_walker_t; + +/* alternative to sigar_net_connection_list_get */ +struct sigar_net_connection_walker_t { + sigar_t *sigar; + int flags; + void *data; /* user data */ + int (*add_connection)(sigar_net_connection_walker_t *walker, + sigar_net_connection_t *connection); +}; + +SIGAR_DECLARE(int) +sigar_net_connection_walk(sigar_net_connection_walker_t *walker); + +typedef struct { + int tcp_states[SIGAR_TCP_UNKNOWN]; + sigar_uint32_t tcp_inbound_total; + sigar_uint32_t tcp_outbound_total; + sigar_uint32_t all_inbound_total; + sigar_uint32_t all_outbound_total; +} sigar_net_stat_t; + +SIGAR_DECLARE(int) +sigar_net_stat_get(sigar_t *sigar, + sigar_net_stat_t *netstat, + int flags); + +SIGAR_DECLARE(int) +sigar_net_stat_port_get(sigar_t *sigar, + sigar_net_stat_t *netstat, + int flags, + sigar_net_address_t *address, + unsigned long port); + +/* TCP-MIB */ +typedef struct { + sigar_uint64_t active_opens; + sigar_uint64_t passive_opens; + sigar_uint64_t attempt_fails; + sigar_uint64_t estab_resets; + sigar_uint64_t curr_estab; + sigar_uint64_t in_segs; + sigar_uint64_t out_segs; + sigar_uint64_t retrans_segs; + sigar_uint64_t in_errs; + sigar_uint64_t out_rsts; +} sigar_tcp_t; + +SIGAR_DECLARE(int) +sigar_tcp_get(sigar_t *sigar, + sigar_tcp_t *tcp); + +typedef struct { + sigar_uint64_t null; + sigar_uint64_t getattr; + sigar_uint64_t setattr; + sigar_uint64_t root; + sigar_uint64_t lookup; + sigar_uint64_t readlink; + sigar_uint64_t read; + sigar_uint64_t writecache; + sigar_uint64_t write; + sigar_uint64_t create; + sigar_uint64_t remove; + sigar_uint64_t rename; + sigar_uint64_t link; + sigar_uint64_t symlink; + sigar_uint64_t mkdir; + sigar_uint64_t rmdir; + sigar_uint64_t readdir; + sigar_uint64_t fsstat; +} sigar_nfs_v2_t; + +typedef sigar_nfs_v2_t sigar_nfs_client_v2_t; +typedef sigar_nfs_v2_t sigar_nfs_server_v2_t; + +SIGAR_DECLARE(int) +sigar_nfs_client_v2_get(sigar_t *sigar, + sigar_nfs_client_v2_t *nfs); + +SIGAR_DECLARE(int) +sigar_nfs_server_v2_get(sigar_t *sigar, + sigar_nfs_server_v2_t *nfs); + +typedef struct { + sigar_uint64_t null; + sigar_uint64_t getattr; + sigar_uint64_t setattr; + sigar_uint64_t lookup; + sigar_uint64_t access; + sigar_uint64_t readlink; + sigar_uint64_t read; + sigar_uint64_t write; + sigar_uint64_t create; + sigar_uint64_t mkdir; + sigar_uint64_t symlink; + sigar_uint64_t mknod; + sigar_uint64_t remove; + sigar_uint64_t rmdir; + sigar_uint64_t rename; + sigar_uint64_t link; + sigar_uint64_t readdir; + sigar_uint64_t readdirplus; + sigar_uint64_t fsstat; + sigar_uint64_t fsinfo; + sigar_uint64_t pathconf; + sigar_uint64_t commit; +} sigar_nfs_v3_t; + +typedef sigar_nfs_v3_t sigar_nfs_client_v3_t; +typedef sigar_nfs_v3_t sigar_nfs_server_v3_t; + +SIGAR_DECLARE(int) +sigar_nfs_client_v3_get(sigar_t *sigar, + sigar_nfs_client_v3_t *nfs); + +SIGAR_DECLARE(int) +sigar_nfs_server_v3_get(sigar_t *sigar, + sigar_nfs_server_v3_t *nfs); + +SIGAR_DECLARE(int) +sigar_net_listen_address_get(sigar_t *sigar, + unsigned long port, + sigar_net_address_t *address); + +typedef struct { + char ifname[MAX_INTERFACE_NAME_LEN]; + char type[64]; + sigar_net_address_t hwaddr; + sigar_net_address_t address; + sigar_uint64_t flags; +} sigar_arp_t; + +typedef struct { + unsigned long number; + unsigned long size; + sigar_arp_t *data; +} sigar_arp_list_t; + +SIGAR_DECLARE(int) sigar_arp_list_get(sigar_t *sigar, + sigar_arp_list_t *arplist); + +SIGAR_DECLARE(int) sigar_arp_list_destroy(sigar_t *sigar, + sigar_arp_list_t *arplist); + +typedef struct { + char user[32]; + char device[32]; + char host[256]; + sigar_uint64_t time; +} sigar_who_t; + +typedef struct { + unsigned long number; + unsigned long size; + sigar_who_t *data; +} sigar_who_list_t; + +SIGAR_DECLARE(int) sigar_who_list_get(sigar_t *sigar, + sigar_who_list_t *wholist); + +SIGAR_DECLARE(int) sigar_who_list_destroy(sigar_t *sigar, + sigar_who_list_t *wholist); + +SIGAR_DECLARE(int) sigar_proc_port_get(sigar_t *sigar, + int protocol, unsigned long port, + sigar_pid_t *pid); + +typedef struct { + const char *build_date; + const char *scm_revision; + const char *version; + const char *archname; + const char *archlib; + const char *binname; + const char *description; + int major, minor, maint, build; +} sigar_version_t; + +SIGAR_DECLARE(sigar_version_t *) sigar_version_get(void); + +#define SIGAR_SYS_INFO_LEN SIGAR_MAXHOSTNAMELEN /* more than enough */ + +typedef struct { + char name[SIGAR_SYS_INFO_LEN]; /* canonicalized sysname */ + char version[SIGAR_SYS_INFO_LEN]; /* utsname.release */ + char arch[SIGAR_SYS_INFO_LEN]; + char machine[SIGAR_SYS_INFO_LEN]; + char description[SIGAR_SYS_INFO_LEN]; + char patch_level[SIGAR_SYS_INFO_LEN]; + char vendor[SIGAR_SYS_INFO_LEN]; + char vendor_version[SIGAR_SYS_INFO_LEN]; + char vendor_name[SIGAR_SYS_INFO_LEN]; /* utsname.sysname */ + char vendor_code_name[SIGAR_SYS_INFO_LEN]; +} sigar_sys_info_t; + +SIGAR_DECLARE(int) sigar_sys_info_get(sigar_t *sigar, sigar_sys_info_t *sysinfo); + +#define SIGAR_FQDN_LEN 512 + +SIGAR_DECLARE(int) sigar_fqdn_get(sigar_t *sigar, char *name, int namelen); + +SIGAR_DECLARE(int) sigar_rpc_ping(char *hostname, + int protocol, + unsigned long program, + unsigned long version); + +SIGAR_DECLARE(char *) sigar_rpc_strerror(int err); + +SIGAR_DECLARE(char *) sigar_password_get(const char *prompt); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/vendor/sigar/include/sigar_fileinfo.h b/vendor/sigar/include/sigar_fileinfo.h new file mode 100644 index 0000000..f13a4e4 --- /dev/null +++ b/vendor/sigar/include/sigar_fileinfo.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2004-2005 Hyperic, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000-2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +#include "sigar.h" + +typedef enum { + SIGAR_FILETYPE_NOFILE = 0, /**< no file type determined */ + SIGAR_FILETYPE_REG, /**< a regular file */ + SIGAR_FILETYPE_DIR, /**< a directory */ + SIGAR_FILETYPE_CHR, /**< a character device */ + SIGAR_FILETYPE_BLK, /**< a block device */ + SIGAR_FILETYPE_PIPE, /**< a FIFO / pipe */ + SIGAR_FILETYPE_LNK, /**< a symbolic link */ + SIGAR_FILETYPE_SOCK, /**< a [unix domain] socket */ + SIGAR_FILETYPE_UNKFILE /**< a file of some other unknown type */ +} sigar_file_type_e; + +#define SIGAR_UREAD 0x0400 /**< Read by user */ +#define SIGAR_UWRITE 0x0200 /**< Write by user */ +#define SIGAR_UEXECUTE 0x0100 /**< Execute by user */ + +#define SIGAR_GREAD 0x0040 /**< Read by group */ +#define SIGAR_GWRITE 0x0020 /**< Write by group */ +#define SIGAR_GEXECUTE 0x0010 /**< Execute by group */ + +#define SIGAR_WREAD 0x0004 /**< Read by others */ +#define SIGAR_WWRITE 0x0002 /**< Write by others */ +#define SIGAR_WEXECUTE 0x0001 /**< Execute by others */ + +typedef struct { + /** The access permissions of the file. Mimics Unix access rights. */ + sigar_uint64_t permissions; + sigar_file_type_e type; + /** The user id that owns the file */ + sigar_uid_t uid; + /** The group id that owns the file */ + sigar_gid_t gid; + /** The inode of the file. */ + sigar_uint64_t inode; + /** The id of the device the file is on. */ + sigar_uint64_t device; + /** The number of hard links to the file. */ + sigar_uint64_t nlink; + /** The size of the file */ + sigar_uint64_t size; + /** The time the file was last accessed */ + sigar_uint64_t atime; + /** The time the file was last modified */ + sigar_uint64_t mtime; + /** The time the file was last changed */ + sigar_uint64_t ctime; +} sigar_file_attrs_t; + +typedef struct { + sigar_uint64_t total; + sigar_uint64_t files; + sigar_uint64_t subdirs; + sigar_uint64_t symlinks; + sigar_uint64_t chrdevs; + sigar_uint64_t blkdevs; + sigar_uint64_t sockets; + sigar_uint64_t disk_usage; +} sigar_dir_stat_t; + +typedef sigar_dir_stat_t sigar_dir_usage_t; + +SIGAR_DECLARE(const char *) +sigar_file_attrs_type_string_get(sigar_file_type_e type); + +SIGAR_DECLARE(int) sigar_file_attrs_get(sigar_t *sigar, + const char *file, + sigar_file_attrs_t *fileattrs); + +SIGAR_DECLARE(int) sigar_link_attrs_get(sigar_t *sigar, + const char *file, + sigar_file_attrs_t *fileattrs); + +SIGAR_DECLARE(int)sigar_file_attrs_mode_get(sigar_uint64_t permissions); + +SIGAR_DECLARE(char *) +sigar_file_attrs_permissions_string_get(sigar_uint64_t permissions, + char *str); + +SIGAR_DECLARE(int) sigar_dir_stat_get(sigar_t *sigar, + const char *dir, + sigar_dir_stat_t *dirstats); + +SIGAR_DECLARE(int) sigar_dir_usage_get(sigar_t *sigar, + const char *dir, + sigar_dir_usage_t *dirusage); diff --git a/vendor/sigar/include/sigar_format.h b/vendor/sigar/include/sigar_format.h new file mode 100644 index 0000000..3bce29b --- /dev/null +++ b/vendor/sigar/include/sigar_format.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2007-2008 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGAR_FORMAT_H +#define SIGAR_FORMAT_H + +typedef struct { + double user; + double sys; + double nice; + double idle; + double wait; + double irq; + double soft_irq; + double stolen; + double combined; +} sigar_cpu_perc_t; + +SIGAR_DECLARE(int) sigar_cpu_perc_calculate(sigar_cpu_t *prev, + sigar_cpu_t *curr, + sigar_cpu_perc_t *perc); + +SIGAR_DECLARE(int) sigar_uptime_string(sigar_t *sigar, + sigar_uptime_t *uptime, + char *buffer, + int buflen); + +SIGAR_DECLARE(char *) sigar_format_size(sigar_uint64_t size, char *buf); + +SIGAR_DECLARE(int) sigar_net_address_equals(sigar_net_address_t *addr1, + sigar_net_address_t *addr2); + +SIGAR_DECLARE(int) sigar_net_address_to_string(sigar_t *sigar, + sigar_net_address_t *address, + char *addr_str); + +SIGAR_DECLARE(const char *)sigar_net_scope_to_string(int type); + +SIGAR_DECLARE(sigar_uint32_t) sigar_net_address_hash(sigar_net_address_t *address); + +SIGAR_DECLARE(const char *)sigar_net_connection_type_get(int type); + +SIGAR_DECLARE(const char *)sigar_net_connection_state_get(int state); + +SIGAR_DECLARE(char *) sigar_net_interface_flags_to_string(sigar_uint64_t flags, char *buf); + +SIGAR_DECLARE(char *)sigar_net_services_name_get(sigar_t *sigar, + int protocol, unsigned long port); + +#endif + diff --git a/vendor/sigar/include/sigar_getline.h b/vendor/sigar/include/sigar_getline.h new file mode 100644 index 0000000..f5bbc7c --- /dev/null +++ b/vendor/sigar/include/sigar_getline.h @@ -0,0 +1,18 @@ +#ifndef SIGAR_GETLINE_H +#define SIGAR_GETLINE_H + +#include "sigar.h" + +typedef int (*sigar_getline_completer_t)(char *, int, int *); + +SIGAR_DECLARE(char *) sigar_getline(char *prompt); +SIGAR_DECLARE(void) sigar_getline_setwidth(int width); +SIGAR_DECLARE(void) sigar_getline_redraw(void); +SIGAR_DECLARE(void) sigar_getline_reset(void); +SIGAR_DECLARE(void) sigar_getline_windowchanged(); +SIGAR_DECLARE(void) sigar_getline_histinit(char *file); +SIGAR_DECLARE(void) sigar_getline_histadd(char *buf); +SIGAR_DECLARE(int) sigar_getline_eof(); +SIGAR_DECLARE(void) sigar_getline_completer_set(sigar_getline_completer_t func); + +#endif /* SIGAR_GETLINE_H */ diff --git a/vendor/sigar/include/sigar_log.h b/vendor/sigar/include/sigar_log.h new file mode 100644 index 0000000..cc32f9a --- /dev/null +++ b/vendor/sigar/include/sigar_log.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2004, 2006 Hyperic, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGAR_LOG_H +#define SIGAR_LOG_H + +#include + +#define SIGAR_LOG_FATAL 0 +#define SIGAR_LOG_ERROR 1 +#define SIGAR_LOG_WARN 2 +#define SIGAR_LOG_INFO 3 +#define SIGAR_LOG_DEBUG 4 +#define SIGAR_LOG_TRACE 5 + +#define SIGAR_LOG_IS_FATAL(sigar) \ + (sigar->log_level >= SIGAR_LOG_FATAL) + +#define SIGAR_LOG_IS_ERROR(sigar) \ + (sigar->log_level >= SIGAR_LOG_ERROR) + +#define SIGAR_LOG_IS_WARN(sigar) \ + (sigar->log_level >= SIGAR_LOG_WARN) + +#define SIGAR_LOG_IS_INFO(sigar) \ + (sigar->log_level >= SIGAR_LOG_INFO) + +#define SIGAR_LOG_IS_DEBUG(sigar) \ + (sigar->log_level >= SIGAR_LOG_DEBUG) + +#define SIGAR_LOG_IS_TRACE(sigar) \ + (sigar->log_level >= SIGAR_LOG_TRACE) + +#define SIGAR_STRINGIFY(n) #n + +#define SIGAR_LOG_FILELINE \ + __FILE__ ":" SIGAR_STRINGIFY(__LINE__) + +#if defined(__GNUC__) +# if (__GNUC__ > 2) +# define SIGAR_FUNC __func__ +# else +# define SIGAR_FUNC __FUNCTION__ +# endif +#else +# define SIGAR_FUNC SIGAR_LOG_FILELINE +#endif + +typedef void (*sigar_log_impl_t)(sigar_t *, void *, int, char *); + +SIGAR_DECLARE(void) sigar_log_printf(sigar_t *sigar, int level, + const char *format, ...); + +SIGAR_DECLARE(void) sigar_log(sigar_t *sigar, int level, char *message); + +SIGAR_DECLARE(void) sigar_log_impl_set(sigar_t *sigar, void *data, + sigar_log_impl_t impl); + +SIGAR_DECLARE(void) sigar_log_impl_file(sigar_t *sigar, void *data, + int level, char *message); + +SIGAR_DECLARE(int) sigar_log_level_get(sigar_t *sigar); + +SIGAR_DECLARE(void) sigar_log_level_set(sigar_t *sigar, int level); + + +#endif /* SIGAR_LOG_H */ diff --git a/vendor/sigar/include/sigar_private.h b/vendor/sigar/include/sigar_private.h new file mode 100644 index 0000000..cfc9aa2 --- /dev/null +++ b/vendor/sigar/include/sigar_private.h @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2004-2008 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2009-2010 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGAR_PRIVATE_DOT_H +#define SIGAR_PRIVATE_DOT_H + +#include "sigar_log.h" +#include "sigar_ptql.h" + +#include +#include +#include + +#ifndef WIN32 +#include +#include +#ifndef DARWIN +#include +#endif +#endif + +#ifdef DMALLOC +#define _MEMORY_H /* exclude memory.h on solaris */ +#define DMALLOC_FUNC_CHECK +#include +#endif + +/* common to all os sigar_t's */ +/* XXX: this is ugly; but don't want the same stuffs + * duplicated on 4 platforms and am too lazy to change + * sigar_t to the way it was originally where sigar_t was + * common and contained a sigar_os_t. + * feel free trav ;-) + */ +#define SIGAR_T_BASE \ + int cpu_list_cores; \ + int log_level; \ + void *log_data; \ + sigar_log_impl_t log_impl; \ + void *ptql_re_data; \ + sigar_ptql_re_impl_t ptql_re_impl; \ + unsigned int ncpu; \ + unsigned long version; \ + unsigned long boot_time; \ + int ticks; \ + sigar_pid_t pid; \ + char errbuf[256]; \ + char *ifconf_buf; \ + int ifconf_len; \ + char *self_path; \ + sigar_proc_list_t *pids; \ + sigar_cache_t *fsdev; \ + sigar_cache_t *proc_cpu; \ + sigar_cache_t *net_listen; \ + sigar_cache_t *net_services_tcp; \ + sigar_cache_t *net_services_udp + +#if defined(WIN32) +# define SIGAR_INLINE __inline +#elif defined(__GNUC__) +# define SIGAR_INLINE inline +#else +# define SIGAR_INLINE +#endif + +#ifdef DMALLOC +/* linux has its own strdup macro, make sure we use dmalloc's */ +#define sigar_strdup(s) \ + dmalloc_strndup(__FILE__, __LINE__, (s), -1, 0) +#else +# ifdef WIN32 +# define sigar_strdup(s) _strdup(s) +# else +# define sigar_strdup(s) strdup(s) +# endif +#endif + +#define SIGAR_ZERO(s) \ + memset(s, '\0', sizeof(*(s))) + +#define SIGAR_STRNCPY(dest, src, len) \ + strncpy(dest, src, len); \ + dest[len-1] = '\0' + +/* we use fixed size buffers pretty much everywhere */ +/* this is strncpy + ensured \0 terminator */ +#define SIGAR_SSTRCPY(dest, src) \ + SIGAR_STRNCPY(dest, src, sizeof(dest)) + +#ifndef strEQ +#define strEQ(s1, s2) (strcmp(s1, s2) == 0) +#endif + +#ifndef strnEQ +#define strnEQ(s1, s2, n) (strncmp(s1, s2, n) == 0) +#endif + +#ifdef WIN32 +#define strcasecmp stricmp +#define strncasecmp strnicmp +#endif + +#ifndef strcaseEQ +#define strcaseEQ(s1, s2) (strcasecmp(s1, s2) == 0) +#endif + +#ifndef strncaseEQ +#define strncaseEQ(s1, s2, n) (strncasecmp(s1, s2, n) == 0) +#endif + +#ifdef offsetof +#define sigar_offsetof offsetof +#else +#define sigar_offsetof(type, field) ((size_t)(&((type *)0)->field)) +#endif + +#define SIGAR_MSEC 1000L +#define SIGAR_USEC 1000000L +#define SIGAR_NSEC 1000000000L + +#define SIGAR_SEC2NANO(s) \ + ((sigar_uint64_t)(s) * (sigar_uint64_t)SIGAR_NSEC) + +/* cpu ticks to milliseconds */ +#define SIGAR_TICK2MSEC(s) \ + ((sigar_uint64_t)(s) * ((sigar_uint64_t)SIGAR_MSEC / (double)sigar->ticks)) + +#define SIGAR_TICK2NSEC(s) \ + ((sigar_uint64_t)(s) * ((sigar_uint64_t)SIGAR_NSEC / (double)sigar->ticks)) + +/* nanoseconds to milliseconds */ +#define SIGAR_NSEC2MSEC(s) \ + ((sigar_uint64_t)(s) / ((sigar_uint64_t)1000000L)) + +#define IFTYPE_LO 2 +#define IFTYPE_ETH 3 + +#define SIGAR_LAST_PROC_EXPIRE 2 + +#define SIGAR_FS_MAX 10 + +#define SIGAR_CPU_INFO_MAX 4 + +#define SIGAR_CPU_LIST_MAX 4 + +#define SIGAR_PROC_LIST_MAX 256 + +#define SIGAR_PROC_ARGS_MAX 12 + +#define SIGAR_NET_ROUTE_LIST_MAX 6 + +#define SIGAR_NET_IFLIST_MAX 20 + +#define SIGAR_NET_CONNLIST_MAX 20 + +#define SIGAR_ARP_LIST_MAX 12 + +#define SIGAR_WHO_LIST_MAX 12 + +int sigar_os_open(sigar_t **sigar); + +int sigar_os_close(sigar_t *sigar); + +char *sigar_os_error_string(sigar_t *sigar, int err); + +char *sigar_strerror_get(int err, char *errbuf, int buflen); + +void sigar_strerror_set(sigar_t *sigar, char *msg); + +void sigar_strerror_printf(sigar_t *sigar, const char *format, ...); + +int sigar_sys_info_get_uname(sigar_sys_info_t *sysinfo); + +int sigar_os_sys_info_get(sigar_t *sigar, sigar_sys_info_t *sysinfo); + +int sigar_os_proc_list_get(sigar_t *sigar, + sigar_proc_list_t *proclist); + +int sigar_proc_list_create(sigar_proc_list_t *proclist); + +int sigar_proc_list_grow(sigar_proc_list_t *proclist); + +#define SIGAR_PROC_LIST_GROW(proclist) \ + if (proclist->number >= proclist->size) { \ + sigar_proc_list_grow(proclist); \ + } + +int sigar_proc_args_create(sigar_proc_args_t *proclist); + +int sigar_proc_args_grow(sigar_proc_args_t *procargs); + +#define SIGAR_PROC_ARGS_GROW(procargs) \ + if (procargs->number >= procargs->size) { \ + sigar_proc_args_grow(procargs); \ + } + +int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs); + +int sigar_file_system_list_create(sigar_file_system_list_t *fslist); + +int sigar_file_system_list_grow(sigar_file_system_list_t *fslist); + +#define SIGAR_FILE_SYSTEM_LIST_GROW(fslist) \ + if (fslist->number >= fslist->size) { \ + sigar_file_system_list_grow(fslist); \ + } + +int sigar_os_fs_type_get(sigar_file_system_t *fsp); + +/* os plugins that set fsp->type call fs_type_get directly */ +#define sigar_fs_type_init(fsp) \ + fsp->type = SIGAR_FSTYPE_UNKNOWN; \ + sigar_fs_type_get(fsp) + +void sigar_fs_type_get(sigar_file_system_t *fsp); + +int sigar_cpu_info_list_create(sigar_cpu_info_list_t *cpu_infos); + +int sigar_cpu_info_list_grow(sigar_cpu_info_list_t *cpu_infos); + +#define SIGAR_CPU_INFO_LIST_GROW(cpu_infos) \ + if (cpu_infos->number >= cpu_infos->size) { \ + sigar_cpu_info_list_grow(cpu_infos); \ + } + +int sigar_cpu_list_create(sigar_cpu_list_t *cpulist); + +int sigar_cpu_list_grow(sigar_cpu_list_t *cpulist); + +#define SIGAR_CPU_LIST_GROW(cpulist) \ + if (cpulist->number >= cpulist->size) { \ + sigar_cpu_list_grow(cpulist); \ + } + +int sigar_net_route_list_create(sigar_net_route_list_t *routelist); + +int sigar_net_route_list_grow(sigar_net_route_list_t *net_routelist); + +#define SIGAR_NET_ROUTE_LIST_GROW(routelist) \ + if (routelist->number >= routelist->size) { \ + sigar_net_route_list_grow(routelist); \ + } + +int sigar_net_interface_list_create(sigar_net_interface_list_t *iflist); + +int sigar_net_interface_list_grow(sigar_net_interface_list_t *iflist); + +#define SIGAR_NET_IFLIST_GROW(iflist) \ + if (iflist->number >= iflist->size) { \ + sigar_net_interface_list_grow(iflist); \ + } + +int sigar_net_connection_list_create(sigar_net_connection_list_t *connlist); + +int sigar_net_connection_list_grow(sigar_net_connection_list_t *connlist); + +#define SIGAR_NET_CONNLIST_GROW(connlist) \ + if (connlist->number >= connlist->size) { \ + sigar_net_connection_list_grow(connlist); \ + } + +#define sigar_net_address_set(a, val) \ + (a).addr.in = val; \ + (a).family = SIGAR_AF_INET + +#define sigar_net_address6_set(a, val) \ + memcpy(&((a).addr.in6), val, sizeof((a).addr.in6)); \ + (a).family = SIGAR_AF_INET6 + +#define SIGAR_IFHWADDRLEN 6 + +#define sigar_net_address_mac_set(a, val, len) \ + memcpy(&((a).addr.mac), val, len); \ + (a).family = SIGAR_AF_LINK + +#define sigar_hwaddr_set_null(ifconfig) \ + SIGAR_ZERO(&ifconfig->hwaddr.addr.mac); \ + ifconfig->hwaddr.family = SIGAR_AF_LINK + +int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig); + +#define sigar_net_interface_ipv6_config_init(ifconfig) \ + ifconfig->address6.family = SIGAR_AF_INET6; \ + ifconfig->prefix6_length = 0; \ + ifconfig->scope6 = 0 + +#define SIGAR_SIN6(s) ((struct sockaddr_in6 *)(s)) + +#define SIGAR_SIN6_ADDR(s) &SIGAR_SIN6(s)->sin6_addr + +#define sigar_net_interface_scope6_set(ifconfig, addr) \ + if (IN6_IS_ADDR_LINKLOCAL(addr)) \ + ifconfig->scope6 = SIGAR_IPV6_ADDR_LINKLOCAL; \ + else if (IN6_IS_ADDR_SITELOCAL(addr)) \ + ifconfig->scope6 = SIGAR_IPV6_ADDR_SITELOCAL; \ + else if (IN6_IS_ADDR_V4COMPAT(addr)) \ + ifconfig->scope6 = SIGAR_IPV6_ADDR_COMPATv4; \ + else if (IN6_IS_ADDR_LOOPBACK(addr)) \ + ifconfig->scope6 = SIGAR_IPV6_ADDR_LOOPBACK; \ + else \ + ifconfig->scope6 = SIGAR_IPV6_ADDR_ANY + +int sigar_tcp_curr_estab(sigar_t *sigar, sigar_tcp_t *tcp); + +int sigar_arp_list_create(sigar_arp_list_t *arplist); + +int sigar_arp_list_grow(sigar_arp_list_t *arplist); + +#define SIGAR_ARP_LIST_GROW(arplist) \ + if (arplist->number >= arplist->size) { \ + sigar_arp_list_grow(arplist); \ + } + +int sigar_who_list_create(sigar_who_list_t *wholist); + +int sigar_who_list_grow(sigar_who_list_t *wholist); + +#define SIGAR_WHO_LIST_GROW(wholist) \ + if (wholist->number >= wholist->size) { \ + sigar_who_list_grow(wholist); \ + } + +int sigar_user_id_get(sigar_t *sigar, const char *name, int *uid); + +int sigar_user_name_get(sigar_t *sigar, int uid, char *buf, int buflen); + +int sigar_group_name_get(sigar_t *sigar, int gid, char *buf, int buflen); + +#define SIGAR_PROC_ENV_KEY_LOOKUP() \ + if ((procenv->type == SIGAR_PROC_ENV_KEY) && \ + (pid == sigar->pid)) \ + { \ + char *value = getenv(procenv->key); \ + if (value != NULL) { \ + procenv->env_getter(procenv->data, \ + procenv->key, \ + procenv->klen, \ + value, strlen(value)); \ + } \ + return SIGAR_OK; \ + } + +#define SIGAR_DISK_STATS_INIT(disk) \ + (disk)->reads = (disk)->writes = \ + (disk)->read_bytes = (disk)->write_bytes = \ + (disk)->rtime = (disk)->wtime = (disk)->qtime = (disk)->time = \ + (disk)->queue = (disk)->service_time = SIGAR_FIELD_NOTIMPL; \ + (disk)->snaptime = 0 + +/* key used for filesystem (/) -> device (/dev/hda1) mapping */ +/* and disk_usage cache for service_time */ +#define SIGAR_FSDEV_ID(sb) \ + (S_ISBLK((sb).st_mode) ? (sb).st_rdev : ((sb).st_ino + (sb).st_dev)) + +#if defined(WIN32) || defined(NETWARE) +int sigar_get_iftype(const char *name, int *type, int *inst); +#endif + +#define SIGAR_NIC_LOOPBACK "Local Loopback" +#define SIGAR_NIC_UNSPEC "UNSPEC" +#define SIGAR_NIC_SLIP "Serial Line IP" +#define SIGAR_NIC_CSLIP "VJ Serial Line IP" +#define SIGAR_NIC_SLIP6 "6-bit Serial Line IP" +#define SIGAR_NIC_CSLIP6 "VJ 6-bit Serial Line IP" +#define SIGAR_NIC_ADAPTIVE "Adaptive Serial Line IP" +#define SIGAR_NIC_ETHERNET "Ethernet" +#define SIGAR_NIC_ASH "Ash" +#define SIGAR_NIC_FDDI "Fiber Distributed Data Interface" +#define SIGAR_NIC_HIPPI "HIPPI" +#define SIGAR_NIC_AX25 "AMPR AX.25" +#define SIGAR_NIC_ROSE "AMPR ROSE" +#define SIGAR_NIC_NETROM "AMPR NET/ROM" +#define SIGAR_NIC_X25 "generic X.25" +#define SIGAR_NIC_TUNNEL "IPIP Tunnel" +#define SIGAR_NIC_PPP "Point-to-Point Protocol" +#define SIGAR_NIC_HDLC "(Cisco)-HDLC" +#define SIGAR_NIC_LAPB "LAPB" +#define SIGAR_NIC_ARCNET "ARCnet" +#define SIGAR_NIC_DLCI "Frame Relay DLCI" +#define SIGAR_NIC_FRAD "Frame Relay Access Device" +#define SIGAR_NIC_SIT "IPv6-in-IPv4" +#define SIGAR_NIC_IRDA "IrLAP" +#define SIGAR_NIC_EC "Econet" + +#ifndef WIN32 +#include +#endif + +#define SIGAR_HOSTENT_LEN 1024 +#if defined(_AIX) +#define SIGAR_HAS_HOSTENT_DATA +#endif + +typedef struct { + char buffer[SIGAR_HOSTENT_LEN]; + int error; +#ifndef WIN32 + struct hostent hs; +#endif +#ifdef SIGAR_HAS_HOSTENT_DATA + struct hostent_data hd; +#endif +} sigar_hostent_t; + +#endif diff --git a/vendor/sigar/include/sigar_ptql.h b/vendor/sigar/include/sigar_ptql.h new file mode 100644 index 0000000..53d28ec --- /dev/null +++ b/vendor/sigar/include/sigar_ptql.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2006-2007 Hyperic, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGAR_PTQL_H +#define SIGAR_PTQL_H + +#define SIGAR_PTQL_MALFORMED_QUERY -1 + +typedef struct sigar_ptql_query_t sigar_ptql_query_t; + +#define SIGAR_PTQL_ERRMSG_SIZE 1024 + +typedef struct { + char message[SIGAR_PTQL_ERRMSG_SIZE]; +} sigar_ptql_error_t; + +typedef int (*sigar_ptql_re_impl_t)(void *, char *, char *); + +SIGAR_DECLARE(void) sigar_ptql_re_impl_set(sigar_t *sigar, void *data, + sigar_ptql_re_impl_t impl); + +SIGAR_DECLARE(int) sigar_ptql_query_create(sigar_ptql_query_t **query, + char *ptql, + sigar_ptql_error_t *error); + +SIGAR_DECLARE(int) sigar_ptql_query_match(sigar_t *sigar, + sigar_ptql_query_t *query, + sigar_pid_t pid); + +SIGAR_DECLARE(int) sigar_ptql_query_destroy(sigar_ptql_query_t *query); + +SIGAR_DECLARE(int) sigar_ptql_query_find_process(sigar_t *sigar, + sigar_ptql_query_t *query, + sigar_pid_t *pid); + +SIGAR_DECLARE(int) sigar_ptql_query_find(sigar_t *sigar, + sigar_ptql_query_t *query, + sigar_proc_list_t *proclist); + +#endif /*SIGAR_PTQL_H*/ diff --git a/vendor/sigar/include/sigar_util.h b/vendor/sigar/include/sigar_util.h new file mode 100644 index 0000000..bc605fc --- /dev/null +++ b/vendor/sigar/include/sigar_util.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2004-2008 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGAR_UTIL_H +#define SIGAR_UTIL_H + +/* most of this is crap for dealing with linux /proc */ +#define UITOA_BUFFER_SIZE \ + (sizeof(int) * 3 + 1) + +#define SSTRLEN(s) \ + (sizeof(s)-1) + +#define sigar_strtoul(ptr) \ + strtoul(ptr, &ptr, 10) + +#define sigar_strtoull(ptr) \ + strtoull(ptr, &ptr, 10) + +#define sigar_isspace(c) \ + (isspace(((unsigned char)(c)))) + +#define sigar_isdigit(c) \ + (isdigit(((unsigned char)(c)))) + +#define sigar_isalpha(c) \ + (isalpha(((unsigned char)(c)))) + +#define sigar_isupper(c) \ + (isupper(((unsigned char)(c)))) + +#define sigar_tolower(c) \ + (tolower(((unsigned char)(c)))) + +#ifdef WIN32 +#define sigar_fileno _fileno +#define sigar_isatty _isatty +#define sigar_write _write +#else +#define sigar_fileno fileno +#define sigar_isatty isatty +#define sigar_write write +#endif + +#ifndef PROC_FS_ROOT +#define PROC_FS_ROOT "/proc/" +#endif + +#ifndef PROCP_FS_ROOT +#define PROCP_FS_ROOT "/proc/" +#endif + +sigar_int64_t sigar_time_now_millis(void); + +char *sigar_uitoa(char *buf, unsigned int n, int *len); + +int sigar_inet_ntoa(sigar_t *sigar, + sigar_uint32_t address, + char *addr_str); + +struct hostent *sigar_gethostbyname(const char *name, + sigar_hostent_t *data); + +SIGAR_INLINE char *sigar_skip_line(char *buffer, int buflen); + +SIGAR_INLINE char *sigar_skip_token(char *p); + +SIGAR_INLINE char *sigar_skip_multiple_token(char *p, int count); + +char *sigar_getword(char **line, char stop); + +char *sigar_strcasestr(const char *s1, const char *s2); + +int sigar_file2str(const char *fname, char *buffer, int buflen); + +int sigar_proc_file2str(char *buffer, int buflen, + sigar_pid_t pid, + const char *fname, + int fname_len); + +#define SIGAR_PROC_FILE2STR(buffer, pid, fname) \ + sigar_proc_file2str(buffer, sizeof(buffer), \ + pid, fname, SSTRLEN(fname)) + +#define SIGAR_PROC_FILENAME(buffer, pid, fname) \ + sigar_proc_filename(buffer, sizeof(buffer), \ + pid, fname, SSTRLEN(fname)) + +#define SIGAR_SKIP_SPACE(ptr) \ + while (sigar_isspace(*ptr)) ++ptr + +char *sigar_proc_filename(char *buffer, int buflen, + sigar_pid_t pid, + const char *fname, int fname_len); + +int sigar_proc_list_procfs_get(sigar_t *sigar, + sigar_proc_list_t *proclist); + +int sigar_proc_fd_count(sigar_t *sigar, sigar_pid_t pid, + sigar_uint64_t *total); + +/* linux + freebsd */ +int sigar_procfs_args_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs); + +int sigar_mem_calc_ram(sigar_t *sigar, sigar_mem_t *mem); + +int sigar_statvfs(sigar_t *sigar, + const char *dirname, + sigar_file_system_usage_t *fsusage); + +double sigar_file_system_usage_calc_used(sigar_t *sigar, + sigar_file_system_usage_t *fs); + +#define SIGAR_DEV_PREFIX "/dev/" + +#define SIGAR_NAME_IS_DEV(dev) \ + strnEQ(dev, SIGAR_DEV_PREFIX, SSTRLEN(SIGAR_DEV_PREFIX)) + +typedef struct { + char name[256]; + int is_partition; + sigar_disk_usage_t disk; +} sigar_iodev_t; + +sigar_iodev_t *sigar_iodev_get(sigar_t *sigar, + const char *dirname); + +int sigar_cpu_core_count(sigar_t *sigar); + +/* e.g. VM guest may have 1 virtual ncpu on multicore hosts */ +#define sigar_cpu_socket_count(sigar) \ + (sigar->ncpu < sigar->lcpu) ? sigar->ncpu : \ + (sigar->ncpu / sigar->lcpu) + +int sigar_cpu_core_rollup(sigar_t *sigar); + +void sigar_cpu_model_adjust(sigar_t *sigar, sigar_cpu_info_t *info); + +int sigar_cpu_mhz_from_model(char *model); + +char *sigar_get_self_path(sigar_t *sigar); + +#if defined(__sun) || defined(__FreeBSD__) + +#define SIGAR_HAS_DLINFO_MODULES +#include +#include + +int sigar_dlinfo_modules(sigar_t *sigar, sigar_proc_modules_t *procmods); +#endif + +typedef struct sigar_cache_entry_t sigar_cache_entry_t; + +struct sigar_cache_entry_t { + sigar_cache_entry_t *next; + sigar_uint64_t id; + void *value; +}; + +typedef struct { + sigar_cache_entry_t **entries; + unsigned int count, size; + void (*free_value)(void *ptr); +} sigar_cache_t; + +sigar_cache_t *sigar_cache_new(int size); + +sigar_cache_entry_t *sigar_cache_get(sigar_cache_t *table, + sigar_uint64_t key); + +sigar_cache_entry_t *sigar_cache_find(sigar_cache_t *table, + sigar_uint64_t key); + +void sigar_cache_destroy(sigar_cache_t *table); + +#endif /* SIGAR_UTIL_H */ diff --git a/vendor/sigar/libsigar_debug.a b/vendor/sigar/libsigar_debug.a new file mode 100644 index 0000000000000000000000000000000000000000..0195ac31c87f99aee58018c8cc323f7edc325663 GIT binary patch literal 621472 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≥<3eJt3WtFoFlI2x=EIt-Ft5S2zut~TTWFHl# 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�EGWRvH?=KX`^B!;wQf7xVH*t}V=oWvovd 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
Iy99$fRG{u*yE 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 ytA;)> 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�~0{{`w}}Z+xJr-+xHzH+vyG9Qsn!S^iN2Cm*g8Hw@Ut@H7m&pCLfDPfsB0 zoe5;Uzr_tpw(}Ms`)4Dt3b-0byWaq5_iG^A`!?W0=&zUl3g9`=pAT$-z8v^H$makL zfjkX}@>>rCWOFsZO9sYKe{+qpna{d8iIe(VC9(V@i$AN{wJEgCcyZ|^5 z`q@CN8_1afq~AOsp3mou7akzo2T1$=K-y;m={FO|eBbRA;3q)ZeE_6g8<2Ld0NE~2 zNqz{(`0kbb6Cm?70h#Y2>Fa^?Um0xwrTj6F z@xBA3{mVec`Fr3Z$ZLVLyBoMW@OGe!6X@a$^sQF{@h|66{6P^pON18y8F!tq63BL$ zC!7srKg|fRbr5h0%H0ikG%y2*A)E909)Y|GNckNgl5*YvGLAn3Plx;`Alqv#a2LoA z0_o>=AoJY}WWMWxv}*;@ZYgj){h&7KovmGfL@0 zl|B&2_UI?M2ax4_g~nt#p8#3T`#_fS7vZ0P%=aXa<=rQ|M(M3ezf5wY@Owa<>RYD+ zS-+EjEawOy%NYu!zk$;420RjSMxbBtB|4Yse+MGeocDno7j4qNB76ZDNBUafBfxR6 z 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

ILh9EdR~_C*lj8QDI~j z?~EGON1<7nLdPuD8P)7>p;@Uy$1K(vHSN-{a9t_It0GyT`0im*B`DUFT6(Jl_5Yao zLM14CG8C04R8PDfV6A}kLtQ-*+Lb9(`-C@7q2uc2?Yg=zbXBVGp-@z!&~ddo=IU0_ zS9@G76{R00GFHr~zbtxT;lQPBXtC#ca-Qr=Fu(i4y74I%Gm?^x}QB%As zQd6iIB8b?z;?F%|r%o@y*IzDf)hF~~x1tA$&h#h*g>yyJ$DDUk%Boj*i=9R^>UCnu zUaI*1NERqwyj#@673fpin)+ z`**FZSH=5VVeBOeHJ1#pBc)ht4QCC7P7sxfwV7zDxKxTQ{ZLt_=#@Q-u4(mR%D$v{ zNhAvtzZc3n1I4Z#W=t-9I}+Lb9(d(@di$5s4HtFC?# zx++!Z*u_t)=ZL;4QbU&B_$+8H!33I-X+VQ$6KHW(pm%*uYaW%>wPG&@n6S*=gfu<-M52?kX}RIIWuh zv6eKFQZZ)(C@za+f#Si#qsCLLD|GeNc+0#yRjES9?#tL4;3cB3$`~RF|ErxQ4hd_oE2VhXNERrr$%|@Pv93wh zTP>^qBg7XPU*Uq#Jti^;u8Y(ZM&9EiNxe@C&B_$2M_&CD*F&tP8L8R`crreDQ^vS9nnUPY;Zcs7;$tE;g<6q}P4T&rn!>Lf zZ;HQ;WaWydhP|h|Uh!FxtX#2Eld)TIT_RBPL1=YZ;$xst6jY&RL$!sHtl3aznI2=)JL80rFrYKF7>`m>^lEK~W~w{h?i{LdP!tXuD1HzYOh46sjGnFE%``6ZPas8wYgi6=#YJt)tL!6>I39iK_=4 zSBlq1t`zng73Nr}xWCAdqe3Ug${tnaJ(6!FzZ8n#%N3VLQ7lw^LL@6!+!XeQ?u9-5 z4<2nL!-QsdCEFBhTxk5_Z9NUEq#U|lB+AoMMeR=s^Y2P2ZjWSv;#)&mXP{VDbnLC) zYT9j~T~|u+osle1eE42ALXHc?#i1%KOK# z+$9Pfv&tSpdcPC(MN#n@6}LwbC_KkeQ+!FJrqIbT_8R7O$x+wgL}3~gJ9hOwBmI}y zeH|50VGu@8s?hON-qVw&O>w%P;^~nrQ2hN+))^?)~#fMrQF_B~803%&se?`07X&D1LC9 zZ32#c#k$C5Z(*tb4PjUd6sj4={+T@+Hf~qei(UMK&$wM_FLoKG zia1xEsmzbVdWbjmgt4|Xs*Cf{5)qv(6r$G!ULc+zQs_93Jz8&)0M8I}jyc8qM?uvn zJ}`2xu)|SP+!d)Q{IR3fvw6OdD87!WOQB;H8?Ffnx=&OM3ilEbYPmd98OK-bs<^v^ zw`UZ<(Jf12^yr4~z;^Y|@-RzmT-`p-xvy@gtEeP&{>lHRc#ltV_4{HU`wcE)$EB zh{DLMd!`eSfpN34Ud)RB?`EYv%}~ejyU@GGTTknSqCYCsb#2kt7Va*EpCS}$JtOEN z9{NX~6moA29`ICYfb&P|VtQD;T`9#!MzTQhMWL)SP^=5w_SOvQzcq|}fx^yERH88Q z6d&N~sW~(&Q>fWSfKX(oaC~G|sd#dvrf`a*)-x)N z_|Z_OE2a4HNERqgPO=`@KNRcw$i4Ls_5W@d)&hm^hoTaNk*9e7P)~1%W@QT19Q{L~ z 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 Vm0vFLKmNwu-@M;f&S(g>{{~+a1iAnK literal 0 HcmV?d00001 diff --git a/vendor/sigar/src/os/aix/aix_sigar.c b/vendor/sigar/src/os/aix/aix_sigar.c new file mode 100644 index 0000000..a4c0a88 --- /dev/null +++ b/vendor/sigar/src/os/aix/aix_sigar.c @@ -0,0 +1,2151 @@ +/* + * Copyright (c) 2004-2009 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2009-2010 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* pull in time.h before resource.h does w/ _KERNEL */ +#include +#define _KERNEL 1 +#include /* for struct file */ +#include /* for rlimit32 in 64-bit mode */ +#undef _KERNEL + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_util.h" +#include "sigar_os.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* for proc_port */ +#include +#include +#include +#include + +/* for net_connection_list */ +#include +#include +#include +#include + +/* for odm api */ +#include +#include +#include + +#include + +/* for net_interface_config ipv6 */ +#include +#include + +/* for getkerninfo */ +#include + +/* not defined in aix 4.3 */ +#ifndef SBITS +#define SBITS 16 +#endif + +#ifndef PTHRDSINFO_RUSAGE_START +#define PTHRDSINFO_RUSAGE_START 0x00000001 +#define PTHRDSINFO_RUSAGE_STOP 0x00000002 +#define PTHRDSINFO_RUSAGE_COLLECT 0x00000004 +#endif + +/* + * from libperfstat.h: + * "To calculate the load average, divide the numbers by (1<." + */ +#define FIXED_TO_DOUBLE(x) (((double)x) / (1<koffsets[i] = klist[i].n_value; + } + + return SIGAR_OK; +} + +static int kread(sigar_t *sigar, void *data, int size, long offset) +{ + if (sigar->kmem < 0) { + return SIGAR_EPERM_KMEM; + } + + if (lseek(sigar->kmem, offset, SEEK_SET) != offset) { + return errno; + } + + if (read(sigar->kmem, data, size) != size) { + return errno; + } + + return SIGAR_OK; +} + +static int sigar_thread_rusage(struct rusage *usage, int mode) +{ + return pthread_getrusage_np(pthread_self(), usage, mode); +} + +static int sigar_perfstat_memory(perfstat_memory_total_t *memory) +{ + return perfstat_memory_total(NULL, memory, sizeof(*memory), 1); +} + +static int sigar_perfstat_cpu(perfstat_cpu_total_t *cpu_total) +{ + return perfstat_cpu_total(NULL, cpu_total, sizeof(*cpu_total), 1); +} + +int sigar_os_open(sigar_t **sigar) +{ + int status, i; + int kmem = -1; + struct utsname name; + + kmem = open("/dev/kmem", O_RDONLY); + + *sigar = malloc(sizeof(**sigar)); + + (*sigar)->getprocfd = NULL; /*XXX*/ + (*sigar)->kmem = kmem; + (*sigar)->pagesize = 0; + (*sigar)->ticks = sysconf(_SC_CLK_TCK); + (*sigar)->boot_time = 0; + (*sigar)->last_pid = -1; + (*sigar)->pinfo = NULL; + (*sigar)->cpuinfo = NULL; + (*sigar)->cpuinfo_size = 0; + SIGAR_ZERO(&(*sigar)->swaps); + + i = getpagesize(); + while ((i >>= 1) > 0) { + (*sigar)->pagesize++; + } + + if (kmem > 0) { + if ((status = get_koffsets(*sigar)) != SIGAR_OK) { + /* libperfstat only mode (aix 6) */ + close((*sigar)->kmem); + (*sigar)->kmem = -1; + } + } + + (*sigar)->cpu_mhz = -1; + + (*sigar)->model[0] = '\0'; + + uname(&name); + + (*sigar)->aix_version = atoi(name.version); + + (*sigar)->thrusage = PTHRDSINFO_RUSAGE_STOP; + + (*sigar)->diskmap = NULL; + + return SIGAR_OK; +} + +static void swaps_free(swaps_t *swaps); + +int sigar_os_close(sigar_t *sigar) +{ + swaps_free(&sigar->swaps); + if (sigar->kmem > 0) { + close(sigar->kmem); + } + if (sigar->pinfo) { + free(sigar->pinfo); + } + if (sigar->cpuinfo) { + free(sigar->cpuinfo); + } + if (sigar->diskmap) { + sigar_cache_destroy(sigar->diskmap); + } + if (sigar->thrusage == PTHRDSINFO_RUSAGE_START) { + struct rusage usage; + sigar_thread_rusage(&usage, + PTHRDSINFO_RUSAGE_STOP); + } + free(sigar); + return SIGAR_OK; +} + +char *sigar_os_error_string(sigar_t *sigar, int err) +{ + switch (err) { + case SIGAR_EPERM_KMEM: + return "Failed to open /dev/kmem for reading"; + default: + return NULL; + } +} + +#define PAGESHIFT(v) \ + ((v) << sigar->pagesize) + +int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem) +{ + int status; + perfstat_memory_total_t minfo; + sigar_uint64_t kern; + + if (sigar_perfstat_memory(&minfo) == 1) { + mem->total = PAGESHIFT(minfo.real_total); + mem->free = PAGESHIFT(minfo.real_free); + kern = PAGESHIFT(minfo.numperm); /* number of pages in file cache */ + } + else { + return errno; + } + + mem->used = mem->total - mem->free; + mem->actual_used = mem->used - kern; + mem->actual_free = mem->free + kern; + + sigar_mem_calc_ram(sigar, mem); + + return SIGAR_OK; +} + +static void swaps_free(swaps_t *swaps) +{ + if (swaps->num) { + int i; + + for (i=0; inum; i++) { + free(swaps->devs[i]); + } + + free(swaps->devs); + + swaps->num = 0; + } +} + +/* + * there is no public api for parsing this file. + * well, there is something, but its super ugly and requires + * linking 2 static libraries (libodm and something else) + * maybe will switch to that if it can add value elsewhere too. + */ +#define SWAPSPACES "/etc/swapspaces" + +static int swaps_get(swaps_t *swaps) +{ + FILE *fp; + char buf[512]; + char *ptr; + struct stat statbuf; + + if (stat(SWAPSPACES, &statbuf) < 0) { + return errno; + } + + /* only re-parse if file has changed */ + if (swaps->mtime == statbuf.st_mtime) { + return 0; + } + + swaps->mtime = statbuf.st_mtime; + + /* easier to just start from scratch */ + swaps_free(swaps); + + if (!(fp = fopen(SWAPSPACES, "r"))) { + return errno; + } + + while ((ptr = fgets(buf, sizeof(buf), fp))) { + if (!isalpha(*ptr)) { + continue; + } + + if (strchr(ptr, ':')) { + int len; + + ptr = fgets(buf, sizeof(buf), fp); + + while (isspace(*ptr)) { + ++ptr; + } + + if (strncmp(ptr, "dev", 3)) { + continue; + } + ptr += 3; + while (isspace(*ptr) || (*ptr == '=')) { + ++ptr; + } + + len = strlen(ptr); + ptr[len-1] = '\0'; /* -1 == chomp \n */ + + swaps->devs = realloc(swaps->devs, swaps->num+1 * sizeof(char *)); + swaps->devs[swaps->num] = malloc(len); + memcpy(swaps->devs[swaps->num], ptr, len); + + swaps->num++; + } + } + + fclose(fp); + + return 0; +} + +/* + * documented in aix tech ref, + * but this prototype is not in any friggin header file. + * struct pginfo is in sys/vminfo.h + */ + +int swapqry(char *path, struct pginfo *info); + +static int sigar_swap_get_swapqry(sigar_t *sigar, sigar_swap_t *swap) +{ + int status, i; + + if ((status = swaps_get(&sigar->swaps)) != SIGAR_OK) { + return status; + } + + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[swap] pagesize=%d, shift=%d", + getpagesize(), sigar->pagesize); + } + + swap->total = swap->free = 0; + + for (i=0; iswaps.num; i++) { + struct pginfo info; + + status = swapqry(sigar->swaps.devs[i], &info); + + if (status != 0) { + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[swap] swapqry(%s) failed: %s", + sigar->swaps.devs[i], + sigar_strerror(sigar, errno)); + } + continue; + } + + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[swap] %s total=%d/%d, free=%d/%d", + sigar->swaps.devs[i], + info.size, PAGESHIFT(info.size), + info.free, PAGESHIFT(info.free)); + } + + swap->total += PAGESHIFT(info.size); /* lsps -a */ + swap->free += PAGESHIFT(info.free); + } + + swap->used = swap->total - swap->free; + + return SIGAR_OK; +} + +#define SWAP_DEV(ps) \ + ((ps.type == LV_PAGING) ? \ + ps.u.lv_paging.vgname : \ + ps.u.nfs_paging.filename) + +#define SWAP_MB_TO_BYTES(v) ((v) * (1024 * 1024)) + +int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap) +{ + perfstat_memory_total_t minfo; + perfstat_pagingspace_t ps; + perfstat_id_t id; + + id.name[0] = '\0'; + + SIGAR_ZERO(swap); + + do { + if (perfstat_pagingspace(&id, &ps, sizeof(ps), 1) != 1) { + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[swap] dev=%s query failed: %s", + SWAP_DEV(ps), + sigar_strerror(sigar, errno)); + } + continue; + } + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[swap] dev=%s: active=%s, " + "total=%lluMb, used=%lluMb", + SWAP_DEV(ps), + ((ps.active == 1) ? "yes" : "no"), + ps.mb_size, ps.mb_used); + } + if (ps.active != 1) { + continue; + } + /* convert MB sizes to bytes */ + swap->total += SWAP_MB_TO_BYTES(ps.mb_size); + swap->used += SWAP_MB_TO_BYTES(ps.mb_used); + } while (id.name[0] != '\0'); + + swap->free = swap->total - swap->used; + + if (sigar_perfstat_memory(&minfo) == 1) { + swap->page_in = minfo.pgins; + swap->page_out = minfo.pgouts; + } + else { + swap->page_in = swap->page_out = -1; + } + return SIGAR_OK; +} + +int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu) +{ + int i, status; + struct sysinfo data; + perfstat_cpu_total_t cpu_data; + + if (sigar_perfstat_cpu(&cpu_data) == 1) { + cpu->user = SIGAR_TICK2MSEC(cpu_data.user); + cpu->nice = SIGAR_FIELD_NOTIMPL; /* N/A */ + cpu->sys = SIGAR_TICK2MSEC(cpu_data.sys); + cpu->idle = SIGAR_TICK2MSEC(cpu_data.idle); + cpu->wait = SIGAR_TICK2MSEC(cpu_data.wait); + cpu->irq = 0; /*N/A*/ + cpu->soft_irq = 0; /*N/A*/ + cpu->stolen = 0; /*N/A*/ + cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait; + return SIGAR_OK; + } + else { + return errno; + } +} + +/* + * other possible metrics we could add: + * struct cpuinfo { + * long cpu[CPU_NTIMES]; + * long pswitch; + * long syscall; + * long sysread; + * long syswrite; + * long sysfork; + * long sysexec; + * long readch; + * long writech; + * long iget; + * long namei; + * long dirblk; + * long msg; + * long sema; + * long bread; + * long bwrite; + * long lread; + * long lwrite; + * long phread; + * long phwrite; + * }; + */ + +int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist) +{ + perfstat_cpu_t data; + int i, ncpu = _system_configuration.ncpus; /* this can change */ + perfstat_id_t id; + + id.name[0] = '\0'; + + sigar_cpu_list_create(cpulist); + + for (i=0; idata[cpulist->number++]; + + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "cpu%d perfstat_id='%s'", + i, id.name); + } + + if (perfstat_cpu(&id, &data, sizeof(data), 1) == 1) { + cpu->user = SIGAR_TICK2MSEC(data.user); + cpu->nice = SIGAR_FIELD_NOTIMPL; /* N/A */ + cpu->sys = SIGAR_TICK2MSEC(data.sys); + cpu->idle = SIGAR_TICK2MSEC(data.idle); + cpu->wait = SIGAR_TICK2MSEC(data.wait); + cpu->irq = 0; /*N/A*/ + cpu->soft_irq = 0; /*N/A*/ + cpu->stolen = 0; /*N/A*/ + cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait; + } + else { + sigar_log_printf(sigar, SIGAR_LOG_ERROR, + "cpu%d perfstat_cpu(%s) failed: %s", + i, id.name, sigar_strerror(sigar, errno)); + SIGAR_ZERO(cpu); + } + } + + return SIGAR_OK; +} + +static int boot_time(sigar_t *sigar, time_t *time) +{ + int fd; + struct utmp data; + + if ((fd = open(UTMP_FILE, O_RDONLY)) < 0) { + return errno; + } + + do { + if (read(fd, &data, sizeof(data)) != sizeof(data)) { + int status = errno; + close(fd); + return status; + } + } while (data.ut_type != BOOT_TIME); + + *time = data.ut_time; + + close(fd); + + return SIGAR_OK; +} + +int sigar_uptime_get(sigar_t *sigar, + sigar_uptime_t *uptime) +{ + if (sigar->boot_time == 0) { + int status; + time_t time; + + if ((status = boot_time(sigar, &time)) != SIGAR_OK) { + return status; + } + + sigar->boot_time = time; + } + + uptime->uptime = time(NULL) - sigar->boot_time; + + return SIGAR_OK; +} + +#define WHOCPY(dest, src) \ + SIGAR_SSTRCPY(dest, src); \ + if (sizeof(src) < sizeof(dest)) \ + dest[sizeof(dest)-1] = '\0' + +static int sigar_who_utmp(sigar_t *sigar, + sigar_who_list_t *wholist) +{ + struct utmp ut; + FILE *fp; + + if (!(fp = fopen(UTMP_FILE, "r"))) { + return errno; + } + + while (fread(&ut, sizeof(ut), 1, fp) == 1) { + sigar_who_t *who; + + if (*ut.ut_name == '\0') { + continue; + } + + if (ut.ut_type != USER_PROCESS) { + continue; + } + + SIGAR_WHO_LIST_GROW(wholist); + who = &wholist->data[wholist->number++]; + + WHOCPY(who->user, ut.ut_user); + WHOCPY(who->device, ut.ut_line); + WHOCPY(who->host, ut.ut_host); + + who->time = ut.ut_time; + } + + fclose(fp); + + return SIGAR_OK; +} + +int sigar_who_list_get(sigar_t *sigar, + sigar_who_list_t *wholist) +{ + int status; + + sigar_who_list_create(wholist); + + status = sigar_who_utmp(sigar, wholist); + if (status != SIGAR_OK) { + sigar_who_list_destroy(sigar, wholist); + return status; + } + + return SIGAR_OK; +} + +int sigar_loadavg_get(sigar_t *sigar, + sigar_loadavg_t *loadavg) +{ + int status, i; + int data[3]; + perfstat_cpu_total_t cpu_data; + + if (sigar_perfstat_cpu(&cpu_data) == 1) { + for (i=0; i<3; i++) { + loadavg->loadavg[i] = FIXED_TO_DOUBLE(cpu_data.loadavg[i]); + } + return SIGAR_OK; + } + else { + return errno; + } +} + +int sigar_os_proc_list_get(sigar_t *sigar, + sigar_proc_list_t *proclist) +{ + pid_t pid = 0; + struct procsinfo info; + + for (;;) { + int num = getprocs(&info, sizeof(info), + NULL, 0, &pid, 1); + + if (num == 0) { + break; + } + + SIGAR_PROC_LIST_GROW(proclist); + + proclist->data[proclist->number++] = info.pi_pid; + } + + return SIGAR_OK; +} + +static int sigar_getprocs(sigar_t *sigar, sigar_pid_t pid) +{ + int status, num; + time_t timenow = time(NULL); + + if (sigar->pinfo == NULL) { + sigar->pinfo = malloc(sizeof(*sigar->pinfo)); + } + + if (sigar->last_pid == pid) { + if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) { + return SIGAR_OK; + } + } + + sigar->last_pid = pid; + sigar->last_getprocs = timenow; + + num = getprocs(sigar->pinfo, sizeof(*sigar->pinfo), + NULL, 0, &pid, 1); + + if (num != 1) { + return ESRCH; + } + + return SIGAR_OK; +} + +int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_mem_t *procmem) +{ + int status = sigar_getprocs(sigar, pid); + struct procsinfo64 *pinfo = sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + + procmem->size = PAGESHIFT(pinfo->pi_size); /* XXX fold in pi_dvm ? */ + procmem->share = PAGESHIFT(pinfo->pi_sdsize); + procmem->resident = PAGESHIFT(pinfo->pi_drss + pinfo->pi_trss); + + procmem->minor_faults = pinfo->pi_minflt; + procmem->major_faults = pinfo->pi_majflt; + procmem->page_faults = + procmem->minor_faults + + procmem->major_faults; + + return SIGAR_OK; +} + +int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_cred_t *proccred) +{ + int status = sigar_getprocs(sigar, pid); + struct procsinfo64 *pinfo = sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + + proccred->uid = pinfo->pi_cred.cr_ruid; + proccred->euid = pinfo->pi_cred.cr_uid; + if (proccred->uid == -1) { + /* + * aix 5.2 has a process named 'jfsz' + * where uid is '-1', getpwuid returns EPERM + */ + proccred->uid = proccred->euid = 0; + } + proccred->gid = pinfo->pi_cred.cr_rgid; + proccred->egid = pinfo->pi_cred.cr_gid; + + return SIGAR_OK; +} + +int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_time_t *proctime) +{ + int status = sigar_getprocs(sigar, pid); + struct procsinfo64 *pinfo = sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + + proctime->start_time = pinfo->pi_start; + proctime->start_time *= SIGAR_MSEC; /* convert to ms */ + proctime->user = pinfo->pi_utime * SIGAR_MSEC; + proctime->sys = pinfo->pi_stime * SIGAR_MSEC; + proctime->total = proctime->user + proctime->sys; + + return SIGAR_OK; +} + +int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_state_t *procstate) +{ + int status = sigar_getprocs(sigar, pid); + struct procsinfo64 *pinfo = sigar->pinfo; + tid_t tid = 0; + struct thrdsinfo64 thrinfo; + + if (status != SIGAR_OK) { + return status; + } + + if (getthrds(pid, &thrinfo, sizeof(thrinfo), &tid, 1) == 1) { + procstate->processor = thrinfo.ti_affinity; + } + else { + procstate->processor = SIGAR_FIELD_NOTIMPL; + } + + SIGAR_SSTRCPY(procstate->name, pinfo->pi_comm); + procstate->ppid = pinfo->pi_ppid; + procstate->nice = pinfo->pi_nice; + procstate->tty = pinfo->pi_ttyd; + procstate->priority = pinfo->pi_pri; + procstate->threads = pinfo->pi_thcount; + + switch (pinfo->pi_state) { + case SACTIVE: + procstate->state = 'R'; + break; + case SIDL: + procstate->state = 'D'; + break; + case SSTOP: + procstate->state = 'S'; + break; + case SZOMB: + procstate->state = 'Z'; + break; + case SSWAP: + procstate->state = 'S'; + break; + } + + return SIGAR_OK; +} + +int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs) +{ + /* XXX if buffer is not large enough args are truncated */ + char buffer[8192], *ptr; + struct procsinfo pinfo; + + pinfo.pi_pid = pid; + + if (getargs(&pinfo, sizeof(pinfo), + buffer, sizeof(buffer)) != 0) + { + return errno; + } + + ptr = buffer; + + while (*ptr) { + int alen = strlen(ptr)+1; + char *arg = malloc(alen); + + SIGAR_PROC_ARGS_GROW(procargs); + memcpy(arg, ptr, alen); + + procargs->data[procargs->number++] = arg; + + ptr += alen; + } + + return SIGAR_OK; +} + +int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_env_t *procenv) +{ + /* XXX if buffer is not large enough args are truncated */ + char buffer[8192], *ptr; + struct procsinfo pinfo; + + pinfo.pi_pid = pid; + + if (getevars(&pinfo, sizeof(pinfo), + buffer, sizeof(buffer)) != 0) + { + return errno; + } + + ptr = buffer; + + while (*ptr) { + char *val = strchr(ptr, '='); + int klen, vlen, status; + char key[128]; /* XXX is there a max key size? */ + + if (val == NULL) { + /* not key=val format */ + procenv->env_getter(procenv->data, ptr, strlen(ptr), NULL, 0); + break; + } + + klen = val - ptr; + SIGAR_SSTRCPY(key, ptr); + key[klen] = '\0'; + ++val; + + vlen = strlen(val); + status = procenv->env_getter(procenv->data, + key, klen, val, vlen); + + if (status != SIGAR_OK) { + /* not an error; just stop iterating */ + break; + } + + ptr += (klen + 1 + vlen + 1); + } + + return SIGAR_OK; +} + +int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_fd_t *procfd) +{ +#ifdef SIGAR_64BIT + /* XXX no getuser() in 64-bit mode */ + return SIGAR_ENOTIMPL; +#else + int i; + struct procsinfo pinfo; + struct user uinfo; + + procfd->total = 0; + pinfo.pi_pid = pid; + + if (getuser(&pinfo, sizeof(pinfo), + &uinfo, sizeof(uinfo)) != 0) { + if (errno == EINVAL) { + return SIGAR_ENOTIMPL; /*XXX 5.2+*/ + } + } + + /* see sys/user.h */ + for (i=0; itotal++; + } + } + + return SIGAR_OK; +#endif +} + +int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_exe_t *procexe) +{ + int len; + char buffer[8192]; + struct procsinfo pinfo; + + pinfo.pi_pid = pid; + + if (getargs(&pinfo, sizeof(pinfo), + buffer, sizeof(buffer)) != 0) + { + return errno; + } + /* XXX argv[0] might be relative */ + len = strlen(buffer); + SIGAR_SSTRCPY(procexe->name, buffer); + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/cwd"); + + if ((len = readlink(buffer, procexe->cwd, + sizeof(procexe->cwd)-1)) < 0) + { + return errno; + } + procexe->cwd[len] = '\0'; + + procexe->root[0] = '\0'; + + return SIGAR_OK; +} + +static int sigar_proc_modules_local_get(sigar_t *sigar, + sigar_proc_modules_t *procmods) +{ + struct ld_info *info; + char *buffer; + int size = 2048, status; + unsigned int offset; + + buffer = malloc(size); + while ((loadquery(L_GETINFO, buffer, size) == -1) && + (errno == ENOMEM)) + { + size += 2048; + buffer = realloc(buffer, size); + } + + info = (struct ld_info *)buffer; + + do { + char *name = info->ldinfo_filename; + + status = + procmods->module_getter(procmods->data, name, strlen(name)); + + if (status != SIGAR_OK) { + /* not an error; just stop iterating */ + free(buffer); + return status; + } + + offset = info->ldinfo_next; + info = (struct ld_info *)((char*)info + offset); + } while(offset); + + free(buffer); + + return SIGAR_OK; +} + +int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_modules_t *procmods) +{ + if (pid == sigar_pid_get(sigar)) { + return sigar_proc_modules_local_get(sigar, procmods); + } + else { + return SIGAR_ENOTIMPL; + } +} + +#define SIGAR_MICROSEC2NANO(s) \ + ((sigar_uint64_t)(s) * (sigar_uint64_t)1000) + +#define TIME_NSEC(t) \ + (SIGAR_SEC2NANO((t).tv_sec) + SIGAR_MICROSEC2NANO((t).tv_usec)) + +int sigar_thread_cpu_get(sigar_t *sigar, + sigar_uint64_t id, + sigar_thread_cpu_t *cpu) +{ + struct rusage usage; + int retval; + + if (sigar->thrusage != PTHRDSINFO_RUSAGE_START) { + sigar->thrusage = PTHRDSINFO_RUSAGE_START; + retval = + sigar_thread_rusage(&usage, + PTHRDSINFO_RUSAGE_START); + if (retval != 0) { + return retval; + } + } + + retval = + sigar_thread_rusage(&usage, + PTHRDSINFO_RUSAGE_COLLECT); + if (retval != 0) { + return retval; + } + + cpu->user = TIME_NSEC(usage.ru_utime); + cpu->sys = TIME_NSEC(usage.ru_stime); + cpu->total = TIME_NSEC(usage.ru_utime) + TIME_NSEC(usage.ru_stime); + + return SIGAR_OK; +} + +int sigar_os_fs_type_get(sigar_file_system_t *fsp) +{ + return fsp->type; +} + +#ifndef MNT_NFS4 +/* another one documented in aix tech ref + * with no friggin prototype in any header file... + * ...but added in 5.2 + */ +int mntctl(int command, int size, char *buffer); +#endif + +int sigar_file_system_list_get(sigar_t *sigar, + sigar_file_system_list_t *fslist) +{ + int i, size, num; + char *buf, *mntlist; + + /* get required size */ + if (mntctl(MCTL_QUERY, sizeof(size), (char *)&size) < 0) { + return errno; + } + + mntlist = buf = malloc(size); + + if ((num = mntctl(MCTL_QUERY, size, buf)) < 0) { + free(buf); + return errno; + } + + sigar_file_system_list_create(fslist); + + for (i=0; ivmt_length; + + SIGAR_FILE_SYSTEM_LIST_GROW(fslist); + + fsp = &fslist->data[fslist->number++]; + + switch (ent->vmt_gfstype) { + case MNT_AIX: + typename = "aix"; + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + break; + case MNT_JFS: + typename = "jfs"; + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + break; + case MNT_NFS: + case MNT_NFS3: + typename = "nfs"; + fsp->type = SIGAR_FSTYPE_NETWORK; + break; + case MNT_CDROM: + fsp->type = SIGAR_FSTYPE_CDROM; + break; + case MNT_SFS: + case MNT_CACHEFS: + case MNT_AUTOFS: + default: + if (ent->vmt_flags & MNT_REMOTE) { + fsp->type = SIGAR_FSTYPE_NETWORK; + } + else { + fsp->type = SIGAR_FSTYPE_NONE; + } + } + + SIGAR_SSTRCPY(fsp->dir_name, vmt2dataptr(ent, VMT_STUB)); + SIGAR_SSTRCPY(fsp->options, vmt2dataptr(ent, VMT_ARGS)); + + devname = vmt2dataptr(ent, VMT_OBJECT); + + if (fsp->type == SIGAR_FSTYPE_NETWORK) { + char *hostname = vmt2dataptr(ent, VMT_HOSTNAME); +#if 0 + /* XXX: these do not seem reliable */ + int hostname_len = vmt2datasize(ent, VMT_HOSTNAME)-1; /* -1 == skip '\0' */ + int devname_len = vmt2datasize(ent, VMT_OBJECT); /* includes '\0' */ +#else + int hostname_len = strlen(hostname); + int devname_len = strlen(devname) + 1; +#endif + int total_len = hostname_len + devname_len + 1; /* 1 == strlen(":") */ + + if (total_len > sizeof(fsp->dev_name)) { + /* justincase - prevent overflow. chances: slim..none */ + SIGAR_SSTRCPY(fsp->dev_name, devname); + } + else { + /* sprintf(fsp->devname, "%s:%s", hostname, devname) */ + char *ptr = fsp->dev_name; + + memcpy(ptr, hostname, hostname_len); + ptr += hostname_len; + + *ptr++ = ':'; + + memcpy(ptr, devname, devname_len); + } + } + else { + SIGAR_SSTRCPY(fsp->dev_name, devname); + } + + /* we set fsp->type, just looking up sigar.c:fstype_names[type] */ + sigar_fs_type_get(fsp); + + if (typename == NULL) { + typename = fsp->type_name; + } + + SIGAR_SSTRCPY(fsp->sys_type_name, typename); + } + + free(buf); + + return SIGAR_OK; +} + +typedef struct { + char name[IDENTIFIER_LENGTH]; + long addr; +} aix_diskio_t; + +static int create_diskmap(sigar_t *sigar) +{ + int i, total, num; + perfstat_disk_t *disk; + perfstat_id_t id; + + total = perfstat_disk(NULL, NULL, sizeof(*disk), 0); + if (total < 1) { + return ENOENT; + } + + disk = malloc(total * sizeof(*disk)); + id.name[0] = '\0'; + + num = perfstat_disk(&id, disk, sizeof(*disk), total); + if (num < 1) { + free(disk); + return ENOENT; + } + + sigar->diskmap = sigar_cache_new(25); + + odm_initialize(); + + for (i=0; iname, "label", 0, &num))) { + retval = stat(attr->value, &sb); + + if (retval == 0) { + aix_diskio_t *diskio = malloc(sizeof(*diskio)); + SIGAR_SSTRCPY(diskio->name, disk[i].name); + diskio->addr = -1; + ent = sigar_cache_get(sigar->diskmap, SIGAR_FSDEV_ID(sb)); + ent->value = diskio; + } + + free(attr); + } + } + + odm_free_list(dv, &info); + } + + free(disk); + odm_terminate(); + + return SIGAR_OK; +} + +int sigar_disk_usage_get(sigar_t *sigar, const char *name, + sigar_disk_usage_t *usage) +{ + perfstat_disk_t disk; + perfstat_id_t id; + + SIGAR_SSTRCPY(id.name, name); + + if (perfstat_disk(&id, &disk, sizeof(disk), 1) != 1) { + return ENXIO; + } + + usage->reads = disk.rblks; + usage->writes = disk.wblks; + usage->read_bytes = disk.rblks * disk.bsize; + usage->write_bytes = disk.wblks * disk.bsize; + usage->queue = disk.qdepth; + usage->time = disk.time; + usage->rtime = SIGAR_FIELD_NOTIMPL; + usage->wtime = SIGAR_FIELD_NOTIMPL; + + return SIGAR_OK; +} + +int sigar_file_system_usage_get(sigar_t *sigar, + const char *dirname, + sigar_file_system_usage_t *fsusage) +{ + sigar_cache_entry_t *ent; + struct stat sb; + int status; + + status = sigar_statvfs(sigar, dirname, fsusage); + + if (status != SIGAR_OK) { + return status; + } + + fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage); + + SIGAR_DISK_STATS_INIT(&fsusage->disk); + + if (!sigar->diskmap) { + status = create_diskmap(sigar); + if (status != SIGAR_OK) { + return SIGAR_OK; + } + } + + status = stat(dirname, &sb); + if (status == 0) { + sigar_cache_entry_t *ent = + sigar_cache_get(sigar->diskmap, SIGAR_FSDEV_ID(sb)); + if (!ent->value) { + return SIGAR_OK; + } + sigar_disk_usage_get(sigar, ((aix_diskio_t *)ent->value)->name, &fsusage->disk); + } + + return SIGAR_OK; +} + +/* from sys/systemcfg.h, not defined in 4.3 headers */ +#ifndef POWER_4 +#define POWER_4 0x0800 +#endif +#ifndef POWER_MPC7450 +#define POWER_MPC7450 0x1000 +#endif +#ifndef POWER_5 +#define POWER_5 0x2000 +#endif + +static char *sigar_get_odm_model(sigar_t *sigar) +{ + if (sigar->model[0] == '\0') { + struct CuAt *odm_obj; + int num; + + odm_initialize(); + + if ((odm_obj = getattr("proc0", "type", 0, &num))) { + SIGAR_SSTRCPY(sigar->model, odm_obj->value); + free(odm_obj); + } + + odm_terminate(); + } + + return sigar->model; +} + +#define SIGAR_CPU_CACHE_SIZE \ + (_system_configuration.L2_cache_size / 1024) + +static int sigar_get_cpu_mhz(sigar_t *sigar) +{ + if (sigar->cpu_mhz == SIGAR_FIELD_NOTIMPL) { + perfstat_cpu_total_t data; + + if (sigar_perfstat_cpu(&data) == 1) { + sigar->cpu_mhz = data.processorHZ / 1000000; + } + else { + sigar_log_printf(sigar, SIGAR_LOG_ERROR, + "perfstat_cpu_total failed: %s", + sigar_strerror(sigar, errno)); + } + } + + return sigar->cpu_mhz; +} + +static char *get_cpu_arch(void) +{ + switch (_system_configuration.architecture) { + case POWER_RS: + return "Power Classic"; + case POWER_PC: + return "PowerPC"; + case IA64: + return "IA64"; + default: + return "PowerPC"; /* what else could it be */ + } +} + +static char *get_ppc_cpu_model(void) +{ + switch (_system_configuration.implementation) { + case POWER_RS1: + return "RS1"; + case POWER_RSC: + return "RSC"; + case POWER_RS2: + return "RS2"; + case POWER_601: + return "601"; + case POWER_603: + return "603"; + case POWER_604: + return "604"; + case POWER_620: + return "620"; + case POWER_630: + return "630"; + case POWER_A35: + return "A35"; + case POWER_RS64II: + return "RS64-II"; + case POWER_RS64III: + return "RS64-III"; + case POWER_4: + return "POWER4"; + case POWER_MPC7450: + return "MPC7450"; + case POWER_5: + return "POWER5"; + default: + return "Unknown"; + } +} + +static char *get_ia64_cpu_model(void) +{ + switch (_system_configuration.implementation) { + case IA64_M1: + return "M1"; + case IA64_M2: + return "M2"; + default: + return "Unknown"; + } +} + +static char *get_cpu_model(void) +{ + if (_system_configuration.architecture == IA64) { + return get_ia64_cpu_model(); + } + else { + return get_ppc_cpu_model(); + } +} + +int sigar_cpu_info_list_get(sigar_t *sigar, + sigar_cpu_info_list_t *cpu_infos) +{ + int i; + int ncpu = _system_configuration.ncpus; /* this can change */ + char *arch = get_cpu_arch(), *model = get_cpu_model(); + + /*XXX should only do this once*/ + sigar_cpu_info_list_create(cpu_infos); + + for (i=0; idata[cpu_infos->number++]; + + info->total_cores = ncpu; + info->cores_per_socket = 1; /*XXX*/ + info->total_sockets = ncpu; /*XXX*/ + + info->cache_size = SIGAR_CPU_CACHE_SIZE; + + info->mhz = sigar_get_cpu_mhz(sigar); + + if (*arch == 'P') { + SIGAR_SSTRCPY(info->vendor, "IBM"); + } + else if (*arch == 'I') { + SIGAR_SSTRCPY(info->vendor, "Intel"); + } + else { + SIGAR_SSTRCPY(info->vendor, "Unknown"); + } + + snprintf(info->model, sizeof(info->model), + "%s %s", arch, model); + } + + return SIGAR_OK; +} +/* XXX net_route_list copy-n-pasted from darwin_sigar.c; only diff is getkerninfo instead of sysctl */ +#define rt_s_addr(sa) ((struct sockaddr_in *)(sa))->sin_addr.s_addr + +#ifndef SA_SIZE +#define SA_SIZE(sa) \ + ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ + sizeof(long) : \ + 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) +#endif + +int sigar_net_route_list_get(sigar_t *sigar, + sigar_net_route_list_t *routelist) +{ + int needed; + int bit; + char *buf, *next, *lim; + struct rt_msghdr *rtm; + + needed = getkerninfo(KINFO_RT_DUMP, NULL, NULL, 0); + if (needed <= 0) { + return errno; + } + + buf = malloc(needed); + + if (getkerninfo(KINFO_RT_DUMP, buf, &needed, 0) < 0) { + return errno; + } + + sigar_net_route_list_create(routelist); + + lim = buf + needed; + + for (next = buf; next < lim; next += rtm->rtm_msglen) { + struct sockaddr *sa; + sigar_net_route_t *route; + rtm = (struct rt_msghdr *)next; + + if (rtm->rtm_type != RTM_GET) { + continue; + } + + sa = (struct sockaddr *)(rtm + 1); + + if (sa->sa_family != AF_INET) { + continue; + } + + SIGAR_NET_ROUTE_LIST_GROW(routelist); + route = &routelist->data[routelist->number++]; + SIGAR_ZERO(route); + + route->flags = rtm->rtm_flags; + if_indextoname(rtm->rtm_index, route->ifname); + + for (bit=RTA_DST; + bit && ((char *)sa < lim); + bit <<= 1) + { + if ((rtm->rtm_addrs & bit) == 0) { + continue; + } + switch (bit) { + case RTA_DST: + sigar_net_address_set(route->destination, + rt_s_addr(sa)); + break; + case RTA_GATEWAY: + if (sa->sa_family == AF_INET) { + sigar_net_address_set(route->gateway, + rt_s_addr(sa)); + } + break; + case RTA_NETMASK: + sigar_net_address_set(route->mask, + rt_s_addr(sa)); + break; + case RTA_IFA: + break; + } + + sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa)); + } + } + + free(buf); + + return SIGAR_OK; +} + +int sigar_net_interface_stat_get(sigar_t *sigar, + const char *name, + sigar_net_interface_stat_t *ifstat) +{ + perfstat_id_t id; + perfstat_netinterface_t data; + + sigar_log(sigar, SIGAR_LOG_DEBUG, "[ifstat] using libperfstat"); + + SIGAR_SSTRCPY(id.name, name); + + if (perfstat_netinterface(&id, &data, sizeof(data), 1) == 1) { + ifstat->rx_bytes = data.ibytes; + ifstat->rx_packets = data.ipackets; + ifstat->rx_errors = data.ierrors; + ifstat->rx_dropped = SIGAR_FIELD_NOTIMPL; + ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL; + ifstat->rx_frame = SIGAR_FIELD_NOTIMPL; + + ifstat->tx_bytes = data.obytes; + ifstat->tx_packets = data.opackets; + ifstat->tx_errors = data.oerrors; + ifstat->tx_dropped = SIGAR_FIELD_NOTIMPL; + ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL; + ifstat->tx_collisions = data.collisions; + ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL; + + ifstat->speed = data.bitrate; + + return SIGAR_OK; + } + else { + return errno; + } +} + +int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig) +{ + int sock; + struct in6_ifreq ifr; + + if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + return errno; + } + + SIGAR_SSTRCPY(ifr.ifr_name, name); + + if (ioctl(sock, SIOCGIFADDR6, &ifr) == 0) { + struct in6_addr *addr = SIGAR_SIN6_ADDR(&ifr.ifr_Addr); + + sigar_net_address6_set(ifconfig->address6, addr); + sigar_net_interface_scope6_set(ifconfig, addr); + + if (ioctl(sock, SIOCGIFNETMASK6, &ifr) == 0) { + addr = SIGAR_SIN6_ADDR(&ifr.ifr_Addr); + ifconfig->prefix6_length = SIGAR_SIN6(&ifr.ifr_Addr)->sin6_len; /*XXX*/ + } + } + + close(sock); + return SIGAR_OK; +} + +#define IS_TCP_SERVER(state, flags) \ + ((flags & SIGAR_NETCONN_SERVER) && (state == TCPS_LISTEN)) + +#define IS_TCP_CLIENT(state, flags) \ + ((flags & SIGAR_NETCONN_CLIENT) && (state != TCPS_LISTEN)) + +static int net_conn_get_tcp(sigar_net_connection_walker_t *walker) +{ + sigar_t *sigar = walker->sigar; + int flags = walker->flags; + int status; + struct inpcb tcp_inpcb; + struct tcpcb tcpcb; + struct inpcb *entry; + + status = kread(sigar, &tcp_inpcb, sizeof(tcp_inpcb), + sigar->koffsets[KOFFSET_TCB]); + + if (status != SIGAR_OK) { + return status; + } + + entry = tcp_inpcb.inp_next; + while (entry) { + struct inpcb pcb; + int state; + + status = kread(sigar, &pcb, sizeof(pcb), (long)entry); + if (status != SIGAR_OK) { + return status; + } + status = kread(sigar, &tcpcb, sizeof(tcpcb), (long)pcb.inp_ppcb); + if (status != SIGAR_OK) { + return status; + } + + state = tcpcb.t_state; + if ((IS_TCP_SERVER(state, flags) || + IS_TCP_CLIENT(state, flags))) + { + sigar_net_connection_t conn; + + SIGAR_ZERO(&conn); + + conn.type = SIGAR_NETCONN_TCP; + + sigar_net_address_set(conn.local_address, + pcb.inp_laddr.s_addr); + + sigar_net_address_set(conn.remote_address, + pcb.inp_faddr.s_addr); + + conn.local_port = ntohs(pcb.inp_lport); + conn.remote_port = ntohs(pcb.inp_fport); + + conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL; + + switch (state) { + case TCPS_CLOSED: + conn.state = SIGAR_TCP_CLOSE; + break; + case TCPS_LISTEN: + conn.state = SIGAR_TCP_LISTEN; + break; + case TCPS_SYN_SENT: + conn.state = SIGAR_TCP_SYN_SENT; + break; + case TCPS_SYN_RECEIVED: + conn.state = SIGAR_TCP_SYN_RECV; + break; + case TCPS_ESTABLISHED: + conn.state = SIGAR_TCP_ESTABLISHED; + break; + case TCPS_CLOSE_WAIT: + conn.state = SIGAR_TCP_CLOSE_WAIT; + break; + case TCPS_FIN_WAIT_1: + conn.state = SIGAR_TCP_FIN_WAIT1; + break; + case TCPS_CLOSING: + conn.state = SIGAR_TCP_CLOSING; + break; + case TCPS_LAST_ACK: + conn.state = SIGAR_TCP_LAST_ACK; + break; + case TCPS_FIN_WAIT_2: + conn.state = SIGAR_TCP_FIN_WAIT2; + break; + case TCPS_TIME_WAIT: + conn.state = SIGAR_TCP_TIME_WAIT; + break; + default: + conn.state = SIGAR_TCP_UNKNOWN; + break; + } + + if (walker->add_connection(walker, &conn) != SIGAR_OK) { + break; + } + } + + entry = pcb.inp_next; + if (entry == tcp_inpcb.inp_next) { + break; + } + } + + return SIGAR_OK; +} + +int sigar_net_connection_walk(sigar_net_connection_walker_t *walker) +{ + int status; + + if (walker->flags & SIGAR_NETCONN_TCP) { + status = net_conn_get_tcp(walker); + + if (status != SIGAR_OK) { + return status; + } + } +#if 0 + if (walker->flags & SIGAR_NETCONN_UDP) { + status = net_conn_get_udp(walker); + + if (status != SIGAR_OK) { + return status; + } + } +#endif + return SIGAR_OK; +} + +SIGAR_DECLARE(int) +sigar_tcp_get(sigar_t *sigar, + sigar_tcp_t *tcp) +{ + perfstat_id_t id; + perfstat_protocol_t proto; + + SIGAR_SSTRCPY(id.name, "tcp"); + + if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { + return ENOENT; + } + + tcp->active_opens = proto.u.tcp.initiated; + tcp->passive_opens = proto.u.tcp.accepted; + tcp->attempt_fails = proto.u.tcp.dropped; + tcp->estab_resets = proto.u.tcp.dropped; + tcp->curr_estab = proto.u.tcp.established; + tcp->in_segs = proto.u.tcp.ipackets; + tcp->out_segs = proto.u.tcp.opackets; + tcp->retrans_segs = 0; + tcp->in_errs = proto.u.tcp.ierrors; + tcp->out_rsts = 0; +} + +#define NFS_V2_STAT_SET(type) \ + nfs->null = proto.u.nfsv2.type.null; \ + nfs->getattr = proto.u.nfsv2.type.getattr; \ + nfs->setattr = proto.u.nfsv2.type.setattr; \ + nfs->root = proto.u.nfsv2.type.root; \ + nfs->lookup = proto.u.nfsv2.type.lookup; \ + nfs->readlink = proto.u.nfsv2.type.readlink; \ + nfs->read = proto.u.nfsv2.type.read; \ + nfs->writecache = proto.u.nfsv2.type.writecache; \ + nfs->write = proto.u.nfsv2.type.write; \ + nfs->create = proto.u.nfsv2.type.create; \ + nfs->remove = proto.u.nfsv2.type.remove; \ + nfs->rename = proto.u.nfsv2.type.rename; \ + nfs->link = proto.u.nfsv2.type.link; \ + nfs->symlink = proto.u.nfsv2.type.symlink; \ + nfs->mkdir = proto.u.nfsv2.type.mkdir; \ + nfs->rmdir = proto.u.nfsv2.type.rmdir; \ + nfs->readdir = proto.u.nfsv2.type.readdir; \ + nfs->fsstat = proto.u.nfsv2.type.statfs + +int sigar_nfs_client_v2_get(sigar_t *sigar, + sigar_nfs_client_v2_t *nfs) +{ + perfstat_id_t id; + perfstat_protocol_t proto; + + SIGAR_SSTRCPY(id.name, "nfsv2"); + + if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { + return ENOENT; + } + + NFS_V2_STAT_SET(client); + + return SIGAR_OK; +} + +int sigar_nfs_server_v2_get(sigar_t *sigar, + sigar_nfs_server_v2_t *nfs) +{ + perfstat_id_t id; + perfstat_protocol_t proto; + + SIGAR_SSTRCPY(id.name, "nfsv2"); + + if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { + return ENOENT; + } + + NFS_V2_STAT_SET(server); + + return SIGAR_OK; +} + +#define NFS_V3_STAT_SET(type) \ + nfs->null = proto.u.nfsv3.type.null; \ + nfs->getattr = proto.u.nfsv3.type.getattr; \ + nfs->setattr = proto.u.nfsv3.type.setattr; \ + nfs->lookup = proto.u.nfsv3.type.lookup; \ + nfs->access = proto.u.nfsv3.type.access; \ + nfs->readlink = proto.u.nfsv3.type.readlink; \ + nfs->read = proto.u.nfsv3.type.read; \ + nfs->write = proto.u.nfsv3.type.write; \ + nfs->create = proto.u.nfsv3.type.create; \ + nfs->mkdir = proto.u.nfsv3.type.mkdir; \ + nfs->symlink = proto.u.nfsv3.type.symlink; \ + nfs->mknod = proto.u.nfsv3.type.mknod; \ + nfs->remove = proto.u.nfsv3.type.remove; \ + nfs->rmdir = proto.u.nfsv3.type.rmdir; \ + nfs->rename = proto.u.nfsv3.type.rename; \ + nfs->link = proto.u.nfsv3.type.link; \ + nfs->readdir = proto.u.nfsv3.type.readdir; \ + nfs->readdirplus = proto.u.nfsv3.type.readdirplus; \ + nfs->fsstat = proto.u.nfsv3.type.fsstat; \ + nfs->fsinfo = proto.u.nfsv3.type.fsinfo; \ + nfs->pathconf = proto.u.nfsv3.type.pathconf; \ + nfs->commit = proto.u.nfsv3.type.commit + +int sigar_nfs_client_v3_get(sigar_t *sigar, + sigar_nfs_client_v3_t *nfs) +{ + perfstat_id_t id; + perfstat_protocol_t proto; + + SIGAR_SSTRCPY(id.name, "nfsv3"); + + if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { + return ENOENT; + } + + NFS_V3_STAT_SET(client); + + return SIGAR_OK; +} + +int sigar_nfs_server_v3_get(sigar_t *sigar, + sigar_nfs_server_v3_t *nfs) +{ + perfstat_id_t id; + perfstat_protocol_t proto; + + SIGAR_SSTRCPY(id.name, "nfsv3"); + + if (perfstat_protocol(&id, &proto, sizeof(proto), 1) != 1) { + return ENOENT; + } + + NFS_V3_STAT_SET(server); + + return SIGAR_OK; +} + +#include +/* + * cannot find any related aix docs on reading the ARP table, + * this impl was gleaned from the above .h file and truss -f arp -an + */ +int sigar_arp_list_get(sigar_t *sigar, + sigar_arp_list_t *arplist) +{ + int status = SIGAR_OK; + long arptabsize; + int i, size, retval; + struct arptab *arptabp; + + size = sizeof(arptabsize); + retval = getkerninfo(KINFO_READ, &arptabsize, &size, + sigar->koffsets[KOFFSET_ARPTABSIZE]); + if (retval != sizeof(arptabsize)) { + return errno; + } + + size = sizeof(arptabp); + retval = getkerninfo(KINFO_READ, &arptabp, &size, + sigar->koffsets[KOFFSET_ARPTABP]); + if (retval != sizeof(arptabp)) { + return errno; + } + + sigar_arp_list_create(arplist); + status = SIGAR_OK; + + for (i=0; idata[arplist->number++]; + + sigar_net_address_set(arp->address, + ent.at_iaddr.s_addr); + + sigar_net_address_mac_set(arp->hwaddr, + ent.hwaddr, + sizeof(arp->hwaddr.addr.mac)); + + if_indextoname(ifp.if_index, arp->ifname); + + arp->flags = ent.at_flags; + SIGAR_SSTRCPY(arp->type, "ether"); /* XXX ifp.if_type */ + } + + if (status != SIGAR_OK) { + sigar_arp_list_destroy(sigar, arplist); + } + + return status; +} + +/* derived from pidentd's k_aix432.c */ +int sigar_proc_port_get(sigar_t *sigar, int protocol, + unsigned long port, sigar_pid_t *pidp) +{ + struct procsinfo pinfo; + struct fdsinfo finfo; + pid_t pid = 0; + int type; + + switch (protocol) { + case SIGAR_NETCONN_TCP: + type = IPPROTO_TCP; + break; + case SIGAR_NETCONN_UDP: + type = IPPROTO_UDP; + break; + default: + return SIGAR_ENOTIMPL; + } + + for (;;) { + int fd, status; + int num = getprocs(&pinfo, sizeof(pinfo), + &finfo, sizeof(finfo), + &pid, 1); + + if (num == 0) { + break; + } + + if ((pinfo.pi_state == 0) || (pinfo.pi_state == SZOMB)) { + continue; + } + + for (fd = 0; fd < pinfo.pi_maxofile; fd++) { + struct file file; + struct socket socket, *sockp; + struct protosw protosw; + struct domain domain; + struct inpcb inpcb; + long ptr; + + if (!(ptr = (long)finfo.pi_ufd[fd].fp)) { + continue; + } + + status = kread(sigar, &file, sizeof(file), ptr); + if (status != SIGAR_OK) { + continue; + } + + if (file.f_type != DTYPE_SOCKET) { + continue; + } + + if (!(sockp = (struct socket *)file.f_data)) { + continue; + } + + status = kread(sigar, &socket, sizeof(socket), (long)sockp); + if (status != SIGAR_OK) { + continue; + } + + if (!(ptr = (long)socket.so_proto)) { + continue; + } + + status = kread(sigar, &protosw, sizeof(protosw), ptr); + if (status != SIGAR_OK) { + continue; + } + + if (protosw.pr_protocol != type) { + continue; + } + + if (!(ptr = (long)protosw.pr_domain)) { + continue; + } + + status = kread(sigar, &domain, sizeof(domain), ptr); + if (status != SIGAR_OK) { + continue; + } + + if ((domain.dom_family != AF_INET) && + domain.dom_family != AF_INET6) + { + continue; + } + + if (!(ptr = (long)socket.so_pcb)) { + continue; + } + + status = kread(sigar, &inpcb, sizeof(inpcb), ptr); + if (status != SIGAR_OK) { + continue; + } + + if (sockp != inpcb.inp_socket) { + continue; + } + + if (inpcb.inp_lport != port) { + continue; + } + + *pidp = pinfo.pi_pid; + + return SIGAR_OK; + } + } + + return ENOENT; +} + +int sigar_os_sys_info_get(sigar_t *sigar, + sigar_sys_info_t *sysinfo) +{ + struct utsname name; + + uname(&name); + + SIGAR_SSTRCPY(sysinfo->vendor, "IBM"); + SIGAR_SSTRCPY(sysinfo->arch, get_cpu_arch()); + /* utsname.machine is a sequence number */ + /* XXX odm might have something better */ + snprintf(sysinfo->machine, + sizeof(sysinfo->machine), + "%s %s", + sysinfo->arch, get_cpu_model()); + + snprintf(sysinfo->version, + sizeof(sysinfo->version), + "%s.%s", + name.version, name.release); + + SIGAR_SSTRCPY(sysinfo->vendor_version, sysinfo->version); + + snprintf(sysinfo->description, + sizeof(sysinfo->description), + "%s %s", + sysinfo->name, sysinfo->version); + + return SIGAR_OK; +} diff --git a/vendor/sigar/src/os/aix/sigar_os.h b/vendor/sigar/src/os/aix/sigar_os.h new file mode 100644 index 0000000..5ee7cf0 --- /dev/null +++ b/vendor/sigar/src/os/aix/sigar_os.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2004-2007, 2009 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2010 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGAR_OS_H +#define SIGAR_OS_H + +#include +#include +#include +#include +#include + +enum { + KOFFSET_LOADAVG, + KOFFSET_VAR, + KOFFSET_SYSINFO, + KOFFSET_IFNET, + KOFFSET_VMINFO, + KOFFSET_CPUINFO, + KOFFSET_TCB, + KOFFSET_ARPTABSIZE, + KOFFSET_ARPTABP, + KOFFSET_MAX +}; + +typedef struct { + time_t mtime; + int num; + char **devs; +} swaps_t; + +typedef int (*proc_fd_func_t) (sigar_t *, sigar_pid_t, sigar_proc_fd_t *); + +struct sigar_t { + SIGAR_T_BASE; + int kmem; + /* offsets for seeking on kmem */ + long koffsets[KOFFSET_MAX]; + proc_fd_func_t getprocfd; + int pagesize; + swaps_t swaps; + time_t last_getprocs; + sigar_pid_t last_pid; + struct procsinfo64 *pinfo; + struct cpuinfo *cpuinfo; + int cpuinfo_size; + int cpu_mhz; + char model[128]; + int aix_version; + int thrusage; + sigar_cache_t *diskmap; +}; + +#define HAVE_STRERROR_R + +#define SIGAR_EPERM_KMEM (SIGAR_OS_START_ERROR+EACCES) + +#endif /* SIGAR_OS_H */ diff --git a/vendor/sigar/src/os/darwin/darwin_sigar.c b/vendor/sigar/src/os/darwin/darwin_sigar.c new file mode 100644 index 0000000..0e154b0 --- /dev/null +++ b/vendor/sigar/src/os/darwin/darwin_sigar.c @@ -0,0 +1,3711 @@ +/* + * Copyright (c) 2004-2009 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2009-2010 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_util.h" +#include "sigar_os.h" + +#include +#include +#if !(defined(__FreeBSD__) && (__FreeBSD_version >= 800000)) +#include +#endif +#include + +#ifdef DARWIN +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !defined(HAVE_SHARED_REGION_H) && defined(__MAC_10_5) /* see Availability.h */ +# define HAVE_SHARED_REGION_H /* suckit autoconf */ +#endif +#ifdef HAVE_SHARED_REGION_H +#include /* does not exist in 10.4 SDK */ +#else +#include /* deprecated in Leopard */ +#endif +#include +#define __OPENTRANSPORTPROVIDERS__ +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#endif + +#if defined(__FreeBSD__) && (__FreeBSD_version >= 500013) +#define SIGAR_FREEBSD5_NFSSTAT +#include +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#ifdef __NetBSD__ +#include +#include +#include +#define SRUN LSRUN +#define SSLEEP LSSLEEP +#define SDEAD LSDEAD +#define SONPROC LSONPROC +#define SSUSPENDED LSSUSPENDED +#include +#endif +#include +#include + +#define NMIB(mib) (sizeof(mib)/sizeof(mib[0])) + +#ifdef __FreeBSD__ +# if (__FreeBSD_version >= 500013) +# define SIGAR_FREEBSD5 +# else +# define SIGAR_FREEBSD4 +# endif +#endif + +#if defined(SIGAR_FREEBSD5) + +#define KI_FD ki_fd +#define KI_PID ki_pid +#define KI_PPID ki_ppid +#define KI_PRI ki_pri.pri_user +#define KI_NICE ki_nice +#define KI_COMM ki_comm +#define KI_STAT ki_stat +#define KI_UID ki_ruid +#define KI_GID ki_rgid +#define KI_EUID ki_svuid +#define KI_EGID ki_svgid +#define KI_SIZE ki_size +#define KI_RSS ki_rssize +#define KI_TSZ ki_tsize +#define KI_DSZ ki_dsize +#define KI_SSZ ki_ssize +#define KI_FLAG ki_flag +#define KI_START ki_start + +#elif defined(DARWIN) || defined(SIGAR_FREEBSD4) || defined(__OpenBSD__) || defined(__NetBSD__) + +#define KI_FD kp_proc.p_fd +#define KI_PID kp_proc.p_pid +#define KI_PPID kp_eproc.e_ppid +#define KI_PRI kp_proc.p_priority +#define KI_NICE kp_proc.p_nice +#define KI_COMM kp_proc.p_comm +#define KI_STAT kp_proc.p_stat +#define KI_UID kp_eproc.e_pcred.p_ruid +#define KI_GID kp_eproc.e_pcred.p_rgid +#define KI_EUID kp_eproc.e_pcred.p_svuid +#define KI_EGID kp_eproc.e_pcred.p_svgid +#define KI_SIZE XXX +#define KI_RSS kp_eproc.e_vm.vm_rssize +#define KI_TSZ kp_eproc.e_vm.vm_tsize +#define KI_DSZ kp_eproc.e_vm.vm_dsize +#define KI_SSZ kp_eproc.e_vm.vm_ssize +#define KI_FLAG kp_eproc.e_flag +#define KI_START kp_proc.p_starttime + +#endif + +#ifndef DARWIN + +#define PROCFS_STATUS(status) \ + ((((status) != SIGAR_OK) && !sigar->proc_mounted) ? \ + SIGAR_ENOTIMPL : status) + +static int get_koffsets(sigar_t *sigar) +{ + int i; + struct nlist klist[] = { + { "_cp_time" }, + { "_cnt" }, +#if defined(__OpenBSD__) || defined(__NetBSD__) + { "_tcpstat" }, + { "_tcbtable" }, +#endif + { NULL } + }; + + if (!sigar->kmem) { + return SIGAR_EPERM_KMEM; + } + + kvm_nlist(sigar->kmem, klist); + + for (i=0; ikoffsets[i] = klist[i].n_value; + } + + return SIGAR_OK; +} + +static int kread(sigar_t *sigar, void *data, int size, long offset) +{ + if (!sigar->kmem) { + return SIGAR_EPERM_KMEM; + } + + if (kvm_read(sigar->kmem, offset, data, size) != size) { + return errno; + } + + return SIGAR_OK; +} +#endif + +int sigar_os_open(sigar_t **sigar) +{ + int mib[2]; + int ncpu; + size_t len; + struct timeval boottime; +#ifndef DARWIN + struct stat sb; +#endif + + len = sizeof(ncpu); + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + if (sysctl(mib, NMIB(mib), &ncpu, &len, NULL, 0) < 0) { + return errno; + } + + len = sizeof(boottime); + mib[0] = CTL_KERN; + mib[1] = KERN_BOOTTIME; + if (sysctl(mib, NMIB(mib), &boottime, &len, NULL, 0) < 0) { + return errno; + } + + *sigar = malloc(sizeof(**sigar)); + +#ifdef DARWIN + (*sigar)->mach_port = mach_host_self(); +# ifdef DARWIN_HAS_LIBPROC_H + if (((*sigar)->libproc = dlopen("/usr/lib/libproc.dylib", 0))) { + (*sigar)->proc_pidinfo = dlsym((*sigar)->libproc, "proc_pidinfo"); + (*sigar)->proc_pidfdinfo = dlsym((*sigar)->libproc, "proc_pidfdinfo"); + } +# endif +#else + (*sigar)->kmem = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL); + if (stat("/proc/curproc", &sb) < 0) { + (*sigar)->proc_mounted = 0; + } + else { + (*sigar)->proc_mounted = 1; + } +#endif + +#ifndef DARWIN + get_koffsets(*sigar); +#endif + + (*sigar)->ncpu = ncpu; + (*sigar)->lcpu = -1; + (*sigar)->argmax = 0; + (*sigar)->boot_time = boottime.tv_sec; /* XXX seems off a bit */ + + (*sigar)->pagesize = getpagesize(); +#ifdef __FreeBSD__ + (*sigar)->ticks = 100; /* sysconf(_SC_CLK_TCK) == 128 !? */ +#else + (*sigar)->ticks = sysconf(_SC_CLK_TCK); +#endif + (*sigar)->last_pid = -1; + + (*sigar)->pinfo = NULL; + + return SIGAR_OK; +} + +int sigar_os_close(sigar_t *sigar) +{ + if (sigar->pinfo) { + free(sigar->pinfo); + } +#ifndef DARWIN + if (sigar->kmem) { + kvm_close(sigar->kmem); + } +#endif + free(sigar); + return SIGAR_OK; +} + +char *sigar_os_error_string(sigar_t *sigar, int err) +{ + switch (err) { + case SIGAR_EPERM_KMEM: + return "Failed to open /dev/kmem for reading"; + case SIGAR_EPROC_NOENT: + return "/proc filesystem is not mounted"; + default: + return NULL; + } +} + +/* ARG_MAX in FreeBSD 6.0 == 262144, which blows up the stack */ +#define SIGAR_ARG_MAX 65536 + +#ifdef DARWIN +static size_t sigar_argmax_get(sigar_t *sigar) +{ +#ifdef KERN_ARGMAX + int mib[] = { CTL_KERN, KERN_ARGMAX }; + size_t size = sizeof(sigar->argmax); + + if (sigar->argmax != 0) { + return sigar->argmax; + } + if (sysctl(mib, NMIB(mib), &sigar->argmax, &size, NULL, 0) == 0) { + return sigar->argmax; + } +#endif + return SIGAR_ARG_MAX; +} +#endif /* DARWIN */ + +#if defined(DARWIN) +static int sigar_vmstat(sigar_t *sigar, vm_statistics_data_t *vmstat) +{ + kern_return_t status; + mach_msg_type_number_t count = sizeof(*vmstat) / sizeof(integer_t); + + status = host_statistics(sigar->mach_port, HOST_VM_INFO, + (host_info_t)vmstat, &count); + + if (status == KERN_SUCCESS) { + return SIGAR_OK; + } + else { + return errno; + } +} +#elif defined(__FreeBSD__) +static int sigar_vmstat(sigar_t *sigar, struct vmmeter *vmstat) +{ + int status; + size_t size = sizeof(unsigned int); + + status = kread(sigar, vmstat, sizeof(*vmstat), + sigar->koffsets[KOFFSET_VMMETER]); + + if (status == SIGAR_OK) { + return SIGAR_OK; + } + + SIGAR_ZERO(vmstat); + + /* derived from src/usr.bin/vmstat/vmstat.c */ + /* only collect the ones we actually use */ +#define GET_VM_STATS(cat, name, used) \ + if (used) sysctlbyname("vm.stats." #cat "." #name, &vmstat->name, &size, NULL, 0) + + /* sys */ + GET_VM_STATS(sys, v_swtch, 0); + GET_VM_STATS(sys, v_trap, 0); + GET_VM_STATS(sys, v_syscall, 0); + GET_VM_STATS(sys, v_intr, 0); + GET_VM_STATS(sys, v_soft, 0); + + /* vm */ + GET_VM_STATS(vm, v_vm_faults, 0); + GET_VM_STATS(vm, v_cow_faults, 0); + GET_VM_STATS(vm, v_cow_optim, 0); + GET_VM_STATS(vm, v_zfod, 0); + GET_VM_STATS(vm, v_ozfod, 0); + GET_VM_STATS(vm, v_swapin, 1); + GET_VM_STATS(vm, v_swapout, 1); + GET_VM_STATS(vm, v_swappgsin, 0); + GET_VM_STATS(vm, v_swappgsout, 0); + GET_VM_STATS(vm, v_vnodein, 1); + GET_VM_STATS(vm, v_vnodeout, 1); + GET_VM_STATS(vm, v_vnodepgsin, 0); + GET_VM_STATS(vm, v_vnodepgsout, 0); + GET_VM_STATS(vm, v_intrans, 0); + GET_VM_STATS(vm, v_reactivated, 0); + GET_VM_STATS(vm, v_pdwakeups, 0); + GET_VM_STATS(vm, v_pdpages, 0); + GET_VM_STATS(vm, v_dfree, 0); + GET_VM_STATS(vm, v_pfree, 0); + GET_VM_STATS(vm, v_tfree, 0); + GET_VM_STATS(vm, v_page_size, 0); + GET_VM_STATS(vm, v_page_count, 0); + GET_VM_STATS(vm, v_free_reserved, 0); + GET_VM_STATS(vm, v_free_target, 0); + GET_VM_STATS(vm, v_free_min, 0); + GET_VM_STATS(vm, v_free_count, 1); + GET_VM_STATS(vm, v_wire_count, 0); + GET_VM_STATS(vm, v_active_count, 0); + GET_VM_STATS(vm, v_inactive_target, 0); + GET_VM_STATS(vm, v_inactive_count, 1); + GET_VM_STATS(vm, v_cache_count, 1); + GET_VM_STATS(vm, v_cache_min, 0); + GET_VM_STATS(vm, v_cache_max, 0); + GET_VM_STATS(vm, v_pageout_free_min, 0); + GET_VM_STATS(vm, v_interrupt_free_min, 0); + GET_VM_STATS(vm, v_forks, 0); + GET_VM_STATS(vm, v_vforks, 0); + GET_VM_STATS(vm, v_rforks, 0); + GET_VM_STATS(vm, v_kthreads, 0); + GET_VM_STATS(vm, v_forkpages, 0); + GET_VM_STATS(vm, v_vforkpages, 0); + GET_VM_STATS(vm, v_rforkpages, 0); + GET_VM_STATS(vm, v_kthreadpages, 0); +#undef GET_VM_STATS + + return SIGAR_OK; +} +#elif defined(__OpenBSD__) || defined(__NetBSD__) +static int sigar_vmstat(sigar_t *sigar, struct uvmexp *vmstat) +{ + size_t size = sizeof(*vmstat); + int mib[] = { CTL_VM, VM_UVMEXP }; + if (sysctl(mib, NMIB(mib), vmstat, &size, NULL, 0) < 0) { + return errno; + } + else { + return SIGAR_OK; + } +} +#endif + +int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem) +{ + sigar_uint64_t kern = 0; +#ifdef DARWIN + vm_statistics_data_t vmstat; + uint64_t mem_total; +#else + unsigned long mem_total; +#endif +#if defined(__FreeBSD__) + struct vmmeter vmstat; +#elif defined(__OpenBSD__) || defined(__NetBSD__) + struct uvmexp vmstat; +#endif + int mib[2]; + size_t len; + int status; + + mib[0] = CTL_HW; + + mib[1] = HW_PAGESIZE; + len = sizeof(sigar->pagesize); + if (sysctl(mib, NMIB(mib), &sigar->pagesize, &len, NULL, 0) < 0) { + return errno; + } + +#ifdef DARWIN + mib[1] = HW_MEMSIZE; +#else + mib[1] = HW_PHYSMEM; +#endif + len = sizeof(mem_total); + if (sysctl(mib, NMIB(mib), &mem_total, &len, NULL, 0) < 0) { + return errno; + } + + mem->total = mem_total; + +#if defined(DARWIN) + if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) { + return status; + } + + mem->free = vmstat.free_count; + mem->free *= sigar->pagesize; + kern = vmstat.inactive_count; + kern *= sigar->pagesize; +#elif defined(__FreeBSD__) + if ((status = sigar_vmstat(sigar, &vmstat)) == SIGAR_OK) { + kern = vmstat.v_cache_count + vmstat.v_inactive_count; + kern *= sigar->pagesize; + mem->free = vmstat.v_free_count; + mem->free *= sigar->pagesize; + } +#elif defined(__OpenBSD__) || defined(__NetBSD__) + if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) { + return status; + } + mem->free = vmstat.free; + kern = vmstat.inactive; +# if defined(__OpenBSD__) + kern += vmstat.vnodepages + vmstat.vtextpages; +# elif defined(__NetBSD__) + kern += vmstat.filepages + vmstat.execpages; +# endif + kern *= sigar->pagesize; +#endif + + mem->used = mem->total - mem->free; + + mem->actual_free = mem->free + kern; + mem->actual_used = mem->used - kern; + + sigar_mem_calc_ram(sigar, mem); + + return SIGAR_OK; +} + +#define SWI_MAXMIB 3 + +#ifdef SIGAR_FREEBSD5 +/* code in this function is based on FreeBSD 5.3 kvm_getswapinfo.c */ +static int getswapinfo_sysctl(struct kvm_swap *swap_ary, + int swap_max) +{ + int ti, ttl; + size_t mibi, len, size; + int soid[SWI_MAXMIB]; + struct xswdev xsd; + struct kvm_swap tot; + int unswdev, dmmax; + + /* XXX this can be optimized by using os_open */ + size = sizeof(dmmax); + if (sysctlbyname("vm.dmmax", &dmmax, &size, NULL, 0) == -1) { + return errno; + } + + mibi = SWI_MAXMIB - 1; + if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) { + return errno; + } + + bzero(&tot, sizeof(tot)); + for (unswdev = 0;; unswdev++) { + soid[mibi] = unswdev; + len = sizeof(xsd); + if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) == -1) { + if (errno == ENOENT) { + break; + } + return errno; + } +#if 0 + if (len != sizeof(xsd)) { + _kvm_err(kd, kd->program, "struct xswdev has unexpected " + "size; kernel and libkvm out of sync?"); + return -1; + } + if (xsd.xsw_version != XSWDEV_VERSION) { + _kvm_err(kd, kd->program, "struct xswdev version " + "mismatch; kernel and libkvm out of sync?"); + return -1; + } +#endif + ttl = xsd.xsw_nblks - dmmax; + if (unswdev < swap_max - 1) { + bzero(&swap_ary[unswdev], sizeof(swap_ary[unswdev])); + swap_ary[unswdev].ksw_total = ttl; + swap_ary[unswdev].ksw_used = xsd.xsw_used; + swap_ary[unswdev].ksw_flags = xsd.xsw_flags; + } + tot.ksw_total += ttl; + tot.ksw_used += xsd.xsw_used; + } + + ti = unswdev; + if (ti >= swap_max) { + ti = swap_max - 1; + } + if (ti >= 0) { + swap_ary[ti] = tot; + } + + return SIGAR_OK; +} +#else +#define getswapinfo_sysctl(swap_ary, swap_max) SIGAR_ENOTIMPL +#endif + +#define SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) ((val * bsize) >> 1) + +#ifdef DARWIN +#define VM_DIR "/private/var/vm" +#define SWAPFILE "swapfile" + +static int sigar_swap_fs_get(sigar_t *sigar, sigar_swap_t *swap) /* <= 10.3 */ +{ + DIR *dirp; + struct dirent *ent; + char swapfile[SSTRLEN(VM_DIR) + SSTRLEN("/") + SSTRLEN(SWAPFILE) + 12]; + struct stat swapstat; + struct statfs vmfs; + sigar_uint64_t val, bsize; + + swap->used = swap->total = swap->free = 0; + + if (!(dirp = opendir(VM_DIR))) { + return errno; + } + + /* looking for "swapfile0", "swapfile1", etc. */ + while ((ent = readdir(dirp))) { + char *ptr = swapfile; + + if ((ent->d_namlen < SSTRLEN(SWAPFILE)+1) || /* n/a, see comment above */ + (ent->d_namlen > SSTRLEN(SWAPFILE)+11)) /* ensure no overflow */ + { + continue; + } + + if (!strnEQ(ent->d_name, SWAPFILE, SSTRLEN(SWAPFILE))) { + continue; + } + + /* sprintf(swapfile, "%s/%s", VM_DIR, ent->d_name) */ + + memcpy(ptr, VM_DIR, SSTRLEN(VM_DIR)); + ptr += SSTRLEN(VM_DIR); + + *ptr++ = '/'; + + memcpy(ptr, ent->d_name, ent->d_namlen+1); + + if (stat(swapfile, &swapstat) < 0) { + continue; + } + + swap->used += swapstat.st_size; + } + + closedir(dirp); + + if (statfs(VM_DIR, &vmfs) < 0) { + return errno; + } + + bsize = vmfs.f_bsize / 512; + val = vmfs.f_bfree; + swap->total = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) + swap->used; + + swap->free = swap->total - swap->used; + + return SIGAR_OK; +} + +static int sigar_swap_sysctl_get(sigar_t *sigar, sigar_swap_t *swap) + +{ +#ifdef VM_SWAPUSAGE /* => 10.4 */ + struct xsw_usage sw_usage; + size_t size = sizeof(sw_usage); + int mib[] = { CTL_VM, VM_SWAPUSAGE }; + + if (sysctl(mib, NMIB(mib), &sw_usage, &size, NULL, 0) != 0) { + return errno; + } + + swap->total = sw_usage.xsu_total; + swap->used = sw_usage.xsu_used; + swap->free = sw_usage.xsu_avail; + + return SIGAR_OK; +#else + return SIGAR_ENOTIMPL; /* <= 10.3 */ +#endif +} +#endif /* DARWIN */ + +int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap) +{ + int status; +#if defined(DARWIN) + vm_statistics_data_t vmstat; + + if (sigar_swap_sysctl_get(sigar, swap) != SIGAR_OK) { + status = sigar_swap_fs_get(sigar, swap); /* <= 10.3 */ + if (status != SIGAR_OK) { + return status; + } + } + + if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) { + return status; + } + swap->page_in = vmstat.pageins; + swap->page_out = vmstat.pageouts; +#elif defined(__FreeBSD__) + struct kvm_swap kswap[1]; + struct vmmeter vmstat; + + if (getswapinfo_sysctl(kswap, 1) != SIGAR_OK) { + if (!sigar->kmem) { + return SIGAR_EPERM_KMEM; + } + + if (kvm_getswapinfo(sigar->kmem, kswap, 1, 0) < 0) { + return errno; + } + } + + if (kswap[0].ksw_total == 0) { + swap->total = 0; + swap->used = 0; + swap->free = 0; + return SIGAR_OK; + } + + swap->total = kswap[0].ksw_total * sigar->pagesize; + swap->used = kswap[0].ksw_used * sigar->pagesize; + swap->free = swap->total - swap->used; + + if ((status = sigar_vmstat(sigar, &vmstat)) == SIGAR_OK) { + swap->page_in = vmstat.v_swapin + vmstat.v_vnodein; + swap->page_out = vmstat.v_swapout + vmstat.v_vnodeout; + } + else { + swap->page_in = swap->page_out = -1; + } +#elif defined(__OpenBSD__) || defined(__NetBSD__) + struct uvmexp vmstat; + + if ((status = sigar_vmstat(sigar, &vmstat)) != SIGAR_OK) { + return status; + } + swap->total = vmstat.swpages * sigar->pagesize; + swap->used = vmstat.swpginuse * sigar->pagesize; + swap->free = swap->total - swap->used; + swap->page_in = vmstat.pageins; + swap->page_out = vmstat.pdpageouts; +#endif + + return SIGAR_OK; +} + +#ifndef KERN_CPTIME +#define KERN_CPTIME KERN_CP_TIME +#endif + +#if defined(__NetBSD__) +typedef uint64_t cp_time_t; +#else +typedef unsigned long cp_time_t; +#endif + +int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu) +{ +#if defined(DARWIN) + kern_return_t status; + mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; + host_cpu_load_info_data_t cpuload; + + status = host_statistics(sigar->mach_port, HOST_CPU_LOAD_INFO, + (host_info_t)&cpuload, &count); + + if (status != KERN_SUCCESS) { + return errno; + } + + cpu->user = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_USER]); + cpu->sys = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_SYSTEM]); + cpu->idle = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_IDLE]); + cpu->nice = SIGAR_TICK2MSEC(cpuload.cpu_ticks[CPU_STATE_NICE]); + cpu->wait = 0; /*N/A*/ + cpu->irq = 0; /*N/A*/ + cpu->soft_irq = 0; /*N/A*/ + cpu->stolen = 0; /*N/A*/ + cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle; + +#elif defined(__FreeBSD__) || (__OpenBSD__) || defined(__NetBSD__) + int status; + cp_time_t cp_time[CPUSTATES]; + size_t size = sizeof(cp_time); + +# if defined(__OpenBSD__) || defined(__NetBSD__) + int mib[] = { CTL_KERN, KERN_CPTIME }; + if (sysctl(mib, NMIB(mib), &cp_time, &size, NULL, 0) == -1) { + status = errno; + } +# else + /* try sysctl first, does not require /dev/kmem perms */ + if (sysctlbyname("kern.cp_time", &cp_time, &size, NULL, 0) == -1) { + status = kread(sigar, &cp_time, sizeof(cp_time), + sigar->koffsets[KOFFSET_CPUINFO]); + } +# endif + else { + status = SIGAR_OK; + } + + if (status != SIGAR_OK) { + return status; + } + + cpu->user = SIGAR_TICK2MSEC(cp_time[CP_USER]); + cpu->nice = SIGAR_TICK2MSEC(cp_time[CP_NICE]); + cpu->sys = SIGAR_TICK2MSEC(cp_time[CP_SYS]); + cpu->idle = SIGAR_TICK2MSEC(cp_time[CP_IDLE]); + cpu->wait = 0; /*N/A*/ + cpu->irq = SIGAR_TICK2MSEC(cp_time[CP_INTR]); + cpu->soft_irq = 0; /*N/A*/ + cpu->stolen = 0; /*N/A*/ + cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle + cpu->irq; +#endif + + return SIGAR_OK; +} + +#if defined(__FreeBSD__) && (__FreeBSD_version >= 700000) +#define HAVE_KERN_CP_TIMES /* kern.cp_times came later than 7.0, not sure exactly when */ +static int sigar_cp_times_get(sigar_t *sigar, sigar_cpu_list_t *cpulist) +{ + int maxcpu, status; + size_t len = sizeof(maxcpu), size; + long *times; + + if (sysctlbyname("kern.smp.maxcpus", &maxcpu, &len, NULL, 0) == -1) { + return errno; + } + + size = sizeof(long) * maxcpu * CPUSTATES; + times = malloc(size); + if (sysctlbyname("kern.cp_times", times, &size, NULL, 0) == -1) { + status = errno; + } + else { + int i, maxid = (size / CPUSTATES / sizeof(long)); + long *cp_time = times; + status = SIGAR_OK; + + for (i=0; idata[cpulist->number++]; + cpu->user = SIGAR_TICK2MSEC(cp_time[CP_USER]); + cpu->nice = SIGAR_TICK2MSEC(cp_time[CP_NICE]); + cpu->sys = SIGAR_TICK2MSEC(cp_time[CP_SYS]); + cpu->idle = SIGAR_TICK2MSEC(cp_time[CP_IDLE]); + cpu->wait = 0; /*N/A*/ + cpu->irq = SIGAR_TICK2MSEC(cp_time[CP_INTR]); + cpu->soft_irq = 0; /*N/A*/ + cpu->stolen = 0; /*N/A*/ + cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle + cpu->irq; + cp_time += CPUSTATES; + } + } + + free(times); + return status; +} +#endif + +int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist) +{ +#ifdef DARWIN + kern_return_t status; + mach_msg_type_number_t count; + processor_cpu_load_info_data_t *cpuload; + natural_t i, ncpu; + + status = host_processor_info(sigar->mach_port, + PROCESSOR_CPU_LOAD_INFO, + &ncpu, + (processor_info_array_t*)&cpuload, + &count); + + if (status != KERN_SUCCESS) { + return errno; + } + + sigar_cpu_list_create(cpulist); + + for (i=0; idata[cpulist->number++]; + + cpu->user = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_USER]); + cpu->sys = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_SYSTEM]); + cpu->idle = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_IDLE]); + cpu->nice = SIGAR_TICK2MSEC(cpuload[i].cpu_ticks[CPU_STATE_NICE]); + cpu->wait = 0; /*N/A*/ + cpu->irq = 0; /*N/A*/ + cpu->soft_irq = 0; /*N/A*/ + cpu->stolen = 0; /*N/A*/ + cpu->total = cpu->user + cpu->nice + cpu->sys + cpu->idle; + } + + vm_deallocate(mach_task_self(), (vm_address_t)cpuload, count); + + return SIGAR_OK; +#else + int status, i; + sigar_cpu_t *cpu; + + sigar_cpu_list_create(cpulist); + +#ifdef HAVE_KERN_CP_TIMES + if ((status = sigar_cp_times_get(sigar, cpulist)) == SIGAR_OK) { + return SIGAR_OK; + } +#endif + /* XXX no multi cpu in freebsd < 7.0, howbout others? + * for now just report all metrics on the 1st cpu + * 0's for the rest + */ + cpu = &cpulist->data[cpulist->number++]; + + status = sigar_cpu_get(sigar, cpu); + if (status != SIGAR_OK) { + return status; + } + + for (i=1; incpu; i++) { + SIGAR_CPU_LIST_GROW(cpulist); + + cpu = &cpulist->data[cpulist->number++]; + SIGAR_ZERO(cpu); + } + + return SIGAR_OK; +#endif +} + +int sigar_uptime_get(sigar_t *sigar, + sigar_uptime_t *uptime) +{ + uptime->uptime = time(NULL) - sigar->boot_time; + + return SIGAR_OK; +} + +int sigar_loadavg_get(sigar_t *sigar, + sigar_loadavg_t *loadavg) +{ + getloadavg(loadavg->loadavg, 3); + + return SIGAR_OK; +} + +#if defined(DARWIN) && defined(DARWIN_HAS_LIBPROC_H) + +static int proc_fdinfo_get(sigar_t *sigar, sigar_pid_t pid, int *num) +{ + int rsize; + const int init_size = PROC_PIDLISTFD_SIZE * 32; + + if (!sigar->libproc) { + return SIGAR_ENOTIMPL; + } + + if (sigar->ifconf_len == 0) { + sigar->ifconf_len = init_size; + sigar->ifconf_buf = malloc(sigar->ifconf_len); + } + + while (1) { + rsize = sigar->proc_pidinfo(pid, PROC_PIDLISTFDS, 0, + sigar->ifconf_buf, sigar->ifconf_len); + if (rsize <= 0) { + return errno; + } + if ((rsize + PROC_PIDLISTFD_SIZE) < sigar->ifconf_len) { + break; + } + + sigar->ifconf_len += init_size; + sigar->ifconf_buf = realloc(sigar->ifconf_buf, sigar->ifconf_len); + } + + *num = rsize / PROC_PIDLISTFD_SIZE; + + return SIGAR_OK; +} + +#endif + +#ifndef KERN_PROC_PROC +/* freebsd 4.x */ +#define KERN_PROC_PROC KERN_PROC_ALL +#endif + +int sigar_os_proc_list_get(sigar_t *sigar, + sigar_proc_list_t *proclist) +{ +#if defined(DARWIN) || defined(SIGAR_FREEBSD5) || defined(__OpenBSD__) || defined(__NetBSD__) + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 }; + int i, num; + size_t len; + struct kinfo_proc *proc; + + if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) { + return errno; + } + + proc = malloc(len); + + if (sysctl(mib, NMIB(mib), proc, &len, NULL, 0) < 0) { + free(proc); + return errno; + } + + num = len/sizeof(*proc); + + for (i=0; idata[proclist->number++] = proc[i].KI_PID; + } + + free(proc); + + return SIGAR_OK; +#else + int i, num; + struct kinfo_proc *proc; + + if (!sigar->kmem) { + return SIGAR_EPERM_KMEM; + } + + proc = kvm_getprocs(sigar->kmem, KERN_PROC_PROC, 0, &num); + + for (i=0; idata[proclist->number++] = proc[i].KI_PID; + } +#endif + + return SIGAR_OK; +} + +static int sigar_get_pinfo(sigar_t *sigar, sigar_pid_t pid) +{ +#if defined(__OpenBSD__) || defined(__NetBSD__) + int mib[] = { CTL_KERN, KERN_PROC2, KERN_PROC_PID, 0, sizeof(*sigar->pinfo), 1 }; +#else + int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 }; +#endif + size_t len = sizeof(*sigar->pinfo); + time_t timenow = time(NULL); + mib[3] = pid; + + if (sigar->pinfo == NULL) { + sigar->pinfo = malloc(len); + } + + if (sigar->last_pid == pid) { + if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) { + return SIGAR_OK; + } + } + + sigar->last_pid = pid; + sigar->last_getprocs = timenow; + + if (sysctl(mib, NMIB(mib), sigar->pinfo, &len, NULL, 0) < 0) { + return errno; + } + + return SIGAR_OK; +} + +#if defined(SHARED_TEXT_REGION_SIZE) && defined(SHARED_DATA_REGION_SIZE) +# define GLOBAL_SHARED_SIZE (SHARED_TEXT_REGION_SIZE + SHARED_DATA_REGION_SIZE) /* 10.4 SDK */ +#endif + +#if defined(DARWIN) && defined(DARWIN_HAS_LIBPROC_H) && !defined(GLOBAL_SHARED_SIZE) +/* get the CPU type of the process for the given pid */ +static int sigar_proc_cpu_type(sigar_t *sigar, sigar_pid_t pid, cpu_type_t *type) +{ + int status; + int mib[CTL_MAXNAME]; + size_t len, miblen = NMIB(mib); + + status = sysctlnametomib("sysctl.proc_cputype", mib, &miblen); + if (status != SIGAR_OK) { + return status; + } + + mib[miblen] = pid; + len = sizeof(*type); + return sysctl(mib, miblen + 1, type, &len, NULL, 0); +} + +/* shared memory region size for the given cpu_type_t */ +static mach_vm_size_t sigar_shared_region_size(cpu_type_t type) +{ + switch (type) { + case CPU_TYPE_ARM: + return SHARED_REGION_SIZE_ARM; + case CPU_TYPE_POWERPC: + return SHARED_REGION_SIZE_PPC; + case CPU_TYPE_POWERPC64: + return SHARED_REGION_SIZE_PPC64; + case CPU_TYPE_I386: + return SHARED_REGION_SIZE_I386; + case CPU_TYPE_X86_64: + return SHARED_REGION_SIZE_X86_64; + default: + return SHARED_REGION_SIZE_I386; /* assume 32-bit x86|ppc */ + } +} +#endif /* DARWIN */ + +int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_mem_t *procmem) +{ +#if defined(DARWIN) + mach_port_t task, self = mach_task_self(); + kern_return_t status; + task_basic_info_data_t info; + task_events_info_data_t events; + mach_msg_type_number_t count; +# ifdef DARWIN_HAS_LIBPROC_H + struct proc_taskinfo pti; + struct proc_regioninfo pri; + + if (sigar->libproc) { + int sz = + sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)); + + if (sz == sizeof(pti)) { + procmem->size = pti.pti_virtual_size; + procmem->resident = pti.pti_resident_size; + procmem->page_faults = pti.pti_faults; + procmem->minor_faults = SIGAR_FIELD_NOTIMPL; + procmem->major_faults = SIGAR_FIELD_NOTIMPL; + procmem->share = SIGAR_FIELD_NOTIMPL; + + sz = sigar->proc_pidinfo(pid, PROC_PIDREGIONINFO, 0, &pri, sizeof(pri)); + if (sz == sizeof(pri)) { + if (pri.pri_share_mode == SM_EMPTY) { + mach_vm_size_t shared_size; +#ifdef GLOBAL_SHARED_SIZE + shared_size = GLOBAL_SHARED_SIZE; /* 10.4 SDK */ +#else + cpu_type_t cpu_type; + + if (sigar_proc_cpu_type(sigar, pid, &cpu_type) == SIGAR_OK) { + shared_size = sigar_shared_region_size(cpu_type); + } + else { + shared_size = SHARED_REGION_SIZE_I386; /* assume 32-bit x86|ppc */ + } +#endif + if (procmem->size > shared_size) { + procmem->size -= shared_size; /* SIGAR-123 */ + } + } + } + return SIGAR_OK; + } + } +# endif + + status = task_for_pid(self, pid, &task); + + if (status != KERN_SUCCESS) { + return errno; + } + + count = TASK_BASIC_INFO_COUNT; + status = task_info(task, TASK_BASIC_INFO, (task_info_t)&info, &count); + if (status != KERN_SUCCESS) { + return errno; + } + + count = TASK_EVENTS_INFO_COUNT; + status = task_info(task, TASK_EVENTS_INFO, (task_info_t)&events, &count); + if (status == KERN_SUCCESS) { + procmem->page_faults = events.faults; + } + else { + procmem->page_faults = SIGAR_FIELD_NOTIMPL; + } + + procmem->minor_faults = SIGAR_FIELD_NOTIMPL; + procmem->major_faults = SIGAR_FIELD_NOTIMPL; + + if (task != self) { + mach_port_deallocate(self, task); + } + + procmem->size = info.virtual_size; + procmem->resident = info.resident_size; + procmem->share = SIGAR_FIELD_NOTIMPL; + + return SIGAR_OK; +#elif defined(__FreeBSD__) + int status = sigar_get_pinfo(sigar, pid); + bsd_pinfo_t *pinfo = sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + + procmem->size = + (pinfo->KI_TSZ + pinfo->KI_DSZ + pinfo->KI_SSZ) * sigar->pagesize; + + procmem->resident = pinfo->KI_RSS * sigar->pagesize; + + procmem->share = SIGAR_FIELD_NOTIMPL; + + procmem->page_faults = SIGAR_FIELD_NOTIMPL; + procmem->minor_faults = SIGAR_FIELD_NOTIMPL; + procmem->major_faults = SIGAR_FIELD_NOTIMPL; +#elif defined(__OpenBSD__) || defined(__NetBSD__) + int status = sigar_get_pinfo(sigar, pid); + bsd_pinfo_t *pinfo = sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + + procmem->size = + (pinfo->p_vm_tsize + pinfo->p_vm_dsize + pinfo->p_vm_ssize) * sigar->pagesize; + + procmem->resident = pinfo->p_vm_rssize * sigar->pagesize; + + procmem->share = SIGAR_FIELD_NOTIMPL; + + procmem->minor_faults = pinfo->p_uru_minflt; + procmem->major_faults = pinfo->p_uru_majflt; + procmem->page_faults = procmem->minor_faults + procmem->major_faults; +#endif + return SIGAR_OK; +} + +int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_cred_t *proccred) +{ + int status = sigar_get_pinfo(sigar, pid); + bsd_pinfo_t *pinfo = sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + +#if defined(__OpenBSD__) || defined(__NetBSD__) + proccred->uid = pinfo->p_ruid; + proccred->gid = pinfo->p_rgid; + proccred->euid = pinfo->p_uid; + proccred->egid = pinfo->p_gid; +#else + proccred->uid = pinfo->KI_UID; + proccred->gid = pinfo->KI_GID; + proccred->euid = pinfo->KI_EUID; + proccred->egid = pinfo->KI_EGID; +#endif + + return SIGAR_OK; +} + +#define tv2msec(tv) \ + (((sigar_uint64_t)tv.tv_sec * SIGAR_MSEC) + (((sigar_uint64_t)tv.tv_usec) / 1000)) + +#ifdef DARWIN +#define tval2msec(tval) \ + ((tval.seconds * SIGAR_MSEC) + (tval.microseconds / 1000)) + +#define tval2nsec(tval) \ + (SIGAR_SEC2NANO((tval).seconds) + SIGAR_MICROSEC2NANO((tval).microseconds)) + +static int get_proc_times(sigar_t *sigar, sigar_pid_t pid, sigar_proc_time_t *time) +{ + unsigned int count; + time_value_t utime = {0, 0}, stime = {0, 0}; + task_basic_info_data_t ti; + task_thread_times_info_data_t tti; + task_port_t task, self; + kern_return_t status; +# ifdef DARWIN_HAS_LIBPROC_H + if (sigar->libproc) { + struct proc_taskinfo pti; + int sz = + sigar->proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)); + + if (sz == sizeof(pti)) { + time->user = SIGAR_NSEC2MSEC(pti.pti_total_user); + time->sys = SIGAR_NSEC2MSEC(pti.pti_total_system); + time->total = time->user + time->sys; + return SIGAR_OK; + } + } +# endif + + self = mach_task_self(); + status = task_for_pid(self, pid, &task); + if (status != KERN_SUCCESS) { + return errno; + } + + count = TASK_BASIC_INFO_COUNT; + status = task_info(task, TASK_BASIC_INFO, + (task_info_t)&ti, &count); + if (status != KERN_SUCCESS) { + if (task != self) { + mach_port_deallocate(self, task); + } + return errno; + } + + count = TASK_THREAD_TIMES_INFO_COUNT; + status = task_info(task, TASK_THREAD_TIMES_INFO, + (task_info_t)&tti, &count); + if (status != KERN_SUCCESS) { + if (task != self) { + mach_port_deallocate(self, task); + } + return errno; + } + + time_value_add(&utime, &ti.user_time); + time_value_add(&stime, &ti.system_time); + time_value_add(&utime, &tti.user_time); + time_value_add(&stime, &tti.system_time); + + time->user = tval2msec(utime); + time->sys = tval2msec(stime); + time->total = time->user + time->sys; + + return SIGAR_OK; +} +#endif + +int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_time_t *proctime) +{ +#ifdef SIGAR_FREEBSD4 + struct user user; +#endif + int status = sigar_get_pinfo(sigar, pid); + bsd_pinfo_t *pinfo = sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + +#if defined(DARWIN) + if ((status = get_proc_times(sigar, pid, proctime)) != SIGAR_OK) { + return status; + } + proctime->start_time = tv2msec(pinfo->KI_START); +#elif defined(SIGAR_FREEBSD5) + proctime->user = tv2msec(pinfo->ki_rusage.ru_utime); + proctime->sys = tv2msec(pinfo->ki_rusage.ru_stime); + proctime->total = proctime->user + proctime->sys; + proctime->start_time = tv2msec(pinfo->KI_START); +#elif defined(SIGAR_FREEBSD4) + if (!sigar->kmem) { + return SIGAR_EPERM_KMEM; + } + + status = kread(sigar, &user, sizeof(user), + (u_long)pinfo->kp_proc.p_addr); + if (status != SIGAR_OK) { + return status; + } + + proctime->user = tv2msec(user.u_stats.p_ru.ru_utime); + proctime->sys = tv2msec(user.u_stats.p_ru.ru_stime); + proctime->total = proctime->user + proctime->sys; + proctime->start_time = tv2msec(user.u_stats.p_start); +#elif defined(__OpenBSD__) || defined(__NetBSD__) + /* XXX *_usec */ + proctime->user = pinfo->p_uutime_sec * SIGAR_MSEC; + proctime->sys = pinfo->p_ustime_sec * SIGAR_MSEC; + proctime->total = proctime->user + proctime->sys; + proctime->start_time = pinfo->p_ustart_sec * SIGAR_MSEC; +#endif + + return SIGAR_OK; +} + +#ifdef DARWIN +/* thread state mapping derived from ps.tproj */ +static const char const thread_states[] = { + /*0*/ '-', + /*1*/ SIGAR_PROC_STATE_RUN, + /*2*/ SIGAR_PROC_STATE_ZOMBIE, + /*3*/ SIGAR_PROC_STATE_SLEEP, + /*4*/ SIGAR_PROC_STATE_IDLE, + /*5*/ SIGAR_PROC_STATE_STOP, + /*6*/ SIGAR_PROC_STATE_STOP, + /*7*/ '?' +}; + +static int thread_state_get(thread_basic_info_data_t *info) +{ + switch (info->run_state) { + case TH_STATE_RUNNING: + return 1; + case TH_STATE_UNINTERRUPTIBLE: + return 2; + case TH_STATE_WAITING: + return (info->sleep_time > 20) ? 4 : 3; + case TH_STATE_STOPPED: + return 5; + case TH_STATE_HALTED: + return 6; + default: + return 7; + } +} + +static int sigar_proc_threads_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_state_t *procstate) +{ + mach_port_t task, self = mach_task_self(); + kern_return_t status; + thread_array_t threads; + mach_msg_type_number_t count, i; + int state = TH_STATE_HALTED + 1; + + status = task_for_pid(self, pid, &task); + if (status != KERN_SUCCESS) { + return errno; + } + + status = task_threads(task, &threads, &count); + if (status != KERN_SUCCESS) { + return errno; + } + + procstate->threads = count; + + for (i=0; istate = thread_states[state]; + + return SIGAR_OK; +} +#endif + +int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_state_t *procstate) +{ + int status = sigar_get_pinfo(sigar, pid); + bsd_pinfo_t *pinfo = sigar->pinfo; +#if defined(__OpenBSD__) || defined(__NetBSD__) + int state = pinfo->p_stat; +#else + int state = pinfo->KI_STAT; +#endif + + if (status != SIGAR_OK) { + return status; + } + +#if defined(__OpenBSD__) || defined(__NetBSD__) + SIGAR_SSTRCPY(procstate->name, pinfo->p_comm); + procstate->ppid = pinfo->p_ppid; + procstate->priority = pinfo->p_priority; + procstate->nice = pinfo->p_nice; + procstate->tty = pinfo->p_tdev; + procstate->threads = SIGAR_FIELD_NOTIMPL; + procstate->processor = pinfo->p_cpuid; +#else + SIGAR_SSTRCPY(procstate->name, pinfo->KI_COMM); + procstate->ppid = pinfo->KI_PPID; + procstate->priority = pinfo->KI_PRI; + procstate->nice = pinfo->KI_NICE; + procstate->tty = SIGAR_FIELD_NOTIMPL; /*XXX*/ + procstate->threads = SIGAR_FIELD_NOTIMPL; + procstate->processor = SIGAR_FIELD_NOTIMPL; +#endif + +#ifdef DARWIN + status = sigar_proc_threads_get(sigar, pid, procstate); + if (status == SIGAR_OK) { + return status; + } +#endif + + switch (state) { + case SIDL: + procstate->state = 'D'; + break; + case SRUN: +#ifdef SONPROC + case SONPROC: +#endif + procstate->state = 'R'; + break; + case SSLEEP: + procstate->state = 'S'; + break; + case SSTOP: + procstate->state = 'T'; + break; + case SZOMB: + procstate->state = 'Z'; + break; + default: + procstate->state = '?'; + break; + } + + return SIGAR_OK; +} + +#if defined(DARWIN) +typedef struct { + char *buf, *ptr, *end; + int count; +} sigar_kern_proc_args_t; + +static void sigar_kern_proc_args_destroy(sigar_kern_proc_args_t *kargs) +{ + if (kargs->buf) { + free(kargs->buf); + kargs->buf = NULL; + } +} + +/* re-usable hack for use by proc_args and proc_env */ +static int sigar_kern_proc_args_get(sigar_t *sigar, + sigar_pid_t pid, + char *exe, + sigar_kern_proc_args_t *kargs) +{ + /* + * derived from: + * http://darwinsource.opendarwin.org/10.4.1/adv_cmds-79.1/ps.tproj/print.c + */ + int mib[3], len; + size_t size = sigar_argmax_get(sigar); + + kargs->buf = malloc(size); + + mib[0] = CTL_KERN; + mib[1] = KERN_PROCARGS2; + mib[2] = pid; + + if (sysctl(mib, NMIB(mib), kargs->buf, &size, NULL, 0) < 0) { + sigar_kern_proc_args_destroy(kargs); + return errno; + } + + kargs->end = &kargs->buf[size]; + + memcpy(&kargs->count, kargs->buf, sizeof(kargs->count)); + kargs->ptr = kargs->buf + sizeof(kargs->count); + + len = strlen(kargs->ptr); + if (exe) { + memcpy(exe, kargs->ptr, len+1); + } + kargs->ptr += len+1; + + if (kargs->ptr == kargs->end) { + sigar_kern_proc_args_destroy(kargs); + return exe ? SIGAR_OK : ENOENT; + } + + for (; kargs->ptr < kargs->end; kargs->ptr++) { + if (*kargs->ptr != '\0') { + break; /* start of argv[0] */ + } + } + + if (kargs->ptr == kargs->end) { + sigar_kern_proc_args_destroy(kargs); + return exe ? SIGAR_OK : ENOENT; + } + + return SIGAR_OK; +} + +static int kern_proc_args_skip_argv(sigar_kern_proc_args_t *kargs) +{ + char *ptr = kargs->ptr; + char *end = kargs->end; + int count = kargs->count; + + /* skip over argv */ + while ((ptr < end) && (count-- > 0)) { + int alen = strlen(ptr)+1; + + ptr += alen; + } + + kargs->ptr = ptr; + kargs->end = end; + kargs->count = 0; + + if (ptr >= end) { + return ENOENT; + } + + return SIGAR_OK; +} +#endif + +int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs) +{ +#if defined(DARWIN) + int status, count; + sigar_kern_proc_args_t kargs; + char *ptr, *end; + + status = sigar_kern_proc_args_get(sigar, pid, NULL, &kargs); + if (status != SIGAR_OK) { + return status; + } + + count = kargs.count; + ptr = kargs.ptr; + end = kargs.end; + + while ((ptr < end) && (count-- > 0)) { + int slen = strlen(ptr); + int alen = slen+1; + char *arg; + + /* + * trim trailing whitespace. + * seen w/ postgresql, probably related + * to messing with argv[0] + */ + while (*(ptr + (slen-1)) == ' ') { + if (--slen <= 0) { + break; + } + } + + arg = malloc(slen+1); + + SIGAR_PROC_ARGS_GROW(procargs); + memcpy(arg, ptr, slen); + *(arg+slen) = '\0'; + + procargs->data[procargs->number++] = arg; + + ptr += alen; + } + + sigar_kern_proc_args_destroy(&kargs); + return SIGAR_OK; +#elif defined(__FreeBSD__) || defined(__NetBSD__) + char buffer[SIGAR_ARG_MAX+1], *ptr=buffer; + size_t len = sizeof(buffer); +# ifdef __NetBSD__ + int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ARGV }; + mib[2] = pid; +# else + int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_ARGS, 0 }; + mib[3] = pid; +# endif + + if (sysctl(mib, NMIB(mib), buffer, &len, NULL, 0) < 0) { + return errno; + } + + if (len == 0) { + procargs->number = 0; + return SIGAR_OK; + } + + buffer[len] = '\0'; + + while (len > 0) { + int alen = strlen(ptr)+1; + char *arg = malloc(alen); + + SIGAR_PROC_ARGS_GROW(procargs); + memcpy(arg, ptr, alen); + + procargs->data[procargs->number++] = arg; + + len -= alen; + if (len > 0) { + ptr += alen; + } + } + + return SIGAR_OK; +#elif defined(__OpenBSD__) + char buffer[SIGAR_ARG_MAX+1], **ptr=(char **)buffer; + size_t len = sizeof(buffer); + int mib[] = { CTL_KERN, KERN_PROC_ARGS, 0, KERN_PROC_ARGV }; + mib[2] = pid; + + if (sysctl(mib, NMIB(mib), buffer, &len, NULL, 0) < 0) { + return errno; + } + + if (len == 0) { + procargs->number = 0; + return SIGAR_OK; + } + + for (; *ptr; ptr++) { + int alen = strlen(*ptr)+1; + char *arg = malloc(alen); + + SIGAR_PROC_ARGS_GROW(procargs); + memcpy(arg, *ptr, alen); + + procargs->data[procargs->number++] = arg; + } + + return SIGAR_OK; +#else + return SIGAR_ENOTIMPL; +#endif +} + +int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_env_t *procenv) +{ +#ifdef DARWIN + int status, count; + sigar_kern_proc_args_t kargs; + char *ptr, *end; + + status = sigar_kern_proc_args_get(sigar, pid, NULL, &kargs); + if (status != SIGAR_OK) { + return status; + } + + status = kern_proc_args_skip_argv(&kargs); + if (status != SIGAR_OK) { + sigar_kern_proc_args_destroy(&kargs); + return status; + } + + count = kargs.count; + ptr = kargs.ptr; + end = kargs.end; + + /* into environ */ + while (ptr < end) { + char *val = strchr(ptr, '='); + int klen, vlen, status; + char key[256]; /* XXX is there a max key size? */ + + if (val == NULL) { + /* not key=val format */ + break; + } + + klen = val - ptr; + SIGAR_SSTRCPY(key, ptr); + key[klen] = '\0'; + ++val; + + vlen = strlen(val); + status = procenv->env_getter(procenv->data, + key, klen, val, vlen); + + if (status != SIGAR_OK) { + /* not an error; just stop iterating */ + break; + } + + ptr += (klen + 1 + vlen + 1); + + if (*ptr == '\0') { + break; + } + } + + sigar_kern_proc_args_destroy(&kargs); + return SIGAR_OK; +#else + char **env; + struct kinfo_proc *pinfo; + int num; + + if (!sigar->kmem) { + return SIGAR_EPERM_KMEM; + } + + pinfo = kvm_getprocs(sigar->kmem, KERN_PROC_PID, pid, &num); + if (!pinfo || (num < 1)) { + return errno; + } + + if (!(env = kvm_getenvv(sigar->kmem, pinfo, 9086))) { + return errno; + } + + while (*env) { + char *ptr = *env++; + char *val = strchr(ptr, '='); + int klen, vlen, status; + char key[128]; /* XXX is there a max key size? */ + + if (val == NULL) { + /* not key=val format */ + procenv->env_getter(procenv->data, ptr, strlen(ptr), NULL, 0); + break; + } + + klen = val - ptr; + SIGAR_SSTRCPY(key, ptr); + key[klen] = '\0'; + ++val; + + vlen = strlen(val); + status = procenv->env_getter(procenv->data, + key, klen, val, vlen); + + if (status != SIGAR_OK) { + /* not an error; just stop iterating */ + break; + } + + ptr += (klen + 1 + vlen + 1); + } + + return SIGAR_OK; +#endif +} + +int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_fd_t *procfd) +{ +#ifdef __FreeBSD__ + int status; + bsd_pinfo_t *pinfo; + struct filedesc filed; +#if 0 + struct file **ofiles; + int nfiles, i; + size_t size; +#endif + if (!sigar->kmem) { + return SIGAR_EPERM_KMEM; + } + + if ((status = sigar_get_pinfo(sigar, pid)) != SIGAR_OK) { + return status; + } + pinfo = sigar->pinfo; + + status = kread(sigar, &filed, sizeof(filed), (u_long)pinfo->KI_FD); + if (status != SIGAR_OK) { + return status; + } +#if 0 + nfiles = filed.fd_lastfile+1; + size = sizeof(*ofiles) * nfiles; + ofiles = malloc(size); + status = kread(sigar, ofiles, size, (u_long)filed.fd_ofiles); + if (status != SIGAR_OK) { + free(ofiles); + return status; + } + + procfd->total = 0; + for (i=0; itotal++; + } + + free(ofiles); +#else + /* seems the same as the above */ + procfd->total = filed.fd_lastfile; +#endif + + return SIGAR_OK; +#else + return SIGAR_ENOTIMPL; +#endif +} + +int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_exe_t *procexe) +{ +#ifdef DARWIN + int status; + sigar_kern_proc_args_t kargs; + + status = sigar_kern_proc_args_get(sigar, pid, procexe->name, &kargs); + if (status != SIGAR_OK) { + return status; + } + + procexe->cwd[0] = '\0'; + procexe->root[0] = '\0'; + + /* attempt to determine cwd from $PWD */ + status = kern_proc_args_skip_argv(&kargs); + if (status == SIGAR_OK) { + char *ptr = kargs.ptr; + char *end = kargs.end; + + /* into environ */ + while (ptr < end) { + int len = strlen(ptr); + + if ((len > 4) && + (ptr[0] == 'P') && + (ptr[1] == 'W') && + (ptr[2] == 'D') && + (ptr[3] == '=')) + { + memcpy(procexe->cwd, ptr+4, len-3); + break; + } + + ptr += len+1; + } + } + + sigar_kern_proc_args_destroy(&kargs); + + return SIGAR_OK; +#else + int len; + char name[1024]; + + procexe->cwd[0] = '\0'; + procexe->root[0] = '\0'; + + (void)SIGAR_PROC_FILENAME(name, pid, "/file"); + + if ((len = readlink(name, procexe->name, + sizeof(procexe->name)-1)) < 0) + { + return PROCFS_STATUS(errno); + } + + procexe->name[len] = '\0'; + + return SIGAR_OK; +#endif +} + +#ifdef DARWIN +static int sigar_dlinfo_modules(sigar_t *sigar, sigar_proc_modules_t *procmods) +{ + uint32_t i, count = _dyld_image_count(); + + for (i=0; imodule_getter(procmods->data, + (char *)name, strlen(name)); + + if (status != SIGAR_OK) { + /* not an error; just stop iterating */ + break; + } + } + return SIGAR_OK; +} +#endif /* DARWIN */ + +int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_modules_t *procmods) +{ +#if defined(SIGAR_HAS_DLINFO_MODULES) || defined(DARWIN) + if (pid == sigar_pid_get(sigar)) { + return sigar_dlinfo_modules(sigar, procmods); + } +#endif + return SIGAR_ENOTIMPL; +} + +#define SIGAR_MICROSEC2NANO(s) \ + ((sigar_uint64_t)(s) * (sigar_uint64_t)1000) + +#define TIME_NSEC(t) \ + (SIGAR_SEC2NANO((t).tv_sec) + SIGAR_MICROSEC2NANO((t).tv_usec)) + +int sigar_thread_cpu_get(sigar_t *sigar, + sigar_uint64_t id, + sigar_thread_cpu_t *cpu) +{ +#if defined(DARWIN) + mach_port_t self = mach_thread_self(); + thread_basic_info_data_t info; + mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; + kern_return_t status; + + status = thread_info(self, THREAD_BASIC_INFO, + (thread_info_t)&info, &count); + if (status != KERN_SUCCESS) { + return errno; + } + + mach_port_deallocate(mach_task_self(), self); + + cpu->user = tval2nsec(info.user_time); + cpu->sys = tval2nsec(info.system_time); + cpu->total = cpu->user + cpu->sys; +#elif defined(__NetBSD__) + return SIGAR_ENOTIMPL; /* http://tinyurl.com/chbvln */ +#else + /* XXX this is not per-thread, it is for the whole-process. + * just want to use for the shell time command at the moment. + */ + struct rusage usage; + getrusage(RUSAGE_SELF, &usage); + + cpu->user = TIME_NSEC(usage.ru_utime); + cpu->sys = TIME_NSEC(usage.ru_stime); + cpu->total = TIME_NSEC(usage.ru_utime) + TIME_NSEC(usage.ru_stime); +#endif + + return SIGAR_OK; +} + +int sigar_os_fs_type_get(sigar_file_system_t *fsp) +{ + char *type = fsp->sys_type_name; + + /* see sys/disklabel.h */ + switch (*type) { + case 'f': + if (strEQ(type, "ffs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'h': + if (strEQ(type, "hfs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'u': + if (strEQ(type, "ufs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + } + + return fsp->type; +} + +static void get_fs_options(char *opts, int osize, long flags) +{ + *opts = '\0'; + if (flags & MNT_RDONLY) strncat(opts, "ro", osize); + else strncat(opts, "rw", osize); + if (flags & MNT_SYNCHRONOUS) strncat(opts, ",sync", osize); + if (flags & MNT_NOEXEC) strncat(opts, ",noexec", osize); + if (flags & MNT_NOSUID) strncat(opts, ",nosuid", osize); +#ifdef MNT_NODEV + if (flags & MNT_NODEV) strncat(opts, ",nodev", osize); +#endif +#ifdef MNT_UNION + if (flags & MNT_UNION) strncat(opts, ",union", osize); +#endif + if (flags & MNT_ASYNC) strncat(opts, ",async", osize); +#ifdef MNT_NOATIME + if (flags & MNT_NOATIME) strncat(opts, ",noatime", osize); +#endif +#ifdef MNT_NOCLUSTERR + if (flags & MNT_NOCLUSTERR) strncat(opts, ",noclusterr", osize); +#endif +#ifdef MNT_NOCLUSTERW + if (flags & MNT_NOCLUSTERW) strncat(opts, ",noclusterw", osize); +#endif +#ifdef MNT_NOSYMFOLLOW + if (flags & MNT_NOSYMFOLLOW) strncat(opts, ",nosymfollow", osize); +#endif +#ifdef MNT_SUIDDIR + if (flags & MNT_SUIDDIR) strncat(opts, ",suiddir", osize); +#endif +#ifdef MNT_SOFTDEP + if (flags & MNT_SOFTDEP) strncat(opts, ",soft-updates", osize); +#endif + if (flags & MNT_LOCAL) strncat(opts, ",local", osize); + if (flags & MNT_QUOTA) strncat(opts, ",quota", osize); + if (flags & MNT_ROOTFS) strncat(opts, ",rootfs", osize); +#ifdef MNT_USER + if (flags & MNT_USER) strncat(opts, ",user", osize); +#endif +#ifdef MNT_IGNORE + if (flags & MNT_IGNORE) strncat(opts, ",ignore", osize); +#endif + if (flags & MNT_EXPORTED) strncat(opts, ",nfs", osize); +} + +#ifdef __NetBSD__ +#define sigar_statfs statvfs +#define sigar_getfsstat getvfsstat +#define sigar_f_flags f_flag +#else +#define sigar_statfs statfs +#define sigar_getfsstat getfsstat +#define sigar_f_flags f_flags +#endif + +int sigar_file_system_list_get(sigar_t *sigar, + sigar_file_system_list_t *fslist) +{ + struct sigar_statfs *fs; + int num, i; + int is_debug = SIGAR_LOG_IS_DEBUG(sigar); + long len; + + if ((num = sigar_getfsstat(NULL, 0, MNT_NOWAIT)) < 0) { + return errno; + } + + len = sizeof(*fs) * num; + fs = malloc(len); + + if ((num = sigar_getfsstat(fs, len, MNT_NOWAIT)) < 0) { + free(fs); + return errno; + } + + sigar_file_system_list_create(fslist); + + for (i=0; idata[fslist->number++]; + + SIGAR_SSTRCPY(fsp->dir_name, fs[i].f_mntonname); + SIGAR_SSTRCPY(fsp->dev_name, fs[i].f_mntfromname); + SIGAR_SSTRCPY(fsp->sys_type_name, fs[i].f_fstypename); + get_fs_options(fsp->options, sizeof(fsp->options)-1, fs[i].sigar_f_flags); + + sigar_fs_type_init(fsp); + } + + free(fs); + return SIGAR_OK; +} + +#ifdef DARWIN +#define IoStatGetValue(key, val) \ + if ((number = (CFNumberRef)CFDictionaryGetValue(stats, CFSTR(kIOBlockStorageDriverStatistics##key)))) \ + CFNumberGetValue(number, kCFNumberSInt64Type, &val) +#endif + +int sigar_disk_usage_get(sigar_t *sigar, const char *name, + sigar_disk_usage_t *disk) +{ +#if defined(DARWIN) + kern_return_t status; + io_registry_entry_t parent; + io_service_t service; + CFDictionaryRef props; + CFNumberRef number; + sigar_iodev_t *iodev = sigar_iodev_get(sigar, name); + char dname[256], *ptr; + + SIGAR_DISK_STATS_INIT(disk); + + if (!iodev) { + return ENXIO; + } + + /* "/dev/disk0s1" -> "disk0" */ /* XXX better way? */ + ptr = &iodev->name[SSTRLEN(SIGAR_DEV_PREFIX)]; + SIGAR_SSTRCPY(dname, ptr); + ptr = dname; + if (strnEQ(ptr, "disk", 4)) { + ptr += 4; + if ((ptr = strchr(ptr, 's')) && isdigit(*(ptr+1))) { + *ptr = '\0'; + } + } + + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[disk_usage] map %s -> %s", + iodev->name, dname); + } + + /* e.g. name == "disk0" */ + service = IOServiceGetMatchingService(kIOMasterPortDefault, + IOBSDNameMatching(kIOMasterPortDefault, 0, dname)); + + if (!service) { + return errno; + } + + status = IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent); + if (status != KERN_SUCCESS) { + IOObjectRelease(service); + return status; + } + + status = IORegistryEntryCreateCFProperties(parent, + (CFMutableDictionaryRef *)&props, + kCFAllocatorDefault, + kNilOptions); + if (props) { + CFDictionaryRef stats = + (CFDictionaryRef)CFDictionaryGetValue(props, + CFSTR(kIOBlockStorageDriverStatisticsKey)); + + if (stats) { + IoStatGetValue(ReadsKey, disk->reads); + IoStatGetValue(BytesReadKey, disk->read_bytes); + IoStatGetValue(TotalReadTimeKey, disk->rtime); + IoStatGetValue(WritesKey, disk->writes); + IoStatGetValue(BytesWrittenKey, disk->write_bytes); + IoStatGetValue(TotalWriteTimeKey, disk->wtime); + disk->time = disk->rtime + disk->wtime; + } + + CFRelease(props); + } + + IOObjectRelease(service); + IOObjectRelease(parent); + + return SIGAR_OK; +#elif defined(__FreeBSD__) + /* XXX incomplete */ + struct sigar_statfs buf; + + if (sigar_statfs(name, &buf) < 0) { + return errno; + } + + SIGAR_DISK_STATS_INIT(disk); + + disk->reads = buf.f_syncreads + buf.f_asyncreads; + disk->writes = buf.f_syncwrites + buf.f_asyncwrites; + return SIGAR_OK; +#else + SIGAR_DISK_STATS_INIT(disk); + return SIGAR_ENOTIMPL; +#endif +} + +int sigar_file_system_usage_get(sigar_t *sigar, + const char *dirname, + sigar_file_system_usage_t *fsusage) +{ + int status = sigar_statvfs(sigar, dirname, fsusage); + + if (status != SIGAR_OK) { + return status; + } + + fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage); + + sigar_disk_usage_get(sigar, dirname, &fsusage->disk); + + return SIGAR_OK; +} + +#ifdef DARWIN +#define CTL_HW_FREQ_MAX "hw.cpufrequency_max" +#define CTL_HW_FREQ_MIN "hw.cpufrequency_min" +#else +/* XXX FreeBSD 5.x+ only? */ +#define CTL_HW_FREQ "machdep.tsc_freq" +#endif + +int sigar_cpu_info_list_get(sigar_t *sigar, + sigar_cpu_info_list_t *cpu_infos) +{ + int i; + unsigned int mhz, mhz_min, mhz_max; + int cache_size=SIGAR_FIELD_NOTIMPL; + size_t size; + char model[128], vendor[128], *ptr; + + size = sizeof(mhz); + + (void)sigar_cpu_core_count(sigar); + +#if defined(DARWIN) + { + int mib[] = { CTL_HW, HW_CPU_FREQ }; + size = sizeof(mhz); + if (sysctl(mib, NMIB(mib), &mhz, &size, NULL, 0) < 0) { + mhz = SIGAR_FIELD_NOTIMPL; + } + } + if (sysctlbyname(CTL_HW_FREQ_MAX, &mhz_max, &size, NULL, 0) < 0) { + mhz_max = SIGAR_FIELD_NOTIMPL; + } + if (sysctlbyname(CTL_HW_FREQ_MIN, &mhz_min, &size, NULL, 0) < 0) { + mhz_min = SIGAR_FIELD_NOTIMPL; + } +#elif defined(__FreeBSD__) + if (sysctlbyname(CTL_HW_FREQ, &mhz, &size, NULL, 0) < 0) { + mhz = SIGAR_FIELD_NOTIMPL; + } + /* TODO */ + mhz_max = SIGAR_FIELD_NOTIMPL; + mhz_min = SIGAR_FIELD_NOTIMPL; +#else + /*XXX OpenBSD*/ + mhz = SIGAR_FIELD_NOTIMPL; + mhz_max = SIGAR_FIELD_NOTIMPL; + mhz_min = SIGAR_FIELD_NOTIMPL; +#endif + + if (mhz != SIGAR_FIELD_NOTIMPL) { + mhz /= 1000000; + } + if (mhz_max != SIGAR_FIELD_NOTIMPL) { + mhz_max /= 1000000; + } + if (mhz_min != SIGAR_FIELD_NOTIMPL) { + mhz_min /= 1000000; + } + + size = sizeof(model); +#ifdef __OpenBSD__ + if (1) { +#else + if (sysctlbyname("hw.model", &model, &size, NULL, 0) < 0) { +#endif + int mib[] = { CTL_HW, HW_MODEL }; + size = sizeof(model); + if (sysctl(mib, NMIB(mib), &model[0], &size, NULL, 0) < 0) { +#ifdef DARWIN + strcpy(model, "powerpc"); +#else + strcpy(model, "Unknown"); +#endif + } + } + + if (mhz == SIGAR_FIELD_NOTIMPL) { + /* freebsd4 */ + mhz = sigar_cpu_mhz_from_model(model); + } + /* XXX not sure */ + if (mhz_max == SIGAR_FIELD_NOTIMPL) { + mhz_max = 0; + } + if (mhz_min == SIGAR_FIELD_NOTIMPL) { + mhz_min = 0; + } + + +#ifdef DARWIN + size = sizeof(vendor); + if (sysctlbyname("machdep.cpu.vendor", &vendor, &size, NULL, 0) < 0) { + SIGAR_SSTRCPY(vendor, "Apple"); + } + else { + /* GenuineIntel -> Intel */ + if (strstr(vendor, "Intel")) { + SIGAR_SSTRCPY(vendor, "Intel"); + } + } +#endif + + if ((ptr = strchr(model, ' '))) { + if (strstr(model, "Intel")) { + SIGAR_SSTRCPY(vendor, "Intel"); + } + else if (strstr(model, "AMD")) { + SIGAR_SSTRCPY(vendor, "AMD"); + } + else { + SIGAR_SSTRCPY(vendor, "Unknown"); + } + SIGAR_SSTRCPY(model, ptr+1); + } + +#ifdef DARWIN + { + int mib[] = { CTL_HW, HW_L2CACHESIZE }; /* in bytes */ + size = sizeof(cache_size); + if (sysctl(mib, NMIB(mib), &cache_size, &size, NULL, 0) < 0) { + cache_size = SIGAR_FIELD_NOTIMPL; + } + else { + cache_size /= 1024; /* convert to KB */ + } + } +#endif + + sigar_cpu_info_list_create(cpu_infos); + + for (i=0; incpu; i++) { + sigar_cpu_info_t *info; + + SIGAR_CPU_INFO_LIST_GROW(cpu_infos); + + info = &cpu_infos->data[cpu_infos->number++]; + + SIGAR_SSTRCPY(info->vendor, vendor); + SIGAR_SSTRCPY(info->model, model); + sigar_cpu_model_adjust(sigar, info); + + info->mhz = mhz; + info->mhz_max = mhz_max; + info->mhz_min = mhz_min; + info->cache_size = cache_size; + info->total_cores = sigar->ncpu; + info->cores_per_socket = sigar->lcpu; + info->total_sockets = sigar_cpu_socket_count(sigar); + } + + return SIGAR_OK; +} + +#define rt_s_addr(sa) ((struct sockaddr_in *)(sa))->sin_addr.s_addr + +#ifndef SA_SIZE +#define SA_SIZE(sa) \ + ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ + sizeof(long) : \ + 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) +#endif + +int sigar_net_route_list_get(sigar_t *sigar, + sigar_net_route_list_t *routelist) +{ + size_t needed; + int bit; + char *buf, *next, *lim; + struct rt_msghdr *rtm; + int mib[6] = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_DUMP, 0 }; + + if (sysctl(mib, NMIB(mib), NULL, &needed, NULL, 0) < 0) { + return errno; + } +#if __FreeBSD_version >= 800000 + if (needed == 0) { + return SIGAR_ENOTIMPL; /*XXX hoping this is an 8.0beta bug*/ + } +#endif + buf = malloc(needed); + + if (sysctl(mib, NMIB(mib), buf, &needed, NULL, 0) < 0) { + free(buf); + return errno; + } + + sigar_net_route_list_create(routelist); + + lim = buf + needed; + for (next = buf; next < lim; next += rtm->rtm_msglen) { + struct sockaddr *sa; + sigar_net_route_t *route; + rtm = (struct rt_msghdr *)next; + + if (rtm->rtm_type != RTM_GET) { + continue; + } + + sa = (struct sockaddr *)(rtm + 1); + + if (sa->sa_family != AF_INET) { + continue; + } + + SIGAR_NET_ROUTE_LIST_GROW(routelist); + route = &routelist->data[routelist->number++]; + SIGAR_ZERO(route); + + route->flags = rtm->rtm_flags; + if_indextoname(rtm->rtm_index, route->ifname); + + for (bit=RTA_DST; + bit && ((char *)sa < lim); + bit <<= 1) + { + if ((rtm->rtm_addrs & bit) == 0) { + continue; + } + switch (bit) { + case RTA_DST: + sigar_net_address_set(route->destination, + rt_s_addr(sa)); + break; + case RTA_GATEWAY: + if (sa->sa_family == AF_INET) { + sigar_net_address_set(route->gateway, + rt_s_addr(sa)); + } + break; + case RTA_NETMASK: + sigar_net_address_set(route->mask, + rt_s_addr(sa)); + break; + case RTA_IFA: + break; + } + + sa = (struct sockaddr *)((char *)sa + SA_SIZE(sa)); + } + } + + free(buf); + + return SIGAR_OK; +} + +typedef enum { + IFMSG_ITER_LIST, + IFMSG_ITER_GET +} ifmsg_iter_e; + +typedef struct { + const char *name; + ifmsg_iter_e type; + union { + sigar_net_interface_list_t *iflist; + struct if_msghdr *ifm; + } data; +} ifmsg_iter_t; + +static int sigar_ifmsg_init(sigar_t *sigar) +{ + int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_IFLIST, 0 }; + size_t len; + + if (sysctl(mib, NMIB(mib), NULL, &len, NULL, 0) < 0) { + return errno; + } + + if (sigar->ifconf_len < len) { + sigar->ifconf_buf = realloc(sigar->ifconf_buf, len); + sigar->ifconf_len = len; + } + + if (sysctl(mib, NMIB(mib), sigar->ifconf_buf, &len, NULL, 0) < 0) { + return errno; + } + + return SIGAR_OK; +} + +/** + * @param name name of the interface + * @param name_len length of name (w/o \0) + */ +static int has_ifaddr(char *name, size_t name_len) +{ + int sock, status; + struct ifreq ifr; + + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + return errno; + } + strncpy(ifr.ifr_name, name, MIN(sizeof(ifr.ifr_name) - 1, name_len)); + ifr.ifr_name[MIN(sizeof(ifr.ifr_name) - 1, name_len)] = '\0'; + if (ioctl(sock, SIOCGIFADDR, &ifr) == 0) { + status = SIGAR_OK; + } + else { + status = errno; + } + + close(sock); + return status; +} + +static int sigar_ifmsg_iter(sigar_t *sigar, ifmsg_iter_t *iter) +{ + char *end = sigar->ifconf_buf + sigar->ifconf_len; + char *ptr = sigar->ifconf_buf; + + if (iter->type == IFMSG_ITER_LIST) { + sigar_net_interface_list_create(iter->data.iflist); + } + + while (ptr < end) { + char *name; + struct sockaddr_dl *sdl; + struct if_msghdr *ifm = (struct if_msghdr *)ptr; + + if (ifm->ifm_type != RTM_IFINFO) { + break; + } + + ptr += ifm->ifm_msglen; + + while (ptr < end) { + struct if_msghdr *next = (struct if_msghdr *)ptr; + + if (next->ifm_type != RTM_NEWADDR) { + break; + } + + ptr += next->ifm_msglen; + } + + sdl = (struct sockaddr_dl *)(ifm + 1); + if (sdl->sdl_family != AF_LINK) { + continue; + } + + switch (iter->type) { + case IFMSG_ITER_LIST: + if (sdl->sdl_type == IFT_OTHER) { + if (has_ifaddr(sdl->sdl_data, sdl->sdl_nlen) != SIGAR_OK) { + break; + } + } + else if (!((sdl->sdl_type == IFT_ETHER) || + (sdl->sdl_type == IFT_LOOP))) + { + break; /* XXX deal w/ other weirdo interfaces */ + } + + SIGAR_NET_IFLIST_GROW(iter->data.iflist); + + /* sdl_data doesn't include a trailing \0, it is only sdl_nlen long */ + name = malloc(sdl->sdl_nlen+1); + memcpy(name, sdl->sdl_data, sdl->sdl_nlen); + name[sdl->sdl_nlen] = '\0'; /* add the missing \0 */ + + iter->data.iflist->data[iter->data.iflist->number++] = name; + break; + + case IFMSG_ITER_GET: + if (strlen(iter->name) == sdl->sdl_nlen && 0 == memcmp(iter->name, sdl->sdl_data, sdl->sdl_nlen)) { + iter->data.ifm = ifm; + return SIGAR_OK; + } + } + } + + switch (iter->type) { + case IFMSG_ITER_LIST: + return SIGAR_OK; + + case IFMSG_ITER_GET: + default: + return ENXIO; + } +} + +int sigar_net_interface_list_get(sigar_t *sigar, + sigar_net_interface_list_t *iflist) +{ + int status; + ifmsg_iter_t iter; + + if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) { + return status; + } + + iter.type = IFMSG_ITER_LIST; + iter.data.iflist = iflist; + + return sigar_ifmsg_iter(sigar, &iter); +} + +#include + +/* in6_prefixlen derived from freebsd/sbin/ifconfig/af_inet6.c */ +static int sigar_in6_prefixlen(struct sockaddr *netmask) +{ + struct in6_addr *addr = SIGAR_SIN6_ADDR(netmask); + u_char *name = (u_char *)addr; + int size = sizeof(*addr); + int byte, bit, plen = 0; + + for (byte = 0; byte < size; byte++, plen += 8) { + if (name[byte] != 0xff) { + break; + } + } + if (byte == size) { + return plen; + } + for (bit = 7; bit != 0; bit--, plen++) { + if (!(name[byte] & (1 << bit))) { + break; + } + } + for (; bit != 0; bit--) { + if (name[byte] & (1 << bit)) { + return 0; + } + } + byte++; + for (; byte < size; byte++) { + if (name[byte]) { + return 0; + } + } + return plen; +} + +int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig) +{ + int status = SIGAR_ENOENT; + struct ifaddrs *addrs, *ifa; + + if (getifaddrs(&addrs) != 0) { + return errno; + } + + for (ifa=addrs; ifa; ifa=ifa->ifa_next) { + if (ifa->ifa_addr && + (ifa->ifa_addr->sa_family == AF_INET6) && + strEQ(ifa->ifa_name, name)) + { + status = SIGAR_OK; + break; + } + } + + if (status == SIGAR_OK) { + struct in6_addr *addr = SIGAR_SIN6_ADDR(ifa->ifa_addr); + + sigar_net_address6_set(ifconfig->address6, addr); + sigar_net_interface_scope6_set(ifconfig, addr); + ifconfig->prefix6_length = sigar_in6_prefixlen(ifa->ifa_netmask); + } + + freeifaddrs(addrs); + + return status; +} + +int sigar_net_interface_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig) +{ + int sock; + int status; + ifmsg_iter_t iter; + struct if_msghdr *ifm; + struct sockaddr_dl *sdl; + struct ifreq ifr; + + if (!name) { + return sigar_net_interface_config_primary_get(sigar, ifconfig); + } + + if (sigar->ifconf_len == 0) { + if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) { + return status; + } + } + + SIGAR_ZERO(ifconfig); + + iter.type = IFMSG_ITER_GET; + iter.name = name; + + if ((status = sigar_ifmsg_iter(sigar, &iter)) != SIGAR_OK) { + return status; + } + + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + return errno; + } + + ifm = iter.data.ifm; + + SIGAR_SSTRCPY(ifconfig->name, name); + + sdl = (struct sockaddr_dl *)(ifm + 1); + + sigar_net_address_mac_set(ifconfig->hwaddr, + LLADDR(sdl), + sdl->sdl_alen); + + ifconfig->flags = ifm->ifm_flags; + ifconfig->mtu = ifm->ifm_data.ifi_mtu; + ifconfig->metric = ifm->ifm_data.ifi_metric; + + SIGAR_SSTRCPY(ifr.ifr_name, name); + +#define ifr_s_addr(ifr) \ + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr + + if (!ioctl(sock, SIOCGIFADDR, &ifr)) { + sigar_net_address_set(ifconfig->address, + ifr_s_addr(ifr)); + } + + if (!ioctl(sock, SIOCGIFNETMASK, &ifr)) { + sigar_net_address_set(ifconfig->netmask, + ifr_s_addr(ifr)); + } + + if (ifconfig->flags & IFF_LOOPBACK) { + sigar_net_address_set(ifconfig->destination, + ifconfig->address.addr.in); + sigar_net_address_set(ifconfig->broadcast, 0); + SIGAR_SSTRCPY(ifconfig->type, + SIGAR_NIC_LOOPBACK); + } + else { + if (!ioctl(sock, SIOCGIFDSTADDR, &ifr)) { + sigar_net_address_set(ifconfig->destination, + ifr_s_addr(ifr)); + } + + if (!ioctl(sock, SIOCGIFBRDADDR, &ifr)) { + sigar_net_address_set(ifconfig->broadcast, + ifr_s_addr(ifr)); + } + SIGAR_SSTRCPY(ifconfig->type, + SIGAR_NIC_ETHERNET); + } + + close(sock); + + /* XXX can we get a better description like win32? */ + SIGAR_SSTRCPY(ifconfig->description, + ifconfig->name); + + sigar_net_interface_ipv6_config_init(ifconfig); + sigar_net_interface_ipv6_config_get(sigar, name, ifconfig); + + return SIGAR_OK; +} + +int sigar_net_interface_stat_get(sigar_t *sigar, const char *name, + sigar_net_interface_stat_t *ifstat) +{ + int status; + ifmsg_iter_t iter; + struct if_msghdr *ifm; + + if ((status = sigar_ifmsg_init(sigar)) != SIGAR_OK) { + return status; + } + + iter.type = IFMSG_ITER_GET; + iter.name = name; + + if ((status = sigar_ifmsg_iter(sigar, &iter)) != SIGAR_OK) { + return status; + } + + ifm = iter.data.ifm; + + ifstat->rx_bytes = ifm->ifm_data.ifi_ibytes; + ifstat->rx_packets = ifm->ifm_data.ifi_ipackets; + ifstat->rx_errors = ifm->ifm_data.ifi_ierrors; + ifstat->rx_dropped = ifm->ifm_data.ifi_iqdrops; + ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL; + ifstat->rx_frame = SIGAR_FIELD_NOTIMPL; + + ifstat->tx_bytes = ifm->ifm_data.ifi_obytes; + ifstat->tx_packets = ifm->ifm_data.ifi_opackets; + ifstat->tx_errors = ifm->ifm_data.ifi_oerrors; + ifstat->tx_collisions = ifm->ifm_data.ifi_collisions; + ifstat->tx_dropped = SIGAR_FIELD_NOTIMPL; + ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL; + ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL; + + ifstat->speed = ifm->ifm_data.ifi_baudrate; + + return SIGAR_OK; +} + +static int net_connection_state_get(int state) +{ + switch (state) { + case TCPS_CLOSED: + return SIGAR_TCP_CLOSE; + case TCPS_LISTEN: + return SIGAR_TCP_LISTEN; + case TCPS_SYN_SENT: + return SIGAR_TCP_SYN_SENT; + case TCPS_SYN_RECEIVED: + return SIGAR_TCP_SYN_RECV; + case TCPS_ESTABLISHED: + return SIGAR_TCP_ESTABLISHED; + case TCPS_CLOSE_WAIT: + return SIGAR_TCP_CLOSE_WAIT; + case TCPS_FIN_WAIT_1: + return SIGAR_TCP_FIN_WAIT1; + case TCPS_CLOSING: + return SIGAR_TCP_CLOSING; + case TCPS_LAST_ACK: + return SIGAR_TCP_LAST_ACK; + case TCPS_FIN_WAIT_2: + return SIGAR_TCP_FIN_WAIT2; + case TCPS_TIME_WAIT: + return SIGAR_TCP_TIME_WAIT; + default: + return SIGAR_TCP_UNKNOWN; + } +} + +#if defined(__OpenBSD__) || defined(__NetBSD__) +static int net_connection_get(sigar_net_connection_walker_t *walker, int proto) +{ + int status; + int istcp = 0, type; + int flags = walker->flags; + struct inpcbtable table; + struct inpcb *head, *next, *prev; + sigar_t *sigar = walker->sigar; + u_long offset; + + switch (proto) { + case IPPROTO_TCP: + offset = sigar->koffsets[KOFFSET_TCBTABLE]; + istcp = 1; + type = SIGAR_NETCONN_TCP; + break; + case IPPROTO_UDP: + default: + return SIGAR_ENOTIMPL; + } + + + status = kread(sigar, &table, sizeof(table), offset); + + if (status != SIGAR_OK) { + return status; + } + + prev = head = + (struct inpcb *)&CIRCLEQ_FIRST(&((struct inpcbtable *)offset)->inpt_queue); + + next = (struct inpcb *)CIRCLEQ_FIRST(&table.inpt_queue); + + while (next != head) { + struct inpcb inpcb; + struct tcpcb tcpcb; + struct socket socket; + + status = kread(sigar, &inpcb, sizeof(inpcb), (long)next); + prev = next; + next = (struct inpcb *)CIRCLEQ_NEXT(&inpcb, inp_queue); + + kread(sigar, &socket, sizeof(socket), (u_long)inpcb.inp_socket); + + if ((((flags & SIGAR_NETCONN_SERVER) && socket.so_qlimit) || + ((flags & SIGAR_NETCONN_CLIENT) && !socket.so_qlimit))) + { + sigar_net_connection_t conn; + + SIGAR_ZERO(&conn); + + if (istcp) { + kread(sigar, &tcpcb, sizeof(tcpcb), (u_long)inpcb.inp_ppcb); + } + +#ifdef __NetBSD__ + if (inpcb.inp_af == AF_INET6) { + /*XXX*/ + continue; + } +#else + if (inpcb.inp_flags & INP_IPV6) { + sigar_net_address6_set(conn.local_address, + &inpcb.inp_laddr6.s6_addr); + + sigar_net_address6_set(conn.remote_address, + &inpcb.inp_faddr6.s6_addr); + } +#endif + else { + sigar_net_address_set(conn.local_address, + inpcb.inp_laddr.s_addr); + + sigar_net_address_set(conn.remote_address, + inpcb.inp_faddr.s_addr); + } + + conn.local_port = ntohs(inpcb.inp_lport); + conn.remote_port = ntohs(inpcb.inp_fport); + conn.receive_queue = socket.so_rcv.sb_cc; + conn.send_queue = socket.so_snd.sb_cc; + conn.uid = socket.so_pgid; + conn.type = type; + + if (!istcp) { + conn.state = SIGAR_TCP_UNKNOWN; + if (walker->add_connection(walker, &conn) != SIGAR_OK) { + break; + } + continue; + } + + conn.state = net_connection_state_get(tcpcb.t_state); + + if (walker->add_connection(walker, &conn) != SIGAR_OK) { + break; + } + } + } + + return SIGAR_OK; +} +#else +static int net_connection_get(sigar_net_connection_walker_t *walker, int proto) +{ + int flags = walker->flags; + int type, istcp = 0; + char *buf; + const char *mibvar; + struct tcpcb *tp = NULL; + struct inpcb *inp; + struct xinpgen *xig, *oxig; + struct xsocket *so; + size_t len; + + switch (proto) { + case IPPROTO_TCP: + mibvar = "net.inet.tcp.pcblist"; + istcp = 1; + type = SIGAR_NETCONN_TCP; + break; + case IPPROTO_UDP: + mibvar = "net.inet.udp.pcblist"; + type = SIGAR_NETCONN_UDP; + break; + default: + mibvar = "net.inet.raw.pcblist"; + type = SIGAR_NETCONN_RAW; + break; + } + + len = 0; + if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) { + return errno; + } + if ((buf = malloc(len)) == 0) { + return errno; + } + if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) { + free(buf); + return errno; + } + + oxig = xig = (struct xinpgen *)buf; + for (xig = (struct xinpgen *)((char *)xig + xig->xig_len); + xig->xig_len > sizeof(struct xinpgen); + xig = (struct xinpgen *)((char *)xig + xig->xig_len)) + { + if (istcp) { + struct xtcpcb *cb = (struct xtcpcb *)xig; + tp = &cb->xt_tp; + inp = &cb->xt_inp; + so = &cb->xt_socket; + } + else { + struct xinpcb *cb = (struct xinpcb *)xig; + inp = &cb->xi_inp; + so = &cb->xi_socket; + } + + if (so->xso_protocol != proto) { + continue; + } + + if (inp->inp_gencnt > oxig->xig_gen) { + continue; + } + + if ((((flags & SIGAR_NETCONN_SERVER) && so->so_qlimit) || + ((flags & SIGAR_NETCONN_CLIENT) && !so->so_qlimit))) + { + sigar_net_connection_t conn; + + SIGAR_ZERO(&conn); + + if (inp->inp_vflag & INP_IPV6) { + sigar_net_address6_set(conn.local_address, + &inp->in6p_laddr.s6_addr); + + sigar_net_address6_set(conn.remote_address, + &inp->in6p_faddr.s6_addr); + } + else { + sigar_net_address_set(conn.local_address, + inp->inp_laddr.s_addr); + + sigar_net_address_set(conn.remote_address, + inp->inp_faddr.s_addr); + } + + conn.local_port = ntohs(inp->inp_lport); + conn.remote_port = ntohs(inp->inp_fport); + conn.receive_queue = so->so_rcv.sb_cc; + conn.send_queue = so->so_snd.sb_cc; + conn.uid = so->so_pgid; + conn.type = type; + + if (!istcp) { + conn.state = SIGAR_TCP_UNKNOWN; + if (walker->add_connection(walker, &conn) != SIGAR_OK) { + break; + } + continue; + } + + conn.state = net_connection_state_get(tp->t_state); + + if (walker->add_connection(walker, &conn) != SIGAR_OK) { + break; + } + } + } + + free(buf); + + return SIGAR_OK; +} +#endif + +int sigar_net_connection_walk(sigar_net_connection_walker_t *walker) +{ + int flags = walker->flags; + int status; + + if (flags & SIGAR_NETCONN_TCP) { + status = net_connection_get(walker, IPPROTO_TCP); + if (status != SIGAR_OK) { + return status; + } + } + if (flags & SIGAR_NETCONN_UDP) { + status = net_connection_get(walker, IPPROTO_UDP); + if (status != SIGAR_OK) { + return status; + } + } + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) +sigar_tcp_get(sigar_t *sigar, + sigar_tcp_t *tcp) +{ + struct tcpstat mib; +#if !defined(TCPCTL_STATS) && (defined(__OpenBSD__) || defined(__NetBSD__)) + int status = + kread(sigar, &mib, sizeof(mib), + sigar->koffsets[KOFFSET_TCPSTAT]); + if (status != SIGAR_OK) { + return status; + } +#else + int var[4] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_STATS }; + size_t len = sizeof(mib); + + if (sysctl(var, NMIB(var), &mib, &len, NULL, 0) < 0) { + return errno; + } +#endif + + tcp->active_opens = mib.tcps_connattempt; + tcp->passive_opens = mib.tcps_accepts; + tcp->attempt_fails = mib.tcps_conndrops; + tcp->estab_resets = mib.tcps_drops; + if (sigar_tcp_curr_estab(sigar, tcp) != SIGAR_OK) { + tcp->curr_estab = -1; + } + tcp->in_segs = mib.tcps_rcvtotal; + tcp->out_segs = mib.tcps_sndtotal - mib.tcps_sndrexmitpack; + tcp->retrans_segs = mib.tcps_sndrexmitpack; + tcp->in_errs = + mib.tcps_rcvbadsum + + mib.tcps_rcvbadoff + + mib.tcps_rcvmemdrop + + mib.tcps_rcvshort; + tcp->out_rsts = -1; /* XXX mib.tcps_sndctrl - mib.tcps_closed; ? */ + + return SIGAR_OK; +} + +#ifndef SIGAR_FREEBSD5_NFSSTAT +static int get_nfsstats(struct nfsstats *stats) +{ + size_t len = sizeof(*stats); + int mib[] = { CTL_VFS, 2, NFS_NFSSTATS }; + + if (sysctl(mib, NMIB(mib), stats, &len, NULL, 0) < 0) { + return errno; + } + else { + return SIGAR_OK; + } +} +#endif + +#if defined(__OpenBSD__) +typedef uint64_t rpc_cnt_t; +#else +typedef int rpc_cnt_t; +#endif + +static void map_nfs_stats(sigar_nfs_v3_t *nfs, rpc_cnt_t *rpc) +{ + nfs->null = rpc[NFSPROC_NULL]; + nfs->getattr = rpc[NFSPROC_GETATTR]; + nfs->setattr = rpc[NFSPROC_SETATTR]; + nfs->lookup = rpc[NFSPROC_LOOKUP]; + nfs->access = rpc[NFSPROC_ACCESS]; + nfs->readlink = rpc[NFSPROC_READLINK]; + nfs->read = rpc[NFSPROC_READ]; + nfs->write = rpc[NFSPROC_WRITE]; + nfs->create = rpc[NFSPROC_CREATE]; + nfs->mkdir = rpc[NFSPROC_MKDIR]; + nfs->symlink = rpc[NFSPROC_SYMLINK]; + nfs->mknod = rpc[NFSPROC_MKNOD]; + nfs->remove = rpc[NFSPROC_REMOVE]; + nfs->rmdir = rpc[NFSPROC_RMDIR]; + nfs->rename = rpc[NFSPROC_RENAME]; + nfs->link = rpc[NFSPROC_LINK]; + nfs->readdir = rpc[NFSPROC_READDIR]; + nfs->readdirplus = rpc[NFSPROC_READDIRPLUS]; + nfs->fsstat = rpc[NFSPROC_FSSTAT]; + nfs->fsinfo = rpc[NFSPROC_FSINFO]; + nfs->pathconf = rpc[NFSPROC_PATHCONF]; + nfs->commit = rpc[NFSPROC_COMMIT]; +} + +int sigar_nfs_client_v2_get(sigar_t *sigar, + sigar_nfs_client_v2_t *nfs) +{ + return SIGAR_ENOTIMPL; +} + +int sigar_nfs_server_v2_get(sigar_t *sigar, + sigar_nfs_server_v2_t *nfs) +{ + return SIGAR_ENOTIMPL; +} + +int sigar_nfs_client_v3_get(sigar_t *sigar, + sigar_nfs_client_v3_t *nfs) +{ +#ifdef SIGAR_FREEBSD5_NFSSTAT + struct nfsstats stats; + size_t size = sizeof(stats); + + if (sysctlbyname("vfs.nfs.nfsstats", &stats, &size, NULL, 0) == -1) { + return errno; + } + + map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.rpccnt[0]); +#else + int status; + struct nfsstats stats; + + if ((status = get_nfsstats(&stats)) != SIGAR_OK) { + return status; + } + + map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.rpccnt[0]); +#endif + + return SIGAR_OK; +} + +int sigar_nfs_server_v3_get(sigar_t *sigar, + sigar_nfs_server_v3_t *nfs) +{ +#ifdef SIGAR_FREEBSD5_NFSSTAT + struct nfsrvstats stats; + size_t size = sizeof(stats); + + if (sysctlbyname("vfs.nfsrv.nfsrvstats", &stats, &size, NULL, 0) == -1) { + return errno; + } + + map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.srvrpccnt[0]); +#else + int status; + struct nfsstats stats; + + if ((status = get_nfsstats(&stats)) != SIGAR_OK) { + return status; + } + + map_nfs_stats((sigar_nfs_v3_t *)nfs, &stats.srvrpccnt[0]); +#endif + + return SIGAR_OK; +} + +static char *get_hw_type(int type) +{ + switch (type) { + case IFT_ETHER: + return "ether"; + case IFT_ISO88025: + return "tr"; + case IFT_FDDI: + return "fddi"; + case IFT_ATM: + return "atm"; + case IFT_L2VLAN: + return "vlan"; + case IFT_IEEE1394: + return "firewire"; +#ifdef IFT_BRIDGE + case IFT_BRIDGE: + return "bridge"; +#endif + default: + return "unknown"; + } +} + +int sigar_arp_list_get(sigar_t *sigar, + sigar_arp_list_t *arplist) +{ + size_t needed; + char *lim, *buf, *next; + struct rt_msghdr *rtm; + struct sockaddr_inarp *sin; + struct sockaddr_dl *sdl; + int mib[] = { CTL_NET, PF_ROUTE, 0, AF_INET, NET_RT_FLAGS, RTF_LLINFO }; + + if (sysctl(mib, NMIB(mib), NULL, &needed, NULL, 0) < 0) { + return errno; + } + + if (needed == 0) { /* empty cache */ + return 0; + } + + buf = malloc(needed); + + if (sysctl(mib, NMIB(mib), buf, &needed, NULL, 0) < 0) { + free(buf); + return errno; + } + + sigar_arp_list_create(arplist); + + lim = buf + needed; + for (next = buf; next < lim; next += rtm->rtm_msglen) { + sigar_arp_t *arp; + + SIGAR_ARP_LIST_GROW(arplist); + arp = &arplist->data[arplist->number++]; + + rtm = (struct rt_msghdr *)next; + sin = (struct sockaddr_inarp *)(rtm + 1); + sdl = (struct sockaddr_dl *)((char *)sin + SA_SIZE(sin)); + + sigar_net_address_set(arp->address, sin->sin_addr.s_addr); + sigar_net_address_mac_set(arp->hwaddr, LLADDR(sdl), sdl->sdl_alen); + if_indextoname(sdl->sdl_index, arp->ifname); + arp->flags = rtm->rtm_flags; + + SIGAR_SSTRCPY(arp->type, get_hw_type(sdl->sdl_type)); + } + + free(buf); + + return SIGAR_OK; +} + +#if defined(__FreeBSD__) && /*XXX*/ (__FreeBSD_version < 800000) + +#define _KERNEL +#include +#undef _KERNEL + +/* derived from + * /usr/ports/security/pidentd/work/pidentd-3.0.16/src/k_freebsd2.c + */ +int sigar_proc_port_get(sigar_t *sigar, int protocol, + unsigned long port, sigar_pid_t *pid) +{ + struct nlist nl[2]; + struct inpcbhead tcb; + struct socket *sockp = NULL; + struct kinfo_proc *pinfo; + struct inpcb *head, pcbp; + int i, nentries, status; + + if (protocol != SIGAR_NETCONN_TCP) { + return SIGAR_ENOTIMPL; + } + + if (!sigar->kmem) { + return SIGAR_EPERM_KMEM; + } + + nl[0].n_name = "_tcb"; /* XXX cache */ + nl[1].n_name = ""; + if (kvm_nlist(sigar->kmem, nl) < 0) { + return errno; + } + + status = kread(sigar, &tcb, sizeof(tcb), nl[0].n_value); + if (status != SIGAR_OK) { + return status; + } + + for (head = tcb.lh_first; head != NULL; + head = pcbp.inp_list.le_next) + { + status = kread(sigar, &pcbp, sizeof(pcbp), (long)head); + if (status != SIGAR_OK) { + return status; + } + if (!(pcbp.inp_vflag & INP_IPV4)) { + continue; + } + if (pcbp.inp_fport != 0) { + continue; + } + if (ntohs(pcbp.inp_lport) == port) { + sockp = pcbp.inp_socket; + break; + } + } + + if (!sockp) { + return ENOENT; + } + + pinfo = kvm_getprocs(sigar->kmem, KERN_PROC_PROC, 0, &nentries); + if (!pinfo) { + return errno; + } + + for (i=0; ilibproc) { + return SIGAR_ENOTIMPL; + } + + status = sigar_proc_list_get(sigar, &pids); + if (status != SIGAR_OK) { + return status; + } + + for (i=0; iifconf_buf; + + for (n=0; nproc_fdtype != PROX_FDTYPE_SOCKET) { + continue; + } + rsize = sigar->proc_pidfdinfo(pids.data[i], fdp->proc_fd, + PROC_PIDFDSOCKETINFO, &si, sizeof(si)); + if (rsize != sizeof(si)) { + continue; + } + if (si.psi.soi_kind != SOCKINFO_TCP) { + continue; + } + if (si.psi.soi_proto.pri_tcp.tcpsi_state != TSI_S_LISTEN) { + continue; + } + family = si.psi.soi_family; + if (!((family == AF_INET) || (family == AF_INET6))) { + continue; + } + lport = ntohs(si.psi.soi_proto.pri_tcp.tcpsi_ini.insi_lport); + if (lport == port) { + *pid = pids.data[i]; + found = 1; + break; + } + } + } + + sigar_proc_list_destroy(sigar, &pids); + + return found ? SIGAR_OK : ENOENT; +} + +#else + +int sigar_proc_port_get(sigar_t *sigar, int protocol, + unsigned long port, sigar_pid_t *pid) +{ + return SIGAR_ENOTIMPL; +} + +#endif + +int sigar_os_sys_info_get(sigar_t *sigar, + sigar_sys_info_t *sysinfo) +{ +#ifdef DARWIN + char *codename = NULL; + SInt32 version, version_major, version_minor, version_fix; + + SIGAR_SSTRCPY(sysinfo->name, "MacOSX"); + SIGAR_SSTRCPY(sysinfo->vendor_name, "Mac OS X"); + SIGAR_SSTRCPY(sysinfo->vendor, "Apple"); + + if (Gestalt(gestaltSystemVersion, &version) == noErr) { + if (version >= 0x00001040) { + Gestalt('sys1' /*gestaltSystemVersionMajor*/, &version_major); + Gestalt('sys2' /*gestaltSystemVersionMinor*/, &version_minor); + Gestalt('sys3' /*gestaltSystemVersionBugFix*/, &version_fix); + } + else { + version_fix = version & 0xf; + version >>= 4; + version_minor = version & 0xf; + version >>= 4; + version_major = version - (version >> 4) * 6; + } + } + else { + return SIGAR_ENOTIMPL; + } + + snprintf(sysinfo->vendor_version, + sizeof(sysinfo->vendor_version), + "%d.%d", + (int)version_major, (int)version_minor); + + snprintf(sysinfo->version, + sizeof(sysinfo->version), + "%s.%d", + sysinfo->vendor_version, (int)version_fix); + + if (version_major == 10) { + switch (version_minor) { + case 2: + codename = "Jaguar"; + break; + case 3: + codename = "Panther"; + break; + case 4: + codename = "Tiger"; + break; + case 5: + codename = "Leopard"; + break; + case 6: + codename = "Snow Leopard"; + break; + case 7: + codename = "Lion"; + break; + default: + codename = "Unknown"; + break; + } + } + else { + return SIGAR_ENOTIMPL; + } + + SIGAR_SSTRCPY(sysinfo->vendor_code_name, codename); + + snprintf(sysinfo->description, + sizeof(sysinfo->description), + "%s %s", + sysinfo->vendor_name, sysinfo->vendor_code_name); +#else + char *ptr; + +#if defined(__FreeBSD__) + SIGAR_SSTRCPY(sysinfo->name, "FreeBSD"); +#elif defined(__OpenBSD__) + SIGAR_SSTRCPY(sysinfo->name, "OpenBSD"); +#elif defined(__NetBSD__) + SIGAR_SSTRCPY(sysinfo->name, "NetBSD"); +#else + SIGAR_SSTRCPY(sysinfo->name, "Unknown"); +#endif + SIGAR_SSTRCPY(sysinfo->vendor_name, sysinfo->name); + SIGAR_SSTRCPY(sysinfo->vendor, sysinfo->name); + SIGAR_SSTRCPY(sysinfo->vendor_version, + sysinfo->version); + + if ((ptr = strstr(sysinfo->vendor_version, "-"))) { + /* STABLE, RELEASE, CURRENT */ + *ptr++ = '\0'; + SIGAR_SSTRCPY(sysinfo->vendor_code_name, ptr); + } + + snprintf(sysinfo->description, + sizeof(sysinfo->description), + "%s %s", + sysinfo->name, sysinfo->version); +#endif + + return SIGAR_OK; +} diff --git a/vendor/sigar/src/os/darwin/sigar_os.h b/vendor/sigar/src/os/darwin/sigar_os.h new file mode 100644 index 0000000..ee00100 --- /dev/null +++ b/vendor/sigar/src/os/darwin/sigar_os.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2004-2006, 2008 Hyperic, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGAR_OS_H +#define SIGAR_OS_H +#ifdef __APPLE__ +#define DARWIN +#endif + +#ifdef DARWIN +/// Added to allow this code to compile with gcc4.7 vs Apple's built in compiler. +#define __private_extern__ extern + + + + +#include +#include +#ifdef DARWIN_HAS_LIBPROC_H +#include +#include +typedef int (*proc_pidinfo_func_t)(int, int, uint64_t, void *, int); +typedef int (*proc_pidfdinfo_func_t)(int, int, int, void *, int); +#endif +#else +#include +#endif + +#ifdef __NetBSD__ +#include +#endif +#include + +enum { + KOFFSET_CPUINFO, + KOFFSET_VMMETER, +#if defined(__OpenBSD__) || defined(__NetBSD__) + KOFFSET_TCPSTAT, + KOFFSET_TCBTABLE, +#endif + KOFFSET_MAX +}; + +#if defined(__OpenBSD__) || defined(__NetBSD__) +typedef struct kinfo_proc2 bsd_pinfo_t; +#else +typedef struct kinfo_proc bsd_pinfo_t; +#endif + +struct sigar_t { + SIGAR_T_BASE; + int pagesize; + time_t last_getprocs; + sigar_pid_t last_pid; + bsd_pinfo_t *pinfo; + int lcpu; + size_t argmax; +#ifdef DARWIN + mach_port_t mach_port; +# ifdef DARWIN_HAS_LIBPROC_H + void *libproc; + proc_pidinfo_func_t proc_pidinfo; + proc_pidfdinfo_func_t proc_pidfdinfo; +# endif +#else + kvm_t *kmem; + /* offsets for seeking on kmem */ + unsigned long koffsets[KOFFSET_MAX]; + int proc_mounted; +#endif +}; + +#define SIGAR_EPERM_KMEM (SIGAR_OS_START_ERROR+EACCES) +#define SIGAR_EPROC_NOENT (SIGAR_OS_START_ERROR+2) + +#endif /* SIGAR_OS_H */ diff --git a/vendor/sigar/src/os/hpux/hpux_sigar.c b/vendor/sigar/src/os/hpux/hpux_sigar.c new file mode 100644 index 0000000..f7a7adc --- /dev/null +++ b/vendor/sigar/src/os/hpux/hpux_sigar.c @@ -0,0 +1,1342 @@ +/* + * Copyright (c) 2004-2009 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2009-2010 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_util.h" +#include "sigar_os.h" + +#include +#include +#ifndef __ia64__ +#include +#endif +#include +#include +#include + +#ifdef _PSTAT64 +typedef int64_t pstat_int_t; +#else +typedef int32_t pstat_int_t; +#endif + +int sigar_os_open(sigar_t **sigar) +{ + *sigar = malloc(sizeof(**sigar)); + + /* does not change while system is running */ + pstat_getstatic(&(*sigar)->pstatic, + sizeof((*sigar)->pstatic), + 1, 0); + + (*sigar)->ticks = sysconf(_SC_CLK_TCK); + + (*sigar)->last_pid = -1; + + (*sigar)->pinfo = NULL; + + (*sigar)->mib = -1; + + return SIGAR_OK; + +} + +int sigar_os_close(sigar_t *sigar) +{ + if (sigar->pinfo) { + free(sigar->pinfo); + } + if (sigar->mib >= 0) { + close_mib(sigar->mib); + } + free(sigar); + return SIGAR_OK; +} + +char *sigar_os_error_string(sigar_t *sigar, int err) +{ + return NULL; +} + +int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem) +{ + struct pst_dynamic stats; + struct pst_vminfo vminfo; + sigar_uint64_t pagesize = sigar->pstatic.page_size; + sigar_uint64_t kern; + + mem->total = sigar->pstatic.physical_memory * pagesize; + + pstat_getdynamic(&stats, sizeof(stats), 1, 0); + + mem->free = stats.psd_free * pagesize; + mem->used = mem->total - mem->free; + + pstat_getvminfo(&vminfo, sizeof(vminfo), 1, 0); + + /* "kernel dynamic memory" */ + kern = vminfo.psv_kern_dynmem * pagesize; + mem->actual_free = mem->free + kern; + mem->actual_used = mem->used - kern; + + sigar_mem_calc_ram(sigar, mem); + + return SIGAR_OK; +} + +int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap) +{ + struct pst_swapinfo swapinfo; + struct pst_vminfo vminfo; + int i=0; + + swap->total = swap->free = 0; + + while (pstat_getswap(&swapinfo, sizeof(swapinfo), 1, i++) > 0) { + swapinfo.pss_nfpgs *= 4; /* nfpgs is in 512 byte blocks */ + + if (swapinfo.pss_nblksenabled == 0) { + swapinfo.pss_nblksenabled = swapinfo.pss_nfpgs; + } + + swap->total += swapinfo.pss_nblksenabled; + swap->free += swapinfo.pss_nfpgs; + } + + swap->used = swap->total - swap->free; + + pstat_getvminfo(&vminfo, sizeof(vminfo), 1, 0); + + swap->page_in = vminfo.psv_spgin; + swap->page_out = vminfo.psv_spgout; + + return SIGAR_OK; +} + +static void get_cpu_metrics(sigar_t *sigar, + sigar_cpu_t *cpu, + pstat_int_t *cpu_time) +{ + cpu->user = SIGAR_TICK2MSEC(cpu_time[CP_USER]); + + cpu->sys = SIGAR_TICK2MSEC(cpu_time[CP_SYS] + + cpu_time[CP_SSYS]); + + cpu->nice = SIGAR_TICK2MSEC(cpu_time[CP_NICE]); + + cpu->idle = SIGAR_TICK2MSEC(cpu_time[CP_IDLE]); + + cpu->wait = SIGAR_TICK2MSEC(cpu_time[CP_SWAIT] + + cpu_time[CP_BLOCK]); + + cpu->irq = SIGAR_TICK2MSEC(cpu_time[CP_INTR]); + cpu->soft_irq = 0; /*N/A*/ + cpu->stolen = 0; /*N/A*/ + + cpu->total = + cpu->user + cpu->sys + cpu->nice + cpu->idle + cpu->wait + cpu->irq; +} + +int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu) +{ + struct pst_dynamic stats; + + pstat_getdynamic(&stats, sizeof(stats), 1, 0); + sigar->ncpu = stats.psd_proc_cnt; + + get_cpu_metrics(sigar, cpu, stats.psd_cpu_time); + + return SIGAR_OK; +} + +int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist) +{ + int i; + struct pst_dynamic stats; + + pstat_getdynamic(&stats, sizeof(stats), 1, 0); + sigar->ncpu = stats.psd_proc_cnt; + + sigar_cpu_list_create(cpulist); + + for (i=0; incpu; i++) { + sigar_cpu_t *cpu; + struct pst_processor proc; + + if (pstat_getprocessor(&proc, sizeof(proc), 1, i) < 0) { + continue; + } + + SIGAR_CPU_LIST_GROW(cpulist); + + cpu = &cpulist->data[cpulist->number++]; + + get_cpu_metrics(sigar, cpu, proc.psp_cpu_time); + } + + return SIGAR_OK; +} + +int sigar_uptime_get(sigar_t *sigar, + sigar_uptime_t *uptime) +{ + uptime->uptime = time(NULL) - sigar->pstatic.boot_time; + + return SIGAR_OK; +} + +int sigar_loadavg_get(sigar_t *sigar, + sigar_loadavg_t *loadavg) +{ + struct pst_dynamic stats; + + pstat_getdynamic(&stats, sizeof(stats), 1, 0); + + loadavg->loadavg[0] = stats.psd_avg_1_min; + loadavg->loadavg[1] = stats.psd_avg_5_min; + loadavg->loadavg[2] = stats.psd_avg_15_min; + + return SIGAR_OK; +} + +#define PROC_ELTS 16 + +int sigar_os_proc_list_get(sigar_t *sigar, + sigar_proc_list_t *proclist) +{ + int num, idx=0; + struct pst_status proctab[PROC_ELTS]; + + while ((num = pstat_getproc(proctab, sizeof(proctab[0]), + PROC_ELTS, idx)) > 0) + { + int i; + + for (i=0; idata[proclist->number++] = + proctab[i].pst_pid; + } + + idx = proctab[num-1].pst_idx + 1; + } + + if (proclist->number == 0) { + return errno; + } + + return SIGAR_OK; +} + +static int sigar_pstat_getproc(sigar_t *sigar, sigar_pid_t pid) +{ + int status, num; + time_t timenow = time(NULL); + + if (sigar->pinfo == NULL) { + sigar->pinfo = malloc(sizeof(*sigar->pinfo)); + } + + if (sigar->last_pid == pid) { + if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) { + return SIGAR_OK; + } + } + + sigar->last_pid = pid; + sigar->last_getprocs = timenow; + + if (pstat_getproc(sigar->pinfo, + sizeof(*sigar->pinfo), + 0, pid) == -1) + { + return errno; + } + + return SIGAR_OK; +} + +int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_mem_t *procmem) +{ + int pagesize = sigar->pstatic.page_size; + int status = sigar_pstat_getproc(sigar, pid); + struct pst_status *pinfo = sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + + procmem->size = + pinfo->pst_vtsize + /* text */ + pinfo->pst_vdsize + /* data */ + pinfo->pst_vssize + /* stack */ + pinfo->pst_vshmsize + /* shared memory */ + pinfo->pst_vmmsize + /* mem-mapped files */ + pinfo->pst_vusize + /* U-Area & K-Stack */ + pinfo->pst_viosize; /* I/O dev mapping */ + + procmem->size *= pagesize; + + procmem->resident = pinfo->pst_rssize * pagesize; + + procmem->share = pinfo->pst_vshmsize * pagesize; + + procmem->minor_faults = pinfo->pst_minorfaults; + procmem->major_faults = pinfo->pst_majorfaults; + procmem->page_faults = + procmem->minor_faults + + procmem->major_faults; + + return SIGAR_OK; +} + +int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_cred_t *proccred) +{ + int status = sigar_pstat_getproc(sigar, pid); + struct pst_status *pinfo = sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + + proccred->uid = pinfo->pst_uid; + proccred->gid = pinfo->pst_gid; + proccred->euid = pinfo->pst_euid; + proccred->egid = pinfo->pst_egid; + + return SIGAR_OK; +} + +int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_time_t *proctime) +{ + int status = sigar_pstat_getproc(sigar, pid); + struct pst_status *pinfo = sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + + proctime->start_time = pinfo->pst_start; + proctime->start_time *= SIGAR_MSEC; + proctime->user = pinfo->pst_utime * SIGAR_MSEC; + proctime->sys = pinfo->pst_stime * SIGAR_MSEC; + proctime->total = proctime->user + proctime->sys; + + return SIGAR_OK; +} + +int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_state_t *procstate) +{ + int status = sigar_pstat_getproc(sigar, pid); + struct pst_status *pinfo = sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + + + SIGAR_SSTRCPY(procstate->name, pinfo->pst_ucomm); + procstate->ppid = pinfo->pst_ppid; + procstate->tty = makedev(pinfo->pst_term.psd_major, + pinfo->pst_term.psd_minor); + procstate->priority = pinfo->pst_pri; + procstate->nice = pinfo->pst_nice; + procstate->threads = pinfo->pst_nlwps; + procstate->processor = pinfo->pst_procnum; + + /* cast to prevent compiler warning: */ + /* Case label too big for the type of the switch expression */ + switch ((int32_t)pinfo->pst_stat) { + case PS_SLEEP: + procstate->state = 'S'; + break; + case PS_RUN: + procstate->state = 'R'; + break; + case PS_STOP: + procstate->state = 'T'; + break; + case PS_ZOMBIE: + procstate->state = 'Z'; + break; + case PS_IDLE: + procstate->state = 'D'; + break; + } + + return SIGAR_OK; +} + +int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs) +{ + char *args, *arg; +#ifdef PSTAT_GETCOMMANDLINE + char buf[1024]; /* kernel limit */ + +# ifdef pstat_getcommandline /* 11i v2 + */ + if (pstat_getcommandline(buf, sizeof(buf), sizeof(buf[0]), pid) == -1) { + return errno; + } +# else + union pstun pu; + + pu.pst_command = buf; + if (pstat(PSTAT_GETCOMMANDLINE, pu, sizeof(buf), sizeof(buf[0]), pid) == -1) { + return errno; + } +# endif /* pstat_getcommandline */ + + args = buf; +#else + struct pst_status status; + + if (pstat_getproc(&status, sizeof(status), 0, pid) == -1) { + return errno; + } + + args = status.pst_cmd; +#endif + + while (*args && (arg = sigar_getword(&args, ' '))) { + SIGAR_PROC_ARGS_GROW(procargs); + procargs->data[procargs->number++] = arg; + } + + return SIGAR_OK; +} + +int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_env_t *procenv) +{ + return SIGAR_ENOTIMPL; +} + +int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_fd_t *procfd) +{ + struct pst_status status; + int idx=0, n; + struct pst_fileinfo2 psf[16]; + + procfd->total = 0; + + if (pstat_getproc(&status, sizeof(status), 0, pid) == -1) { + return errno; + } + + /* HPUX 11.31 removed the deprecated pstat_getfile call */ + while ((n = pstat_getfile2(psf, sizeof(psf[0]), + sizeof(psf)/sizeof(psf[0]), + idx, pid)) > 0) + { + procfd->total += n; + idx = psf[n-1].psf_fd + 1; + } + + if (n == -1) { + return errno; + } + + return SIGAR_OK; +} + +int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_exe_t *procexe) +{ +#ifdef __pst_fid /* 11.11+ */ + int rc; + struct pst_status status; + + if (pstat_getproc(&status, sizeof(status), 0, pid) == -1) { + return errno; + } + + rc = pstat_getpathname(procexe->cwd, + sizeof(procexe->cwd), + &status.pst_fid_cdir); + if (rc == -1) { + return errno; + } + + rc = pstat_getpathname(procexe->name, + sizeof(procexe->name), + &status.pst_fid_text); + if (rc == -1) { + return errno; + } + + rc = pstat_getpathname(procexe->root, + sizeof(procexe->root), + &status.pst_fid_rdir); + if (rc == -1) { + return errno; + } + + return SIGAR_OK; +#else + return SIGAR_ENOTIMPL; /* 11.00 */ +#endif +} + +int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_modules_t *procmods) +{ + return SIGAR_ENOTIMPL; +} + +#define TIME_NSEC(t) \ + (SIGAR_SEC2NANO((t).tv_sec) + (sigar_uint64_t)(t).tv_nsec) + +int sigar_thread_cpu_get(sigar_t *sigar, + sigar_uint64_t id, + sigar_thread_cpu_t *cpu) +{ +#ifdef __ia64__ + /* XXX seems _lwp funcs were for solaris compat and dont exist + * on itanium. hp docs claim that have equiv functions, + * but wtf is it for _lwp_info? + */ + return SIGAR_ENOTIMPL; +#else + struct lwpinfo info; + + if (id != 0) { + return SIGAR_ENOTIMPL; + } + + _lwp_info(&info); + + cpu->user = TIME_NSEC(info.lwp_utime); + cpu->sys = TIME_NSEC(info.lwp_stime); + cpu->total = TIME_NSEC(info.lwp_utime) + TIME_NSEC(info.lwp_stime); + + return SIGAR_OK; +#endif +} + +#include + +int sigar_os_fs_type_get(sigar_file_system_t *fsp) +{ + char *type = fsp->sys_type_name; + + switch (*type) { + case 'h': + if (strEQ(type, "hfs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'c': + if (strEQ(type, "cdfs")) { + fsp->type = SIGAR_FSTYPE_CDROM; + } + break; + } + + return fsp->type; +} + +int sigar_file_system_list_get(sigar_t *sigar, + sigar_file_system_list_t *fslist) +{ + struct mntent *ent; + + FILE *fp; + sigar_file_system_t *fsp; + + if (!(fp = setmntent(MNT_MNTTAB, "r"))) { + return errno; + } + + sigar_file_system_list_create(fslist); + + while ((ent = getmntent(fp))) { + if ((*(ent->mnt_type) == 's') && + strEQ(ent->mnt_type, "swap")) + { + /* + * in this case, devname == "...", for + * which statfs chokes on. so skip it. + * also notice hpux df command has no swap info. + */ + continue; + } + + SIGAR_FILE_SYSTEM_LIST_GROW(fslist); + + fsp = &fslist->data[fslist->number++]; + + SIGAR_SSTRCPY(fsp->dir_name, ent->mnt_dir); + SIGAR_SSTRCPY(fsp->dev_name, ent->mnt_fsname); + SIGAR_SSTRCPY(fsp->sys_type_name, ent->mnt_type); + SIGAR_SSTRCPY(fsp->options, ent->mnt_opts); + sigar_fs_type_init(fsp); + } + + endmntent(fp); + + return SIGAR_OK; +} + +static int create_fsdev_cache(sigar_t *sigar) +{ + sigar_file_system_list_t fslist; + int i; + int status = + sigar_file_system_list_get(sigar, &fslist); + + if (status != SIGAR_OK) { + return status; + } + + sigar->fsdev = sigar_cache_new(15); + + for (i=0; itype == SIGAR_FSTYPE_LOCAL_DISK) { + sigar_cache_entry_t *ent; + struct stat sb; + + if (stat(fsp->dir_name, &sb) < 0) { + continue; + } + + ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb)); + ent->value = strdup(fsp->dev_name); + } + } + + return SIGAR_OK; +} + +int sigar_disk_usage_get(sigar_t *sigar, const char *name, + sigar_disk_usage_t *usage) +{ + return SIGAR_ENOTIMPL; +} + +int sigar_file_system_usage_get(sigar_t *sigar, + const char *dirname, + sigar_file_system_usage_t *fsusage) +{ + struct stat sb; + int status = sigar_statvfs(sigar, dirname, fsusage); + + if (status != SIGAR_OK) { + return status; + } + + fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage); + + SIGAR_DISK_STATS_INIT(&fsusage->disk); + + if (!sigar->fsdev) { + if (create_fsdev_cache(sigar) != SIGAR_OK) { + return SIGAR_OK; + } + } + + if (stat(dirname, &sb) == 0) { + sigar_cache_entry_t *ent; + struct pst_lvinfo lv; + struct stat devsb; + char *devname; + int retval; + + ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb)); + if (ent->value == NULL) { + return SIGAR_OK; + } + + if (stat((char *)ent->value, &devsb) < 0) { + return SIGAR_OK; + } + + retval = pstat_getlv(&lv, sizeof(lv), 0, (int)devsb.st_rdev); + + if (retval == 1) { + fsusage->disk.reads = lv.psl_rxfer; + fsusage->disk.writes = lv.psl_wxfer; + fsusage->disk.read_bytes = lv.psl_rcount; + fsusage->disk.write_bytes = lv.psl_wcount; + fsusage->disk.queue = SIGAR_FIELD_NOTIMPL; + } + } + + return SIGAR_OK; +} + +int sigar_cpu_info_list_get(sigar_t *sigar, + sigar_cpu_info_list_t *cpu_infos) +{ + int i; + struct pst_dynamic stats; + + pstat_getdynamic(&stats, sizeof(stats), 1, 0); + sigar->ncpu = stats.psd_proc_cnt; + + sigar_cpu_info_list_create(cpu_infos); + + for (i=0; incpu; i++) { + sigar_cpu_info_t *info; + struct pst_processor proc; + + if (pstat_getprocessor(&proc, sizeof(proc), 1, i) < 0) { + perror("pstat_getprocessor"); + continue; + } + + SIGAR_CPU_INFO_LIST_GROW(cpu_infos); + + info = &cpu_infos->data[cpu_infos->number++]; + + info->total_cores = sigar->ncpu; + info->cores_per_socket = 1; /*XXX*/ + info->total_sockets = sigar->ncpu; /*XXX*/ + +#ifdef __ia64__ + SIGAR_SSTRCPY(info->vendor, "Intel"); /*XXX*/ + SIGAR_SSTRCPY(info->model, "Itanium"); /*XXX*/ +#else + SIGAR_SSTRCPY(info->vendor, "HP"); /*XXX*/ + SIGAR_SSTRCPY(info->model, "PA RISC"); /*XXX*/ +#endif +#ifdef PSP_MAX_CACHE_LEVELS /* 11.31+; see SIGAR-196 */ + info->mhz = proc.psp_cpu_frequency / 1000000; +#else + info->mhz = sigar->ticks * proc.psp_iticksperclktick / 1000000; +#endif + info->cache_size = SIGAR_FIELD_NOTIMPL; /*XXX*/ + } + + return SIGAR_OK; +} + +static int sigar_get_mib_info(sigar_t *sigar, + struct nmparms *parms) +{ + if (sigar->mib < 0) { + if ((sigar->mib = open_mib("/dev/ip", O_RDONLY, 0, 0)) < 0) { + return errno; + } + } + return get_mib_info(sigar->mib, parms); +} + +/* wrapper around get_physical_stat() */ +static int sigar_get_physical_stat(sigar_t *sigar, int *count) +{ + int status; + unsigned int len; + struct nmparms parms; + + len = sizeof(*count); + parms.objid = ID_ifNumber; + parms.buffer = count; + parms.len = &len; + + if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { + return status; + } + + len = sizeof(nmapi_phystat) * *count; + + if (sigar->ifconf_len < len) { + sigar->ifconf_buf = realloc(sigar->ifconf_buf, len); + sigar->ifconf_len = len; + } + + if (get_physical_stat(sigar->ifconf_buf, &len) < 0) { + return errno; + } + else { + return SIGAR_OK; + } +} + +#define SIGAR_IF_NAMESIZE 16 +/* hpux if_indextoname() does not work as advertised in 11.11 */ +static int sigar_if_indextoname(sigar_t *sigar, + char *name, + int index) +{ + int i, status, count; + nmapi_phystat *stat; + + if ((status = sigar_get_physical_stat(sigar, &count) != SIGAR_OK)) { + return status; + } + + for (i=0, stat = (nmapi_phystat *)sigar->ifconf_buf; + iif_entry.ifIndex == index) { + strncpy(name, stat->nm_device, SIGAR_IF_NAMESIZE); + return SIGAR_OK; + } + } + + return ENXIO; +} + +int sigar_net_route_list_get(sigar_t *sigar, + sigar_net_route_list_t *routelist) +{ + int status, count, i; + unsigned int len; + struct nmparms parms; + mib_ipRouteEnt *routes; + sigar_net_route_t *route; + + len = sizeof(count); + parms.objid = ID_ipRouteNumEnt; + parms.buffer = &count; + parms.len = &len; + + if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { + return status; + } + + len = count * sizeof(*routes); + routes = malloc(len); + + parms.objid = ID_ipRouteTable; + parms.buffer = routes; + parms.len = &len; + + if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { + free(routes); + return status; + } + + routelist->size = routelist->number = 0; + + sigar_net_route_list_create(routelist); + + for (i=0; idata[routelist->number++]; + SIGAR_ZERO(route); /* XXX: other fields */ + + sigar_net_address_set(route->destination, + ent->Dest); + + sigar_net_address_set(route->mask, + ent->Mask); + + sigar_net_address_set(route->gateway, + ent->NextHop); + + sigar_if_indextoname(sigar, route->ifname, ent->IfIndex); + + route->flags = SIGAR_RTF_UP; + if ((ent->Dest == 0) && + (ent->Mask == 0)) + { + route->flags |= SIGAR_RTF_GATEWAY; + } + } + + free(routes); + + return SIGAR_OK; +} + +static int get_mib_ifstat(sigar_t *sigar, + const char *name, + mib_ifEntry *mib) +{ + int i, status, count; + nmapi_phystat *stat; + + if ((status = sigar_get_physical_stat(sigar, &count) != SIGAR_OK)) { + return status; + } + + for (i=0, stat = (nmapi_phystat *)sigar->ifconf_buf; + inm_device, name)) { + memcpy(mib, &stat->if_entry, sizeof(*mib)); + return SIGAR_OK; + } + } + + return ENXIO; +} + +int sigar_net_interface_stat_get(sigar_t *sigar, const char *name, + sigar_net_interface_stat_t *ifstat) +{ + int status; + mib_ifEntry mib; + + status = get_mib_ifstat(sigar, name, &mib); + + if (status != SIGAR_OK) { + return status; + } + + ifstat->rx_bytes = mib.ifInOctets; + ifstat->rx_packets = mib.ifInUcastPkts + mib.ifInNUcastPkts; + ifstat->rx_errors = mib.ifInErrors; + ifstat->rx_dropped = mib.ifInDiscards; + ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL; + ifstat->rx_frame = SIGAR_FIELD_NOTIMPL; + + ifstat->tx_bytes = mib.ifOutOctets; + ifstat->tx_packets = mib.ifOutUcastPkts + mib.ifOutNUcastPkts; + ifstat->tx_errors = mib.ifOutErrors; + ifstat->tx_dropped = mib.ifOutDiscards; + ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL; + ifstat->tx_collisions = SIGAR_FIELD_NOTIMPL; + ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL; + + ifstat->speed = mib.ifSpeed; + + return SIGAR_OK; +} + +int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig) +{ + int sock; + struct if_laddrreq iflr; + + if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + return errno; + } + + SIGAR_SSTRCPY(iflr.iflr_name, name); + + if (ioctl(sock, SIOCGLIFADDR, &iflr) == 0) { + struct in6_addr *addr = SIGAR_SIN6_ADDR(&iflr.iflr_addr); + + sigar_net_address6_set(ifconfig->address6, addr); + sigar_net_interface_scope6_set(ifconfig, addr); + + if (ioctl(sock, SIOCGLIFNETMASK, &iflr) == 0) { + addr = SIGAR_SIN6_ADDR(&iflr.iflr_addr); + ifconfig->prefix6_length = 10; /*XXX*/ + } + } + + close(sock); + return SIGAR_OK; +} + +static int net_conn_get_udp_listen(sigar_net_connection_walker_t *walker) +{ + sigar_t *sigar = walker->sigar; + int flags = walker->flags; + int status, count, i; + unsigned int len; + mib_udpLsnEnt *entries; + struct nmparms parms; + + len = sizeof(count); + parms.objid = ID_udpLsnNumEnt; + parms.buffer = &count; + parms.len = &len; + + if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { + return status; + } + + if (count <= 0) { + return ENOENT; + } + + len = count * sizeof(*entries); + entries = malloc(len); + parms.objid = ID_udpLsnTable; + parms.buffer = entries; + parms.len = &len; + + if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { + free(entries); + return status; + } + + for (i=0; iLocalPort; + conn.remote_port = 0; + + sigar_net_address_set(conn.local_address, + entry->LocalAddress); + + sigar_net_address_set(conn.remote_address, 0); + + conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL; + + if (walker->add_connection(walker, &conn) != SIGAR_OK) { + break; + } + } + + free(entries); + return SIGAR_OK; +} + +static int net_conn_get_udp(sigar_net_connection_walker_t *walker) +{ + int status = SIGAR_OK; + + if (walker->flags & SIGAR_NETCONN_SERVER) { + status = net_conn_get_udp_listen(walker); + } + + return status; +} + +#define IS_TCP_SERVER(state, flags) \ + ((flags & SIGAR_NETCONN_SERVER) && (state == TCLISTEN)) + +#define IS_TCP_CLIENT(state, flags) \ + ((flags & SIGAR_NETCONN_CLIENT) && (state != TCLISTEN)) + +static int net_conn_get_tcp(sigar_net_connection_walker_t *walker) +{ + sigar_t *sigar = walker->sigar; + int flags = walker->flags; + int status, count, i; + unsigned int len; + mib_tcpConnEnt *entries; + struct nmparms parms; + + len = sizeof(count); + parms.objid = ID_tcpConnNumEnt; + parms.buffer = &count; + parms.len = &len; + + if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { + return status; + } + + if (count <= 0) { + return ENOENT; + } + + len = count * sizeof(*entries); + entries = malloc(len); + parms.objid = ID_tcpConnTable; + parms.buffer = entries; + parms.len = &len; + + if ((status = sigar_get_mib_info(sigar, &parms)) != SIGAR_OK) { + free(entries); + return status; + } + + for (i=0; iState; + + if (!(IS_TCP_SERVER(state, flags) || + IS_TCP_CLIENT(state, flags))) + { + continue; + } + + SIGAR_ZERO(&conn); + + switch (state) { + case TCCLOSED: + conn.state = SIGAR_TCP_CLOSE; + break; + case TCLISTEN: + conn.state = SIGAR_TCP_LISTEN; + break; + case TCSYNSENT: + conn.state = SIGAR_TCP_SYN_SENT; + break; + case TCSYNRECEIVE: + conn.state = SIGAR_TCP_SYN_RECV; + break; + case TCESTABLISED: + conn.state = SIGAR_TCP_ESTABLISHED; + break; + case TCFINWAIT1: + conn.state = SIGAR_TCP_FIN_WAIT1; + break; + case TCFINWAIT2: + conn.state = SIGAR_TCP_FIN_WAIT2; + break; + case TCCLOSEWAIT: + conn.state = SIGAR_TCP_CLOSE_WAIT; + break; + case TCCLOSING: + conn.state = SIGAR_TCP_CLOSING; + break; + case TCLASTACK: + conn.state = SIGAR_TCP_LAST_ACK; + break; + case TCTIMEWAIT: + conn.state = SIGAR_TCP_TIME_WAIT; + break; + case TCDELETETCB: + default: + conn.state = SIGAR_TCP_UNKNOWN; + break; + } + + conn.local_port = (unsigned short)entry->LocalPort; + conn.remote_port = (unsigned short)entry->RemPort; + conn.type = SIGAR_NETCONN_TCP; + + sigar_net_address_set(conn.local_address, entry->LocalAddress); + sigar_net_address_set(conn.remote_address, entry->RemAddress); + + conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL; + + if (walker->add_connection(walker, &conn) != SIGAR_OK) { + break; + } + } + + free(entries); + + return SIGAR_OK; +} + +int sigar_net_connection_walk(sigar_net_connection_walker_t *walker) +{ + int status; + + if (walker->flags & SIGAR_NETCONN_TCP) { + status = net_conn_get_tcp(walker); + + if (status != SIGAR_OK) { + return status; + } + } + + if (walker->flags & SIGAR_NETCONN_UDP) { + status = net_conn_get_udp(walker); + + if (status != SIGAR_OK) { + return status; + } + } + + return SIGAR_OK; +} + +#define tcpsoff(x) sigar_offsetof(sigar_tcp_t, x) + +static struct { + unsigned int id; + size_t offset; +} tcps_lu[] = { +#if 0 + { ID_tcpRtoAlgorithm, tcpsoff(xxx) }, + { ID_tcpRtoMin, tcpsoff(xxx) }, + { ID_tcpRtoMax, tcpsoff(xxx) }, + { ID_tcpMaxConn, tcpsoff(max_conn) }, +#endif + { ID_tcpActiveOpens, tcpsoff(active_opens) }, + { ID_tcpPassiveOpens, tcpsoff(passive_opens) }, + { ID_tcpAttemptFails, tcpsoff(attempt_fails) }, + { ID_tcpEstabResets, tcpsoff(estab_resets) }, + { ID_tcpCurrEstab, tcpsoff(curr_estab) }, + { ID_tcpInSegs, tcpsoff(in_segs) }, + { ID_tcpOutSegs, tcpsoff(out_segs) }, + { ID_tcpRetransSegs, tcpsoff(retrans_segs) }, + { ID_tcpInErrs, tcpsoff(in_errs) }, + { ID_tcpOutRsts, tcpsoff(out_rsts) } +}; + +SIGAR_DECLARE(int) +sigar_tcp_get(sigar_t *sigar, + sigar_tcp_t *tcp) +{ + int i; + + for (i=0; idata[arplist->number++]; + + sigar_net_address_set(arp->address, + ent->NetAddr); + + sigar_net_address_mac_set(arp->hwaddr, + ent->PhysAddr.o_bytes, + ent->PhysAddr.o_length); + + sigar_if_indextoname(sigar, arp->ifname, ent->IfIndex); + + SIGAR_SSTRCPY(arp->type, "ether"); /*XXX*/ + arp->flags = 0; /*XXX*/ + } + + free(entries); + + return SIGAR_OK; +} + +int sigar_proc_port_get(sigar_t *sigar, int protocol, + unsigned long port, sigar_pid_t *pid) +{ + return SIGAR_ENOTIMPL; +} + + +int sigar_os_sys_info_get(sigar_t *sigar, + sigar_sys_info_t *sysinfo) +{ + char *vendor_version, *arch; + long cpu = sysconf(_SC_CPU_VERSION); + + switch (cpu) { + case CPU_PA_RISC1_0: + arch = "PA_RISC1.0"; + break; + case CPU_PA_RISC1_1: + arch = "PA_RISC1.1"; + break; + case CPU_PA_RISC2_0: + arch = "PA_RISC2.0"; + break; +#ifdef CPU_IA64_ARCHREV_0 + case CPU_IA64_ARCHREV_0: + arch = "ia64"; + break; +#endif + default: + arch = "unknown"; + break; + } + + SIGAR_SSTRCPY(sysinfo->arch, arch); + + SIGAR_SSTRCPY(sysinfo->name, "HPUX"); + SIGAR_SSTRCPY(sysinfo->vendor, "Hewlett-Packard"); + + if (strstr(sysinfo->version, ".11.")) { + vendor_version = "11"; + } + else { + vendor_version = sysinfo->version; + } + + SIGAR_SSTRCPY(sysinfo->vendor_version, vendor_version); + + snprintf(sysinfo->description, + sizeof(sysinfo->description), + "%s %s", + sysinfo->vendor_name, sysinfo->vendor_version); + + return SIGAR_OK; +} diff --git a/vendor/sigar/src/os/hpux/sigar_os.h b/vendor/sigar/src/os/hpux/sigar_os.h new file mode 100644 index 0000000..ee2434a --- /dev/null +++ b/vendor/sigar/src/os/hpux/sigar_os.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2004-2007 Hyperic, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGAR_OS_H +#define SIGAR_OS_H + +#if defined(__ia64) && !defined(__ia64__) +#define __ia64__ +#endif + +#ifdef __ia64__ +#ifndef _LP64 +#define _LP64 +#endif +#endif + +#define _PSTAT64 + +#include +#include +#include +#include + +struct sigar_t { + SIGAR_T_BASE; + struct pst_static pstatic; + time_t last_getprocs; + sigar_pid_t last_pid; + struct pst_status *pinfo; + + int mib; +}; + +int hpux_get_mib_ifentry(int ppa, mib_ifEntry *mib); + +#endif /* SIGAR_OS_H */ diff --git a/vendor/sigar/src/os/linux/linux_sigar.c b/vendor/sigar/src/os/linux/linux_sigar.c new file mode 100644 index 0000000..0e4283f --- /dev/null +++ b/vendor/sigar/src/os/linux/linux_sigar.c @@ -0,0 +1,2782 @@ +/* + * Copyright (c) 2004-2009 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2009-2010 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_util.h" +#include "sigar_os.h" + +#define pageshift(x) ((x) << sigar->pagesize) + +#define PROC_MEMINFO PROC_FS_ROOT "meminfo" +#define PROC_VMSTAT PROC_FS_ROOT "vmstat" +#define PROC_MTRR PROC_FS_ROOT "mtrr" +#define PROC_STAT PROC_FS_ROOT "stat" +#define PROC_UPTIME PROC_FS_ROOT "uptime" +#define PROC_LOADAVG PROC_FS_ROOT "loadavg" + +#define PROC_PSTAT "/stat" +#define PROC_PSTATUS "/status" + +#define SYS_BLOCK "/sys/block" +#define PROC_PARTITIONS PROC_FS_ROOT "partitions" +#define PROC_DISKSTATS PROC_FS_ROOT "diskstats" + +/* + * /proc/self/stat fields: + * 1 - pid + * 2 - comm + * 3 - state + * 4 - ppid + * 5 - pgrp + * 6 - session + * 7 - tty_nr + * 8 - tpgid + * 9 - flags + * 10 - minflt + * 11 - cminflt + * 12 - majflt + * 13 - cmajflt + * 14 - utime + * 15 - stime + * 16 - cutime + * 17 - cstime + * 18 - priority + * 19 - nice + * 20 - 0 (removed field) + * 21 - itrealvalue + * 22 - starttime + * 23 - vsize + * 24 - rss + * 25 - rlim + * 26 - startcode + * 27 - endcode + * 28 - startstack + * 29 - kstkesp + * 30 - kstkeip + * 31 - signal + * 32 - blocked + * 33 - sigignore + * 34 - sigcache + * 35 - wchan + * 36 - nswap + * 37 - cnswap + * 38 - exit_signal <-- looking for this. + * 39 - processor + * ... more for newer RH + */ + +#define PROC_SIGNAL_IX 38 + +static int get_proc_signal_offset(void) +{ + char buffer[BUFSIZ], *ptr=buffer; + int fields = 0; + int status = sigar_file2str(PROCP_FS_ROOT "self/stat", + buffer, sizeof(buffer)); + + if (status != SIGAR_OK) { + return 1; + } + + while (*ptr) { + if (*ptr++ == ' ') { + fields++; + } + } + + return (fields - PROC_SIGNAL_IX) + 1; +} + +sigar_pid_t sigar_pid_get(sigar_t *sigar) +{ + /* XXX cannot safely cache getpid unless using nptl */ + /* we can however, cache it for optimizations in the + * case of proc_env_get for example. + */ + sigar->pid = getpid(); + return sigar->pid; +} + +static int sigar_boot_time_get(sigar_t *sigar) +{ + FILE *fp; + char buffer[BUFSIZ], *ptr; + int found = 0; + + if (!(fp = fopen(PROC_STAT, "r"))) { + return errno; + } + + while ((ptr = fgets(buffer, sizeof(buffer), fp))) { + if (strnEQ(ptr, "btime", 5)) { + if ((ptr = sigar_skip_token(ptr))) { + sigar->boot_time = sigar_strtoul(ptr); + found = 1; + } + break; + } + } + + fclose(fp); + + if (!found) { + /* should never happen */ + sigar->boot_time = time(NULL); + } + + return SIGAR_OK; +} + +int sigar_os_open(sigar_t **sigar) +{ + int i, status; + int kernel_rev, has_nptl; + struct stat sb; + struct utsname name; + + *sigar = malloc(sizeof(**sigar)); + + (*sigar)->pagesize = 0; + i = getpagesize(); + while ((i >>= 1) > 0) { + (*sigar)->pagesize++; + } + + status = sigar_boot_time_get(*sigar); + if (status != SIGAR_OK) { + return status; + } + + (*sigar)->ticks = sysconf(_SC_CLK_TCK); + + (*sigar)->ram = -1; + + (*sigar)->proc_signal_offset = -1; + + (*sigar)->last_proc_stat.pid = -1; + + (*sigar)->lcpu = -1; + + if (stat(PROC_DISKSTATS, &sb) == 0) { + (*sigar)->iostat = IOSTAT_DISKSTATS; + } + else if (stat(SYS_BLOCK, &sb) == 0) { + (*sigar)->iostat = IOSTAT_SYS; + } + else if (stat(PROC_PARTITIONS, &sb) == 0) { + /* XXX file exists does not mean is has the fields */ + (*sigar)->iostat = IOSTAT_PARTITIONS; + } + else { + (*sigar)->iostat = IOSTAT_NONE; + } + + /* hook for using mirrored /proc/net/tcp file */ + (*sigar)->proc_net = getenv("SIGAR_PROC_NET"); + + uname(&name); + /* 2.X.y.z -> just need X (unless there is ever a kernel version 3!) */ + kernel_rev = atoi(&name.release[2]); + if (kernel_rev >= 6) { + has_nptl = 1; + } + else { + has_nptl = getenv("SIGAR_HAS_NPTL") ? 1 : 0; + } + (*sigar)->has_nptl = has_nptl; + + return SIGAR_OK; +} + +int sigar_os_close(sigar_t *sigar) +{ + free(sigar); + return SIGAR_OK; +} + +char *sigar_os_error_string(sigar_t *sigar, int err) +{ + return NULL; +} + +static int sigar_cpu_total_count(sigar_t *sigar) +{ + sigar->ncpu = (int)sysconf(_SC_NPROCESSORS_CONF); + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[cpu] ncpu=%d\n", + sigar->ncpu); + return sigar->ncpu; +} + +static int get_ram(sigar_t *sigar, sigar_mem_t *mem) +{ + char buffer[BUFSIZ], *ptr; + FILE *fp; + int total = 0; + sigar_uint64_t sys_total = (mem->total / (1024 * 1024)); + + if (sigar->ram > 0) { + /* return cached value */ + mem->ram = sigar->ram; + return SIGAR_OK; + } + + if (sigar->ram == 0) { + return ENOENT; + } + + /* + * Memory Type Range Registers + * write-back registers add up to the total. + * Well, they are supposed to add up, but seen + * at least one configuration where that is not the + * case. + */ + if (!(fp = fopen(PROC_MTRR, "r"))) { + return errno; + } + + while ((ptr = fgets(buffer, sizeof(buffer), fp))) { + if (!(ptr = strstr(ptr, "size="))) { + continue; + } + + if (!strstr(ptr, "write-back")) { + continue; + } + + ptr += 5; + while (sigar_isspace(*ptr)) { + ++ptr; + } + + total += atoi(ptr); + } + + fclose(fp); + + if ((total - sys_total) > 256) { + /* mtrr write-back registers are way off + * kernel should not be using more that 256MB of mem + */ + total = 0; /* punt */ + } + + if (total == 0) { + return ENOENT; + } + + mem->ram = sigar->ram = total; + + return SIGAR_OK; +} + +#define MEMINFO_PARAM(a) a ":", SSTRLEN(a ":") + +static SIGAR_INLINE sigar_uint64_t sigar_meminfo(char *buffer, + char *attr, int len) +{ + sigar_uint64_t val = 0; + char *ptr, *tok; + + if ((ptr = strstr(buffer, attr))) { + ptr += len; + val = strtoull(ptr, &tok, 0); + while (*tok == ' ') { + ++tok; + } + if (*tok == 'k') { + val *= 1024; + } + else if (*tok == 'M') { + val *= (1024 * 1024); + } + } + + return val; +} + +int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem) +{ + sigar_uint64_t buffers, cached, kern; + char buffer[BUFSIZ]; + + int status = sigar_file2str(PROC_MEMINFO, + buffer, sizeof(buffer)); + + if (status != SIGAR_OK) { + return status; + } + + mem->total = sigar_meminfo(buffer, MEMINFO_PARAM("MemTotal")); + mem->free = sigar_meminfo(buffer, MEMINFO_PARAM("MemFree")); + mem->used = mem->total - mem->free; + + buffers = sigar_meminfo(buffer, MEMINFO_PARAM("Buffers")); + cached = sigar_meminfo(buffer, MEMINFO_PARAM("Cached")); + + kern = buffers + cached; + mem->actual_free = mem->free + kern; + mem->actual_used = mem->used - kern; + + sigar_mem_calc_ram(sigar, mem); + + if (get_ram(sigar, mem) != SIGAR_OK) { + /* XXX other options on failure? */ + } + + return SIGAR_OK; +} + +int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap) +{ + char buffer[BUFSIZ], *ptr; + + /* XXX: we open/parse the same file here as sigar_mem_get */ + int status = sigar_file2str(PROC_MEMINFO, + buffer, sizeof(buffer)); + + if (status != SIGAR_OK) { + return status; + } + + swap->total = sigar_meminfo(buffer, MEMINFO_PARAM("SwapTotal")); + swap->free = sigar_meminfo(buffer, MEMINFO_PARAM("SwapFree")); + swap->used = swap->total - swap->free; + + swap->page_in = swap->page_out = -1; + + status = sigar_file2str(PROC_VMSTAT, + buffer, sizeof(buffer)); + + if (status == SIGAR_OK) { + /* 2.6+ kernel */ + if ((ptr = strstr(buffer, "\npswpin"))) { + ptr = sigar_skip_token(ptr); + swap->page_in = sigar_strtoull(ptr); + ptr = sigar_skip_token(ptr); + swap->page_out = sigar_strtoull(ptr); + } + } + else { + /* 2.2, 2.4 kernels */ + status = sigar_file2str(PROC_STAT, + buffer, sizeof(buffer)); + if (status != SIGAR_OK) { + return status; + } + + if ((ptr = strstr(buffer, "\nswap"))) { + ptr = sigar_skip_token(ptr); + swap->page_in = sigar_strtoull(ptr); + swap->page_out = sigar_strtoull(ptr); + } + } + + return SIGAR_OK; +} + +static void get_cpu_metrics(sigar_t *sigar, sigar_cpu_t *cpu, char *line) +{ + char *ptr = sigar_skip_token(line); /* "cpu%d" */ + + cpu->user += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); + cpu->nice += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); + cpu->sys += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); + cpu->idle += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); + if (*ptr == ' ') { + /* 2.6+ kernels only */ + cpu->wait += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); + cpu->irq += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); + cpu->soft_irq += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); + } + if (*ptr == ' ') { + /* 2.6.11+ kernels only */ + cpu->stolen += SIGAR_TICK2MSEC(sigar_strtoull(ptr)); + } + cpu->total = + cpu->user + cpu->nice + cpu->sys + cpu->idle + + cpu->wait + cpu->irq + cpu->soft_irq + cpu->stolen; +} + +int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu) +{ + char buffer[BUFSIZ]; + int status = sigar_file2str(PROC_STAT, buffer, sizeof(buffer)); + + if (status != SIGAR_OK) { + return status; + } + + SIGAR_ZERO(cpu); + get_cpu_metrics(sigar, cpu, buffer); + + return SIGAR_OK; +} + +int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist) +{ + FILE *fp; + char buffer[BUFSIZ], cpu_total[BUFSIZ], *ptr; + int core_rollup = sigar_cpu_core_rollup(sigar), i=0; + sigar_cpu_t *cpu; + + if (!(fp = fopen(PROC_STAT, "r"))) { + return errno; + } + + /* skip first line */ + (void)fgets(cpu_total, sizeof(cpu_total), fp); + + sigar_cpu_list_create(cpulist); + + /* XXX: merge times of logical processors if hyperthreading */ + while ((ptr = fgets(buffer, sizeof(buffer), fp))) { + if (!strnEQ(ptr, "cpu", 3)) { + break; + } + + if (core_rollup && (i % sigar->lcpu)) { + /* merge times of logical processors */ + cpu = &cpulist->data[cpulist->number-1]; + } + else { + SIGAR_CPU_LIST_GROW(cpulist); + cpu = &cpulist->data[cpulist->number++]; + SIGAR_ZERO(cpu); + } + + get_cpu_metrics(sigar, cpu, ptr); + + i++; + } + + fclose(fp); + + if (cpulist->number == 0) { + /* likely older kernel where cpu\d is not present */ + cpu = &cpulist->data[cpulist->number++]; + SIGAR_ZERO(cpu); + get_cpu_metrics(sigar, cpu, cpu_total); + } + + return SIGAR_OK; +} + +int sigar_uptime_get(sigar_t *sigar, + sigar_uptime_t *uptime) +{ + char buffer[BUFSIZ], *ptr = buffer; + int status = sigar_file2str(PROC_UPTIME, buffer, sizeof(buffer)); + + if (status != SIGAR_OK) { + return status; + } + + uptime->uptime = strtod(buffer, &ptr); + + return SIGAR_OK; +} + +int sigar_loadavg_get(sigar_t *sigar, + sigar_loadavg_t *loadavg) +{ + char buffer[BUFSIZ], *ptr = buffer; + int status = sigar_file2str(PROC_LOADAVG, buffer, sizeof(buffer)); + + if (status != SIGAR_OK) { + return status; + } + + loadavg->loadavg[0] = strtod(buffer, &ptr); + loadavg->loadavg[1] = strtod(ptr, &ptr); + loadavg->loadavg[2] = strtod(ptr, &ptr); + + return SIGAR_OK; +} + +/* + * seems the easiest/fastest way to tell if a process listed in /proc + * is a thread is to check the "exit signal" flag in /proc/num/stat. + * any value other than SIGCHLD seems to be a thread. this make hulk mad. + * redhat's procps patch (named "threadbadhack.pat") does not use + * this flag to filter out threads. instead does much more expensive + * comparisions. their patch also bubbles up thread cpu times to the main + * process. functionality we currently lack. + * when nptl is in use, this is not the case and all threads spawned from + * a process have the same pid. however, it seems both old-style linux + * threads and nptl threads can be run on the same machine. + * there is also the "Tgid" field in /proc/self/status which could be used + * to detect threads, but this is not available in older kernels. + */ +static SIGAR_INLINE int proc_isthread(sigar_t *sigar, char *pidstr, int len) +{ + char buffer[BUFSIZ], *ptr=buffer; + int fd, n, offset=sigar->proc_signal_offset; + + /* sprintf(buffer, "/proc/%s/stat", pidstr) */ + memcpy(ptr, PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT)); + ptr += SSTRLEN(PROCP_FS_ROOT); + + memcpy(ptr, pidstr, len); + ptr += len; + + memcpy(ptr, PROC_PSTAT, SSTRLEN(PROC_PSTAT)); + ptr += SSTRLEN(PROC_PSTAT); + + *ptr = '\0'; + + if ((fd = open(buffer, O_RDONLY)) < 0) { + /* unlikely if pid was from readdir proc */ + return 0; + } + + n = read(fd, buffer, sizeof(buffer)); + close(fd); + + if (n < 0) { + return 0; /* chances: slim..none */ + } + + buffer[n--] = '\0'; + + /* exit_signal is the second to last field so we look backwards. + * XXX if newer kernels drop more turds in this file we'll need + * to go the other way. luckily linux has no real api for this shit. + */ + + /* skip trailing crap */ + while ((n > 0) && !isdigit(buffer[n--])) ; + + while (offset-- > 0) { + /* skip last field */ + while ((n > 0) && isdigit(buffer[n--])) ; + + /* skip whitespace */ + while ((n > 0) && !isdigit(buffer[n--])) ; + } + + if (n < 3) { + return 0; /* hulk smashed /proc? */ + } + + ptr = &buffer[n]; + /* + * '17' == SIGCHLD == real process. + * '33' and '0' are threads + */ + if ((*ptr++ == '1') && + (*ptr++ == '7') && + (*ptr++ == ' ')) + { + return 0; + } + + return 1; +} + +int sigar_os_proc_list_get(sigar_t *sigar, + sigar_proc_list_t *proclist) +{ + DIR *dirp = opendir(PROCP_FS_ROOT); + struct dirent *ent, dbuf; + register const int threadbadhack = !sigar->has_nptl; + + if (!dirp) { + return errno; + } + + if (threadbadhack && (sigar->proc_signal_offset == -1)) { + sigar->proc_signal_offset = get_proc_signal_offset(); + } + + while (readdir_r(dirp, &dbuf, &ent) == 0) { + if (!ent) { + break; + } + + if (!sigar_isdigit(*ent->d_name)) { + continue; + } + + if (threadbadhack && + proc_isthread(sigar, ent->d_name, strlen(ent->d_name))) + { + continue; + } + + /* XXX: more sanity checking */ + + SIGAR_PROC_LIST_GROW(proclist); + + proclist->data[proclist->number++] = + strtoul(ent->d_name, NULL, 10); + } + + closedir(dirp); + + return SIGAR_OK; +} + +static int proc_stat_read(sigar_t *sigar, sigar_pid_t pid) +{ + char buffer[BUFSIZ], *ptr=buffer, *tmp; + unsigned int len; + linux_proc_stat_t *pstat = &sigar->last_proc_stat; + int status; + + time_t timenow = time(NULL); + + /* + * short-lived cache read/parse of last /proc/pid/stat + * as this info is spread out across a few functions. + */ + if (pstat->pid == pid) { + if ((timenow - pstat->mtime) < SIGAR_LAST_PROC_EXPIRE) { + return SIGAR_OK; + } + } + + pstat->pid = pid; + pstat->mtime = timenow; + + status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTAT); + + if (status != SIGAR_OK) { + return status; + } + + if (!(ptr = strchr(ptr, '('))) { + return EINVAL; + } + if (!(tmp = strrchr(++ptr, ')'))) { + return EINVAL; + } + len = tmp-ptr; + + if (len >= sizeof(pstat->name)) { + len = sizeof(pstat->name)-1; + } + + /* (1,2) */ + memcpy(pstat->name, ptr, len); + pstat->name[len] = '\0'; + ptr = tmp+1; + + SIGAR_SKIP_SPACE(ptr); + pstat->state = *ptr++; /* (3) */ + SIGAR_SKIP_SPACE(ptr); + + pstat->ppid = sigar_strtoul(ptr); /* (4) */ + ptr = sigar_skip_token(ptr); /* (5) pgrp */ + ptr = sigar_skip_token(ptr); /* (6) session */ + pstat->tty = sigar_strtoul(ptr); /* (7) */ + ptr = sigar_skip_token(ptr); /* (8) tty pgrp */ + + ptr = sigar_skip_token(ptr); /* (9) flags */ + pstat->minor_faults = sigar_strtoull(ptr); /* (10) */ + ptr = sigar_skip_token(ptr); /* (11) cmin flt */ + pstat->major_faults = sigar_strtoull(ptr); /* (12) */ + ptr = sigar_skip_token(ptr); /* (13) cmaj flt */ + + pstat->utime = SIGAR_TICK2MSEC(sigar_strtoull(ptr)); /* (14) */ + pstat->stime = SIGAR_TICK2MSEC(sigar_strtoull(ptr)); /* (15) */ + + ptr = sigar_skip_token(ptr); /* (16) cutime */ + ptr = sigar_skip_token(ptr); /* (17) cstime */ + + pstat->priority = sigar_strtoul(ptr); /* (18) */ + pstat->nice = sigar_strtoul(ptr); /* (19) */ + + ptr = sigar_skip_token(ptr); /* (20) timeout */ + ptr = sigar_skip_token(ptr); /* (21) it_real_value */ + + pstat->start_time = sigar_strtoul(ptr); /* (22) */ + pstat->start_time /= sigar->ticks; + pstat->start_time += sigar->boot_time; /* seconds */ + pstat->start_time *= 1000; /* milliseconds */ + + pstat->vsize = sigar_strtoull(ptr); /* (23) */ + pstat->rss = pageshift(sigar_strtoull(ptr)); /* (24) */ + + ptr = sigar_skip_token(ptr); /* (25) rlim */ + ptr = sigar_skip_token(ptr); /* (26) startcode */ + ptr = sigar_skip_token(ptr); /* (27) endcode */ + ptr = sigar_skip_token(ptr); /* (28) startstack */ + ptr = sigar_skip_token(ptr); /* (29) kstkesp */ + ptr = sigar_skip_token(ptr); /* (30) kstkeip */ + ptr = sigar_skip_token(ptr); /* (31) signal */ + ptr = sigar_skip_token(ptr); /* (32) blocked */ + ptr = sigar_skip_token(ptr); /* (33) sigignore */ + ptr = sigar_skip_token(ptr); /* (34) sigcache */ + ptr = sigar_skip_token(ptr); /* (35) wchan */ + ptr = sigar_skip_token(ptr); /* (36) nswap */ + ptr = sigar_skip_token(ptr); /* (37) cnswap */ + ptr = sigar_skip_token(ptr); /* (38) exit_signal */ + + pstat->processor = sigar_strtoul(ptr); /* (39) */ + + return SIGAR_OK; +} + +int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_mem_t *procmem) +{ + char buffer[BUFSIZ], *ptr=buffer; + int status = proc_stat_read(sigar, pid); + linux_proc_stat_t *pstat = &sigar->last_proc_stat; + + procmem->minor_faults = pstat->minor_faults; + procmem->major_faults = pstat->major_faults; + procmem->page_faults = + procmem->minor_faults + procmem->major_faults; + + status = SIGAR_PROC_FILE2STR(buffer, pid, "/statm"); + + if (status != SIGAR_OK) { + return status; + } + + procmem->size = pageshift(sigar_strtoull(ptr)); + procmem->resident = pageshift(sigar_strtoull(ptr)); + procmem->share = pageshift(sigar_strtoull(ptr)); + + return SIGAR_OK; +} + +#define NO_ID_MSG "[proc_cred] /proc/%lu" PROC_PSTATUS " missing " + +int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_cred_t *proccred) +{ + char buffer[BUFSIZ], *ptr; + int status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTATUS); + + if (status != SIGAR_OK) { + return status; + } + + if ((ptr = strstr(buffer, "\nUid:"))) { + ptr = sigar_skip_token(ptr); + + proccred->uid = sigar_strtoul(ptr); + proccred->euid = sigar_strtoul(ptr); + } + else { + sigar_log_printf(sigar, SIGAR_LOG_WARN, + NO_ID_MSG "Uid", pid); + return ENOENT; + } + + if ((ptr = strstr(ptr, "\nGid:"))) { + ptr = sigar_skip_token(ptr); + + proccred->gid = sigar_strtoul(ptr); + proccred->egid = sigar_strtoul(ptr); + } + else { + sigar_log_printf(sigar, SIGAR_LOG_WARN, + NO_ID_MSG "Gid", pid); + return ENOENT; + } + + return SIGAR_OK; +} + +int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_time_t *proctime) +{ + int status = proc_stat_read(sigar, pid); + linux_proc_stat_t *pstat = &sigar->last_proc_stat; + + if (status != SIGAR_OK) { + return status; + } + + proctime->user = pstat->utime; + proctime->sys = pstat->stime; + proctime->total = proctime->user + proctime->sys; + proctime->start_time = pstat->start_time; + + return SIGAR_OK; +} + +static int proc_status_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_state_t *procstate) +{ + char buffer[BUFSIZ], *ptr; + int status = SIGAR_PROC_FILE2STR(buffer, pid, PROC_PSTATUS); + + if (status != SIGAR_OK) { + return status; + } + + ptr = strstr(buffer, "\nThreads:"); + if (ptr) { + /* 2.6+ kernel only */ + ptr = sigar_skip_token(ptr); + procstate->threads = sigar_strtoul(ptr); + } + else { + procstate->threads = SIGAR_FIELD_NOTIMPL; + } + + return SIGAR_OK; +} + +int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_state_t *procstate) +{ + int status = proc_stat_read(sigar, pid); + linux_proc_stat_t *pstat = &sigar->last_proc_stat; + + if (status != SIGAR_OK) { + return status; + } + + memcpy(procstate->name, pstat->name, sizeof(procstate->name)); + procstate->state = pstat->state; + + procstate->ppid = pstat->ppid; + procstate->tty = pstat->tty; + procstate->priority = pstat->priority; + procstate->nice = pstat->nice; + procstate->processor = pstat->processor; + + if (sigar_cpu_core_rollup(sigar)) { + procstate->processor /= sigar->lcpu; + } + + proc_status_get(sigar, pid, procstate); + + return SIGAR_OK; +} + +int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs) +{ + return sigar_procfs_args_get(sigar, pid, procargs); +} + +/* glibc 2.8 XXX use sysconf(_SC_ARG_MAX) */ +#ifndef ARG_MAX +#define ARG_MAX 131072 +#endif + +int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_env_t *procenv) +{ + int fd; + char buffer[ARG_MAX]; /* XXX: ARG_MAX == 130k */ + char name[BUFSIZ]; + size_t len; + char *ptr, *end; + + /* optimize if pid == $$ and type == ENV_KEY */ + SIGAR_PROC_ENV_KEY_LOOKUP(); + + (void)SIGAR_PROC_FILENAME(name, pid, "/environ"); + + if ((fd = open(name, O_RDONLY)) < 0) { + if (errno == ENOENT) { + return ESRCH; + } + return errno; + } + + len = read(fd, buffer, sizeof(buffer)); + + close(fd); + + buffer[len] = '\0'; + ptr = buffer; + + end = buffer + len; + while (ptr < end) { + char *val = strchr(ptr, '='); + int klen, vlen, status; + char key[128]; /* XXX is there a max key size? */ + + if (val == NULL) { + /* not key=val format */ + break; + } + + klen = val - ptr; + SIGAR_SSTRCPY(key, ptr); + key[klen] = '\0'; + ++val; + + vlen = strlen(val); + status = procenv->env_getter(procenv->data, + key, klen, val, vlen); + + if (status != SIGAR_OK) { + /* not an error; just stop iterating */ + break; + } + + ptr += (klen + 1 + vlen + 1); + } + + return SIGAR_OK; +} + +int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_fd_t *procfd) +{ + int status = + sigar_proc_fd_count(sigar, pid, &procfd->total); + + return status; +} + +int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_exe_t *procexe) +{ + int len; + char name[BUFSIZ]; + + (void)SIGAR_PROC_FILENAME(name, pid, "/cwd"); + + if ((len = readlink(name, procexe->cwd, + sizeof(procexe->cwd)-1)) < 0) + { + return errno; + } + + procexe->cwd[len] = '\0'; + + (void)SIGAR_PROC_FILENAME(name, pid, "/exe"); + + if ((len = readlink(name, procexe->name, + sizeof(procexe->name)-1)) < 0) + { + return errno; + } + + procexe->name[len] = '\0'; + + (void)SIGAR_PROC_FILENAME(name, pid, "/root"); + + if ((len = readlink(name, procexe->root, + sizeof(procexe->root)-1)) < 0) + { + return errno; + } + + procexe->root[len] = '\0'; + + return SIGAR_OK; +} + +int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_modules_t *procmods) +{ + FILE *fp; + char buffer[BUFSIZ], *ptr; + unsigned long inode, last_inode = 0; + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/maps"); + + if (!(fp = fopen(buffer, "r"))) { + return errno; + } + + while ((ptr = fgets(buffer, sizeof(buffer), fp))) { + int len, status; + /* skip region, flags, offset, dev */ + ptr = sigar_skip_multiple_token(ptr, 4); + inode = sigar_strtoul(ptr); + + if ((inode == 0) || (inode == last_inode)) { + last_inode = 0; + continue; + } + + last_inode = inode; + SIGAR_SKIP_SPACE(ptr); + len = strlen(ptr); + ptr[len-1] = '\0'; /* chop \n */ + + status = + procmods->module_getter(procmods->data, + ptr, len-1); + + if (status != SIGAR_OK) { + /* not an error; just stop iterating */ + break; + } + } + + fclose(fp); + + return SIGAR_OK; +} + +int sigar_thread_cpu_get(sigar_t *sigar, + sigar_uint64_t id, + sigar_thread_cpu_t *cpu) +{ + struct tms now; + + if (id != 0) { + return SIGAR_ENOTIMPL; + } + + times(&now); + + cpu->user = SIGAR_TICK2NSEC(now.tms_utime); + cpu->sys = SIGAR_TICK2NSEC(now.tms_stime); + cpu->total = SIGAR_TICK2NSEC(now.tms_utime + now.tms_stime); + + return SIGAR_OK; +} + +#include + +int sigar_os_fs_type_get(sigar_file_system_t *fsp) +{ + char *type = fsp->sys_type_name; + + switch (*type) { + case 'e': + if (strnEQ(type, "ext", 3)) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'g': + if (strEQ(type, "gfs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'h': + if (strEQ(type, "hpfs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'j': + if (strnEQ(type, "jfs", 3)) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'o': + if (strnEQ(type, "ocfs", 4)) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'p': + if (strnEQ(type, "psfs", 4)) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'r': + if (strEQ(type, "reiserfs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'v': + if (strEQ(type, "vzfs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'x': + if (strEQ(type, "xfs") || strEQ(type, "xiafs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + } + + return fsp->type; +} + +int sigar_file_system_list_get(sigar_t *sigar, + sigar_file_system_list_t *fslist) +{ + struct mntent ent; + char buf[1025]; /* buffer for strings within ent */ + FILE *fp; + sigar_file_system_t *fsp; + + if (!(fp = setmntent(MOUNTED, "r"))) { + return errno; + } + + sigar_file_system_list_create(fslist); + + while (getmntent_r(fp, &ent, buf, sizeof(buf))) { + SIGAR_FILE_SYSTEM_LIST_GROW(fslist); + + fsp = &fslist->data[fslist->number++]; + + fsp->type = SIGAR_FSTYPE_UNKNOWN; /* unknown, will be set later */ + SIGAR_SSTRCPY(fsp->dir_name, ent.mnt_dir); + SIGAR_SSTRCPY(fsp->dev_name, ent.mnt_fsname); + SIGAR_SSTRCPY(fsp->sys_type_name, ent.mnt_type); + SIGAR_SSTRCPY(fsp->options, ent.mnt_opts); + sigar_fs_type_get(fsp); + } + + endmntent(fp); + + return SIGAR_OK; +} + +#define ST_MAJOR(sb) major((sb).st_rdev) +#define ST_MINOR(sb) minor((sb).st_rdev) + +static int get_iostat_sys(sigar_t *sigar, + const char *dirname, + sigar_disk_usage_t *disk, + sigar_iodev_t **iodev) +{ + char stat[1025], dev[1025]; + char *name, *ptr, *fsdev; + int partition, status; + + if (!(*iodev = sigar_iodev_get(sigar, dirname))) { + return ENXIO; + } + + name = fsdev = (*iodev)->name; + + if (SIGAR_NAME_IS_DEV(name)) { + name += SSTRLEN(SIGAR_DEV_PREFIX); /* strip "/dev/" */ + } + + while (!sigar_isdigit(*fsdev)) { + fsdev++; + } + + partition = strtoul(fsdev, NULL, 0); + *fsdev = '\0'; + + snprintf(stat, sizeof(stat), + SYS_BLOCK "/%s/%s%d/stat", name, name, partition); + + status = sigar_file2str(stat, dev, sizeof(dev)); + if (status != SIGAR_OK) { + return status; + } + + ptr = dev; + ptr = sigar_skip_token(ptr); + disk->reads = sigar_strtoull(ptr); + ptr = sigar_skip_token(ptr); + disk->writes = sigar_strtoull(ptr); + + disk->read_bytes = SIGAR_FIELD_NOTIMPL; + disk->write_bytes = SIGAR_FIELD_NOTIMPL; + disk->queue = SIGAR_FIELD_NOTIMPL; + + return SIGAR_OK; +} + +static int get_iostat_proc_dstat(sigar_t *sigar, + const char *dirname, + sigar_disk_usage_t *disk, + sigar_iodev_t **iodev, + sigar_disk_usage_t *device_usage) +{ + FILE *fp; + char buffer[1025]; + char *ptr; + struct stat sb; + int status=ENOENT; + + SIGAR_DISK_STATS_INIT(device_usage); + + if (!(*iodev = sigar_iodev_get(sigar, dirname))) { + return ENXIO; + } + + if (stat((*iodev)->name, &sb) < 0) { + return errno; + } + + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + PROC_DISKSTATS " %s -> %s [%d,%d]", + dirname, (*iodev)->name, + ST_MAJOR(sb), ST_MINOR(sb)); + } + + if (!(fp = fopen(PROC_DISKSTATS, "r"))) { + return errno; + } + + while ((ptr = fgets(buffer, sizeof(buffer), fp))) { + unsigned long major, minor; + + major = sigar_strtoul(ptr); + minor = sigar_strtoul(ptr); + + if ((major == ST_MAJOR(sb)) && + ((minor == ST_MINOR(sb)) || (minor == 0))) + { + int num; + unsigned long + rio, rmerge, rsect, ruse, + wio, wmerge, wsect, wuse, + running, use, aveq; + + ptr = sigar_skip_token(ptr); /* name */ + + num = sscanf(ptr, + "%lu %lu %lu %lu " + "%lu %lu %lu %lu " + "%lu %lu %lu", + &rio, /* 1 # reads issued */ + &rmerge, /* 2 # reads merged */ + &rsect, /* 3 # sectors read */ + &ruse, /* 4 # millis spent reading */ + &wio, /* 5 # writes completed */ + &wmerge, /* 6 # writes merged */ + &wsect, /* 7 # sectors written */ + &wuse, /* 8 # millis spent writing */ + &running, /* 9 # I/Os currently in progress */ + &use, /* 10 # millis spent doing I/Os */ + &aveq); /* 11 # of millis spent doing I/Os (weighted) */ + + if (num == 11) { + disk->rtime = ruse; + disk->wtime = wuse; + disk->time = use; + disk->qtime = aveq; + } + else if (num == 4) { + wio = rsect; + rsect = rmerge; + wsect = ruse; + disk->time = disk->qtime = SIGAR_FIELD_NOTIMPL; + } + else { + status = ENOENT; + } + + disk->reads = rio; + disk->writes = wio; + disk->read_bytes = rsect; + disk->write_bytes = wsect; + + /* convert sectors to bytes (512 is fixed size in 2.6 kernels) */ + disk->read_bytes *= 512; + disk->write_bytes *= 512; + + if (minor == ST_MINOR(sb)) { + status = SIGAR_OK; + break; + } + else if (minor == 0) { + memcpy(device_usage, disk, sizeof(*device_usage)); + } + } + } + + fclose(fp); + + return status; +} + +static int get_iostat_procp(sigar_t *sigar, + const char *dirname, + sigar_disk_usage_t *disk, + sigar_iodev_t **iodev) +{ + FILE *fp; + char buffer[1025]; + char *ptr; + struct stat sb; + + if (!(*iodev = sigar_iodev_get(sigar, dirname))) { + return ENXIO; + } + + if (stat((*iodev)->name, &sb) < 0) { + return errno; + } + + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + PROC_PARTITIONS " %s -> %s [%d,%d]", + dirname, (*iodev)->name, + ST_MAJOR(sb), ST_MINOR(sb)); + } + + if (!(fp = fopen(PROC_PARTITIONS, "r"))) { + return errno; + } + + (void)fgets(buffer, sizeof(buffer), fp); /* skip header */ + while ((ptr = fgets(buffer, sizeof(buffer), fp))) { + unsigned long major, minor; + + major = sigar_strtoul(ptr); + minor = sigar_strtoul(ptr); + + if ((major == ST_MAJOR(sb)) && (minor == ST_MINOR(sb))) { + ptr = sigar_skip_token(ptr); /* blocks */ + ptr = sigar_skip_token(ptr); /* name */ + disk->reads = sigar_strtoull(ptr); /* rio */ + ptr = sigar_skip_token(ptr); /* rmerge */ + disk->read_bytes = sigar_strtoull(ptr); /* rsect */ + disk->rtime = sigar_strtoull(ptr); /* ruse */ + disk->writes = sigar_strtoull(ptr); /* wio */ + ptr = sigar_skip_token(ptr); /* wmerge */ + disk->write_bytes = sigar_strtoull(ptr); /* wsect */ + disk->wtime = sigar_strtoull(ptr); /* wuse */ + ptr = sigar_skip_token(ptr); /* running */ + disk->time = sigar_strtoull(ptr); /* use */ + disk->qtime = sigar_strtoull(ptr); /* aveq */ + + /* convert sectors to bytes (512 is fixed size in 2.6 kernels) */ + disk->read_bytes *= 512; + disk->write_bytes *= 512; + + fclose(fp); + return SIGAR_OK; + } + } + + fclose(fp); + + return ENOENT; +} + +int sigar_disk_usage_get(sigar_t *sigar, const char *name, + sigar_disk_usage_t *disk) +{ + int status; + sigar_iodev_t *iodev = NULL; + sigar_disk_usage_t device_usage; + SIGAR_DISK_STATS_INIT(disk); + + /* + * 2.2 has metrics /proc/stat, but wtf is the device mapping? + * 2.4 has /proc/partitions w/ the metrics. + * 2.6 has /proc/partitions w/o the metrics. + * instead the metrics are within the /proc-like /sys filesystem. + * also has /proc/diskstats + */ + switch (sigar->iostat) { + case IOSTAT_SYS: + status = get_iostat_sys(sigar, name, disk, &iodev); + break; + case IOSTAT_DISKSTATS: + status = get_iostat_proc_dstat(sigar, name, disk, &iodev, &device_usage); + break; + case IOSTAT_PARTITIONS: + status = get_iostat_procp(sigar, name, disk, &iodev); + break; + /* + * case IOSTAT_SOME_OTHER_WIERD_THING: + * break; + */ + case IOSTAT_NONE: + default: + status = ENOENT; + break; + } + + if ((status == SIGAR_OK) && iodev) { + sigar_uptime_t uptime; + sigar_uint64_t interval, ios; + double tput, util; + sigar_disk_usage_t *partition_usage=NULL; + + sigar_uptime_get(sigar, &uptime); + + if (iodev->is_partition && + (sigar->iostat == IOSTAT_DISKSTATS)) + { + /* 2.6 kernels do not have per-partition times */ + partition_usage = disk; + disk = &device_usage; + } + + disk->snaptime = uptime.uptime; + + if (iodev->disk.snaptime) { + interval = disk->snaptime - iodev->disk.snaptime; + } + else { + interval = disk->snaptime; + } + + ios = + (disk->reads - iodev->disk.reads) + + (disk->writes - iodev->disk.writes); + + if (disk->time == SIGAR_FIELD_NOTIMPL) { + disk->service_time = SIGAR_FIELD_NOTIMPL; + } + else { + tput = ((double)ios) * HZ / interval; + util = ((double)(disk->time - iodev->disk.time)) / interval * HZ; + disk->service_time = tput ? util / tput : 0.0; + } + if (disk->qtime == SIGAR_FIELD_NOTIMPL) { + disk->queue = SIGAR_FIELD_NOTIMPL; + } + else { + util = ((double)(disk->qtime - iodev->disk.qtime)) / interval; + disk->queue = util / 1000.0; + } + + memcpy(&iodev->disk, disk, sizeof(iodev->disk)); + if (partition_usage) { + partition_usage->service_time = disk->service_time; + partition_usage->queue = disk->queue; + } + } + + return status; +} + +int sigar_file_system_usage_get(sigar_t *sigar, + const char *dirname, + sigar_file_system_usage_t *fsusage) +{ + int status = sigar_statvfs(sigar, dirname, fsusage); + + if (status != SIGAR_OK) { + return status; + } + + fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage); + + (void)sigar_disk_usage_get(sigar, dirname, &fsusage->disk); + + return SIGAR_OK; +} + +static SIGAR_INLINE char *cpu_info_strval(char *ptr) +{ + if ((ptr = strchr(ptr, ':'))) { + ptr++; + while (isspace (*ptr)) ptr++; + return ptr; + } + return NULL; +} + +static SIGAR_INLINE void cpu_info_strcpy(char *ptr, char *buf, int len) +{ + int slen; + ptr = cpu_info_strval(ptr); + if (!ptr) { + return; + } + slen = strlen(ptr); + strncpy(buf, ptr, len); + buf[len] = '\0'; + if (slen < len) { + buf[slen-1] = '\0'; /* rid \n */ + } +} + +static int get_cpu_info(sigar_t *sigar, sigar_cpu_info_t *info, + FILE *fp) +{ + char buffer[BUFSIZ], *ptr; + + int found = 0; + + /* UML vm wont have "cpu MHz" or "cache size" fields */ + info->mhz = 0; + info->cache_size = 0; + +#ifdef __powerpc64__ + SIGAR_SSTRCPY(info->vendor, "IBM"); +#endif + + while ((ptr = fgets(buffer, sizeof(buffer), fp))) { + switch (*ptr) { + case 'p': /* processor : 0 */ + if (strnEQ(ptr, "processor", 9)) { + found = 1; + } + break; + case 'v': + /* "vendor_id" or "vendor" */ + if (strnEQ(ptr, "vendor", 6)) { + cpu_info_strcpy(ptr, info->vendor, sizeof(info->vendor)); + if (strEQ(info->vendor, "GenuineIntel")) { + SIGAR_SSTRCPY(info->vendor, "Intel"); + } + else if (strEQ(info->vendor, "AuthenticAMD")) { + SIGAR_SSTRCPY(info->vendor, "AMD"); + } + } + break; + case 'f': + if (strnEQ(ptr, "family", 6)) { + /* IA64 version of "model name" */ + cpu_info_strcpy(ptr, info->model, sizeof(info->model)); + sigar_cpu_model_adjust(sigar, info); + } + break; + case 'm': + if (strnEQ(ptr, "model name", 10)) { + cpu_info_strcpy(ptr, info->model, sizeof(info->model)); + sigar_cpu_model_adjust(sigar, info); + } + break; + case 'c': + if (strnEQ(ptr, "cpu MHz", 7)) { + ptr = cpu_info_strval(ptr); + info->mhz = atoi(ptr); + } + else if (strnEQ(ptr, "cache size", 10)) { + ptr = cpu_info_strval(ptr); + info->cache_size = sigar_strtoul(ptr); + } +#ifdef __powerpc64__ + /* each /proc/cpuinfo entry looks like so: + * processor : 0 + * cpu : POWER5 (gr) + * clock : 1656.392000MHz + * revision : 2.2 + */ + else if (strnEQ(ptr, "clock", 5)) { + ptr = cpu_info_strval(ptr); + info->mhz = atoi(ptr); + } + else if (strnEQ(ptr, "cpu", 3)) { + cpu_info_strcpy(ptr, info->model, sizeof(info->model)); + + if ((ptr = strchr(info->model, ' '))) { + /* "POWER5 (gr)" -> "POWER5" */ + *ptr = '\0'; + } + } +#endif + break; + /* lone \n means end of info for this processor */ + case '\n': + return found; + } + } + + return found; +} + +/* /proc/cpuinfo MHz will change w/ AMD + PowerNow */ +static void get_cpuinfo_max_freq(sigar_cpu_info_t *cpu_info, int num) +{ + int status; + char max_freq[PATH_MAX]; + snprintf(max_freq, sizeof(max_freq), + "/sys/devices/system/cpu/cpu%d" + "/cpufreq/cpuinfo_max_freq", num); + + status = + sigar_file2str(max_freq, max_freq, sizeof(max_freq)-1); + + if (status == SIGAR_OK) { + cpu_info->mhz_max = atoi(max_freq) / 1000; + } +} + +static void get_cpuinfo_min_freq(sigar_cpu_info_t *cpu_info, int num) +{ + int status; + char min_freq[PATH_MAX]; + snprintf(min_freq, sizeof(min_freq), + "/sys/devices/system/cpu/cpu%d" + "/cpufreq/cpuinfo_min_freq", num); + + status = + sigar_file2str(min_freq, min_freq, sizeof(min_freq)-1); + + if (status == SIGAR_OK) { + cpu_info->mhz_min = atoi(min_freq) / 1000; + } +} + +int sigar_cpu_info_list_get(sigar_t *sigar, + sigar_cpu_info_list_t *cpu_infos) +{ + FILE *fp; + int core_rollup = sigar_cpu_core_rollup(sigar), i=0; + + if (!(fp = fopen(PROC_FS_ROOT "cpuinfo", "r"))) { + return errno; + } + + (void)sigar_cpu_total_count(sigar); + sigar_cpu_info_list_create(cpu_infos); + + while (get_cpu_info(sigar, &cpu_infos->data[cpu_infos->number], fp)) { + sigar_cpu_info_t *info; + + if (core_rollup && (i++ % sigar->lcpu)) { + continue; /* fold logical processors */ + } + + info = &cpu_infos->data[cpu_infos->number]; + get_cpuinfo_max_freq(info, cpu_infos->number); + get_cpuinfo_min_freq(info, cpu_infos->number); + + info->total_cores = sigar->ncpu; + info->cores_per_socket = sigar->lcpu; + info->total_sockets = sigar_cpu_socket_count(sigar); + + ++cpu_infos->number; + SIGAR_CPU_INFO_LIST_GROW(cpu_infos); + } + + fclose(fp); + + return SIGAR_OK; +} + +static SIGAR_INLINE unsigned int hex2int(const char *x, int len) +{ + int i; + unsigned int j; + + for (i=0, j=0; isize = routelist->number = 0; + + if (!(fp = fopen(PROC_FS_ROOT "net/route", "r"))) { + return errno; + } + + sigar_net_route_list_create(routelist); + + (void)fgets(buffer, sizeof(buffer), fp); /* skip header */ + while (fgets(buffer, sizeof(buffer), fp)) { + int num; + + SIGAR_NET_ROUTE_LIST_GROW(routelist); + route = &routelist->data[routelist->number++]; + + /* XXX rid sscanf */ + num = sscanf(buffer, ROUTE_FMT, + route->ifname, net_addr, gate_addr, + &flags, &route->refcnt, &route->use, + &route->metric, mask_addr, + &route->mtu, &route->window, &route->irtt); + + if ((num < 10) || !(flags & RTF_UP)) { + --routelist->number; + continue; + } + + route->flags = flags; + + sigar_net_address_set(route->destination, hex2int(net_addr, HEX_ENT_LEN)); + sigar_net_address_set(route->gateway, hex2int(gate_addr, HEX_ENT_LEN)); + sigar_net_address_set(route->mask, hex2int(mask_addr, HEX_ENT_LEN)); + } + + fclose(fp); + + return SIGAR_OK; +} + +int sigar_net_interface_stat_get(sigar_t *sigar, const char *name, + sigar_net_interface_stat_t *ifstat) +{ + int found = 0; + char buffer[BUFSIZ]; + FILE *fp = fopen(PROC_FS_ROOT "net/dev", "r"); + + if (!fp) { + return errno; + } + + /* skip header */ + fgets(buffer, sizeof(buffer), fp); + fgets(buffer, sizeof(buffer), fp); + + while (fgets(buffer, sizeof(buffer), fp)) { + char *ptr, *dev; + + dev = buffer; + while (isspace(*dev)) { + dev++; + } + + if (!(ptr = strchr(dev, ':'))) { + continue; + } + + *ptr++ = 0; + + if (!strEQ(dev, name)) { + continue; + } + + found = 1; + ifstat->rx_bytes = sigar_strtoull(ptr); + ifstat->rx_packets = sigar_strtoull(ptr); + ifstat->rx_errors = sigar_strtoull(ptr); + ifstat->rx_dropped = sigar_strtoull(ptr); + ifstat->rx_overruns = sigar_strtoull(ptr); + ifstat->rx_frame = sigar_strtoull(ptr); + + /* skip: compressed multicast */ + ptr = sigar_skip_multiple_token(ptr, 2); + + ifstat->tx_bytes = sigar_strtoull(ptr); + ifstat->tx_packets = sigar_strtoull(ptr); + ifstat->tx_errors = sigar_strtoull(ptr); + ifstat->tx_dropped = sigar_strtoull(ptr); + ifstat->tx_overruns = sigar_strtoull(ptr); + ifstat->tx_collisions = sigar_strtoull(ptr); + ifstat->tx_carrier = sigar_strtoull(ptr); + + ifstat->speed = SIGAR_FIELD_NOTIMPL; + + break; + } + + fclose(fp); + + return found ? SIGAR_OK : ENXIO; +} + +static SIGAR_INLINE void convert_hex_address(sigar_net_address_t *address, + char *ptr, int len) +{ + if (len > HEX_ENT_LEN) { + int i; + for (i=0; i<=3; i++, ptr+=HEX_ENT_LEN) { + address->addr.in6[i] = hex2int(ptr, HEX_ENT_LEN); + } + + address->family = SIGAR_AF_INET6; + } + else { + address->addr.in = + (len == HEX_ENT_LEN) ? hex2int(ptr, HEX_ENT_LEN) : 0; + + address->family = SIGAR_AF_INET; + } +} + +typedef struct { + sigar_net_connection_list_t *connlist; + sigar_net_connection_t *conn; + unsigned long port; +} net_conn_getter_t; + +static int proc_net_walker(sigar_net_connection_walker_t *walker, + sigar_net_connection_t *conn) +{ + net_conn_getter_t *getter = + (net_conn_getter_t *)walker->data; + + if (getter->connlist) { + SIGAR_NET_CONNLIST_GROW(getter->connlist); + memcpy(&getter->connlist->data[getter->connlist->number++], + conn, sizeof(*conn)); + } + else { + if ((getter->port == conn->local_port) && + (conn->remote_port == 0)) + { + memcpy(getter->conn, conn, sizeof(*conn)); + return !SIGAR_OK; /* break loop */ + } + } + + return SIGAR_OK; /* continue loop */ +} + +#define SKIP_WHILE(p, c) while (*p == c) p++ +#define SKIP_PAST(p, c) \ + while(*p && (*p != c)) p++; \ + SKIP_WHILE(p, c) + +typedef struct { + FILE *fp; + int (*close)(FILE *); +} xproc_t; + +static FILE *xproc_open(const char *command, xproc_t *xproc) +{ + struct stat sb; + if (stat(command, &sb) == 0) { + if (sb.st_mode & S_IXUSR) { + /* executable script for testing large + * conn table where we can sleep() to better + * simulate /proc/net/tcp behavior + */ + xproc->fp = popen(command, "r"); + xproc->close = pclose; + } + else { + xproc->fp = fopen(command, "r"); + xproc->close = fclose; + } + return xproc->fp; + } + else { + return NULL; + } +} + +static int proc_net_read(sigar_net_connection_walker_t *walker, + const char *fname, + int type) +{ + FILE *fp = NULL; + char buffer[8192]; + sigar_t *sigar = walker->sigar; + char *ptr = sigar->proc_net; + int flags = walker->flags; + xproc_t xproc = { NULL, fclose }; + + if (ptr) { + snprintf(buffer, sizeof(buffer), + "%s/%s", ptr, + fname + sizeof(PROC_FS_ROOT)-1); + + if ((fp = xproc_open(buffer, &xproc))) { + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[proc_net] using %s", + buffer); + } + } + else if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[proc_net] cannot open %s", + buffer); + } + } + + if (!(fp || (fp = fopen(fname, "r")))) { + return errno; + } + + fgets(buffer, sizeof(buffer), fp); /* skip header */ + + while ((ptr = fgets(buffer, sizeof(buffer), fp))) { + sigar_net_connection_t conn; + char *laddr, *raddr; + int laddr_len=0, raddr_len=0; + int more; + + /* skip leading space */ + SKIP_WHILE(ptr, ' '); + + /* skip "%d: " */ + SKIP_PAST(ptr, ' '); + + laddr = ptr; + while (*ptr && (*ptr != ':')) { + laddr_len++; + ptr++; + } + SKIP_WHILE(ptr, ':'); + + conn.local_port = (strtoul(ptr, &ptr, 16) & 0xffff); + + SKIP_WHILE(ptr, ' '); + + raddr = ptr; + while (*ptr && (*ptr != ':')) { + raddr_len++; + ptr++; + } + SKIP_WHILE(ptr, ':'); + + conn.remote_port = (strtoul(ptr, &ptr, 16) & 0xffff); + + SKIP_WHILE(ptr, ' '); + + if (!((conn.remote_port && (flags & SIGAR_NETCONN_CLIENT)) || + (!conn.remote_port && (flags & SIGAR_NETCONN_SERVER)))) + { + continue; + } + + conn.type = type; + + convert_hex_address(&conn.local_address, + laddr, laddr_len); + + convert_hex_address(&conn.remote_address, + raddr, raddr_len); + + /* SIGAR_TCP_* currently matches TCP_* in linux/tcp.h */ + conn.state = hex2int(ptr, 2); + ptr += 2; + SKIP_WHILE(ptr, ' '); + + conn.send_queue = hex2int(ptr, HEX_ENT_LEN); + ptr += HEX_ENT_LEN+1; /* tx + ':' */; + + conn.receive_queue = hex2int(ptr, HEX_ENT_LEN); + ptr += HEX_ENT_LEN; + SKIP_WHILE(ptr, ' '); + + SKIP_PAST(ptr, ' '); /* tr:tm->whem */ + SKIP_PAST(ptr, ' '); /* retrnsmt */ + + conn.uid = sigar_strtoul(ptr); + + SKIP_WHILE(ptr, ' '); + SKIP_PAST(ptr, ' '); /* timeout */ + + conn.inode = sigar_strtoul(ptr); + + more = walker->add_connection(walker, &conn); + if (more != SIGAR_OK) { + xproc.close(fp); + return SIGAR_OK; + } + } + + xproc.close(fp); + + return SIGAR_OK; +} + +int sigar_net_connection_walk(sigar_net_connection_walker_t *walker) +{ + int flags = walker->flags; + int status; + + if (flags & SIGAR_NETCONN_TCP) { + status = proc_net_read(walker, + PROC_FS_ROOT "net/tcp", + SIGAR_NETCONN_TCP); + + if (status != SIGAR_OK) { + return status; + } + + status = proc_net_read(walker, + PROC_FS_ROOT "net/tcp6", + SIGAR_NETCONN_TCP); + + if (!((status == SIGAR_OK) || (status == ENOENT))) { + return status; + } + } + + if (flags & SIGAR_NETCONN_UDP) { + status = proc_net_read(walker, + PROC_FS_ROOT "net/udp", + SIGAR_NETCONN_UDP); + + if (status != SIGAR_OK) { + return status; + } + + status = proc_net_read(walker, + PROC_FS_ROOT "net/udp6", + SIGAR_NETCONN_UDP); + + if (!((status == SIGAR_OK) || (status == ENOENT))) { + return status; + } + } + + if (flags & SIGAR_NETCONN_RAW) { + status = proc_net_read(walker, + PROC_FS_ROOT "net/raw", + SIGAR_NETCONN_RAW); + + if (status != SIGAR_OK) { + return status; + } + + status = proc_net_read(walker, + PROC_FS_ROOT "net/raw6", + SIGAR_NETCONN_RAW); + + if (!((status == SIGAR_OK) || (status == ENOENT))) { + return status; + } + } + + /* XXX /proc/net/unix */ + + return SIGAR_OK; +} + +int sigar_net_connection_list_get(sigar_t *sigar, + sigar_net_connection_list_t *connlist, + int flags) +{ + int status; + sigar_net_connection_walker_t walker; + net_conn_getter_t getter; + + sigar_net_connection_list_create(connlist); + + getter.conn = NULL; + getter.connlist = connlist; + + walker.sigar = sigar; + walker.flags = flags; + walker.data = &getter; + walker.add_connection = proc_net_walker; + + status = sigar_net_connection_walk(&walker); + + if (status != SIGAR_OK) { + sigar_net_connection_list_destroy(sigar, connlist); + } + + return status; +} + +static int sigar_net_connection_get(sigar_t *sigar, + sigar_net_connection_t *netconn, + unsigned long port, + int flags) +{ + int status; + sigar_net_connection_walker_t walker; + net_conn_getter_t getter; + + getter.conn = netconn; + getter.connlist = NULL; + getter.port = port; + + walker.sigar = sigar; + walker.flags = flags; + walker.data = &getter; + walker.add_connection = proc_net_walker; + + status = sigar_net_connection_walk(&walker); + + return status; +} + +int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig) +{ + FILE *fp; + char addr[32+1], ifname[8+1]; + int status = SIGAR_ENOENT; + int idx, prefix, scope, flags; + + if (!(fp = fopen(PROC_FS_ROOT "net/if_inet6", "r"))) { + return errno; + } + + while (fscanf(fp, "%32s %02x %02x %02x %02x %8s\n", + addr, &idx, &prefix, &scope, &flags, ifname) != EOF) + { + if (strEQ(name, ifname)) { + status = SIGAR_OK; + break; + } + } + + fclose(fp); + + if (status == SIGAR_OK) { + int i=0; + unsigned char *addr6 = (unsigned char *)&(ifconfig->address6.addr.in6); + char *ptr = addr; + + for (i=0; i<16; i++, ptr+=2) { + addr6[i] = (unsigned char)hex2int(ptr, 2); + } + + ifconfig->prefix6_length = prefix; + ifconfig->scope6 = scope; + } + + return status; +} + +#define SNMP_TCP_PREFIX "Tcp: " + +SIGAR_DECLARE(int) +sigar_tcp_get(sigar_t *sigar, + sigar_tcp_t *tcp) +{ + FILE *fp; + char buffer[1024], *ptr=buffer; + int status = SIGAR_ENOENT; + + if (!(fp = fopen(PROC_FS_ROOT "net/snmp", "r"))) { + return errno; + } + + while (fgets(buffer, sizeof(buffer), fp)) { + if (strnEQ(buffer, SNMP_TCP_PREFIX, sizeof(SNMP_TCP_PREFIX)-1)) { + if (fgets(buffer, sizeof(buffer), fp)) { + status = SIGAR_OK; + break; + } + } + } + + fclose(fp); + + if (status == SIGAR_OK) { + /* assuming field order, same in 2.2, 2.4 and 2.6 kernels */ + /* Tcp: RtoAlgorithm RtoMin RtoMax MaxConn */ + ptr = sigar_skip_multiple_token(ptr, 5); + tcp->active_opens = sigar_strtoull(ptr); + tcp->passive_opens = sigar_strtoull(ptr); + tcp->attempt_fails = sigar_strtoull(ptr); + tcp->estab_resets = sigar_strtoull(ptr); + tcp->curr_estab = sigar_strtoull(ptr); + tcp->in_segs = sigar_strtoull(ptr); + tcp->out_segs = sigar_strtoull(ptr); + tcp->retrans_segs = sigar_strtoull(ptr); + tcp->in_errs = sigar_strtoull(ptr); + tcp->out_rsts = sigar_strtoull(ptr); + } + + return status; +} + +static int sigar_proc_nfs_gets(char *file, char *tok, + char *buffer, size_t size) +{ + int status = ENOENT; + int len = strlen(tok); + FILE *fp = fopen(file, "r"); + + if (!fp) { + return SIGAR_ENOTIMPL; + } + + while (fgets(buffer, size, fp)) { + if (strnEQ(buffer, tok, len)) { + status = SIGAR_OK; + break; + } + } + + fclose(fp); + + return status; +} + +static int sigar_nfs_v2_get(char *file, sigar_nfs_v2_t *nfs) +{ + char buffer[BUFSIZ], *ptr=buffer; + int status = + sigar_proc_nfs_gets(file, + "proc2", buffer, sizeof(buffer)); + + if (status != SIGAR_OK) { + return status; + } + + ptr = sigar_skip_multiple_token(ptr, 2); + + nfs->null = sigar_strtoull(ptr); + nfs->getattr = sigar_strtoull(ptr); + nfs->setattr = sigar_strtoull(ptr); + nfs->root = sigar_strtoull(ptr); + nfs->lookup = sigar_strtoull(ptr); + nfs->readlink = sigar_strtoull(ptr); + nfs->read = sigar_strtoull(ptr); + nfs->writecache = sigar_strtoull(ptr); + nfs->write = sigar_strtoull(ptr); + nfs->create = sigar_strtoull(ptr); + nfs->remove = sigar_strtoull(ptr); + nfs->rename = sigar_strtoull(ptr); + nfs->link = sigar_strtoull(ptr); + nfs->symlink = sigar_strtoull(ptr); + nfs->mkdir = sigar_strtoull(ptr); + nfs->rmdir = sigar_strtoull(ptr); + nfs->readdir = sigar_strtoull(ptr); + nfs->fsstat = sigar_strtoull(ptr); + + return SIGAR_OK; +} + +int sigar_nfs_client_v2_get(sigar_t *sigar, + sigar_nfs_client_v2_t *nfs) +{ + return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfs", + (sigar_nfs_v2_t *)nfs); +} + +int sigar_nfs_server_v2_get(sigar_t *sigar, + sigar_nfs_server_v2_t *nfs) +{ + return sigar_nfs_v2_get(PROC_FS_ROOT "net/rpc/nfsd", + (sigar_nfs_v2_t *)nfs); +} + +static int sigar_nfs_v3_get(char *file, sigar_nfs_v3_t *nfs) +{ + char buffer[BUFSIZ], *ptr=buffer; + int status = + sigar_proc_nfs_gets(file, + "proc3", buffer, sizeof(buffer)); + + if (status != SIGAR_OK) { + return status; + } + + ptr = sigar_skip_multiple_token(ptr, 2); + + nfs->null = sigar_strtoull(ptr); + nfs->getattr = sigar_strtoull(ptr); + nfs->setattr = sigar_strtoull(ptr); + nfs->lookup = sigar_strtoull(ptr); + nfs->access = sigar_strtoull(ptr); + nfs->readlink = sigar_strtoull(ptr); + nfs->read = sigar_strtoull(ptr); + nfs->write = sigar_strtoull(ptr); + nfs->create = sigar_strtoull(ptr); + nfs->mkdir = sigar_strtoull(ptr); + nfs->symlink = sigar_strtoull(ptr); + nfs->mknod = sigar_strtoull(ptr); + nfs->remove = sigar_strtoull(ptr); + nfs->rmdir = sigar_strtoull(ptr); + nfs->rename = sigar_strtoull(ptr); + nfs->link = sigar_strtoull(ptr); + nfs->readdir = sigar_strtoull(ptr); + nfs->readdirplus = sigar_strtoull(ptr); + nfs->fsstat = sigar_strtoull(ptr); + nfs->fsinfo = sigar_strtoull(ptr); + nfs->pathconf = sigar_strtoull(ptr); + nfs->commit = sigar_strtoull(ptr); + + return SIGAR_OK; +} + +int sigar_nfs_client_v3_get(sigar_t *sigar, + sigar_nfs_client_v3_t *nfs) +{ + return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfs", + (sigar_nfs_v3_t *)nfs); +} + +int sigar_nfs_server_v3_get(sigar_t *sigar, + sigar_nfs_server_v3_t *nfs) +{ + return sigar_nfs_v3_get(PROC_FS_ROOT "net/rpc/nfsd", + (sigar_nfs_v3_t *)nfs); +} + +#include + +static char *get_hw_type(int type) +{ + switch (type) { + case ARPHRD_AX25: + return "ax25"; + case ARPHRD_ECONET: + return "ec"; + case ARPHRD_ETHER: + return "ether"; + case ARPHRD_FDDI: + return "fddi"; + case ARPHRD_DLCI: + return "dlci"; + case ARPHRD_FRAD: + return "frad"; + case ARPHRD_HDLC: + return "hdlc"; + case ARPHRD_LAPB: + return "lapb"; + case ARPHRD_HIPPI: + return "hippi"; + case ARPHRD_IRDA: + return "irda"; + case ARPHRD_LOOPBACK: + return "loop"; + case ARPHRD_NETROM: + return "netrom"; + case ARPHRD_PPP: + return "ppp"; + case ARPHRD_ROSE: + return "rose"; + case ARPHRD_SIT: + return "sit"; + case ARPHRD_SLIP: + return "slip"; + case ARPHRD_CSLIP: + return "cslip"; + case ARPHRD_SLIP6: + return "slip6"; + case ARPHRD_CSLIP6: + return "cslip6"; + case ARPHRD_ADAPT: + return "adaptive"; + case ARPHRD_IEEE802: + return "tr"; + case ARPHRD_IEEE802_TR: + return "tr"; + case ARPHRD_TUNNEL: + return "tunnel"; + case ARPHRD_X25: + return "x25"; + default: + return "unknown"; + } +} + +int sigar_arp_list_get(sigar_t *sigar, + sigar_arp_list_t *arplist) +{ + FILE *fp; + char buffer[1024]; + char net_addr[128], hwaddr[128], mask_addr[128]; + int flags, type, status; + sigar_arp_t *arp; + + arplist->size = arplist->number = 0; + + if (!(fp = fopen(PROC_FS_ROOT "net/arp", "r"))) { + return errno; + } + + sigar_arp_list_create(arplist); + + (void)fgets(buffer, sizeof(buffer), fp); /* skip header */ + while (fgets(buffer, sizeof(buffer), fp)) { + int num; + + SIGAR_ARP_LIST_GROW(arplist); + arp = &arplist->data[arplist->number++]; + + /* XXX rid sscanf */ + num = sscanf(buffer, "%128s 0x%x 0x%x %128s %128s %16s", + net_addr, &type, &flags, + hwaddr, mask_addr, arp->ifname); + + if (num < 6) { + --arplist->number; + continue; + } + + arp->flags = flags; + status = inet_pton(AF_INET, net_addr, &arp->address.addr); + if (status > 0) { + arp->address.family = SIGAR_AF_INET; + } + else if ((status = inet_pton(AF_INET6, net_addr, &arp->address.addr)) > 0) { + arp->address.family = SIGAR_AF_INET6; + } + else { + sigar_log_printf(sigar, SIGAR_LOG_WARN, + "[arp] failed to parse address='%s' (%s)\n", net_addr, + ((status == 0) ? "Invalid format" : sigar_strerror(sigar, errno))); + --arplist->number; + continue; + } + + num = sscanf(hwaddr, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", + &arp->hwaddr.addr.mac[0], + &arp->hwaddr.addr.mac[1], + &arp->hwaddr.addr.mac[2], + &arp->hwaddr.addr.mac[3], + &arp->hwaddr.addr.mac[4], + &arp->hwaddr.addr.mac[5]); + if (num < 6) { + sigar_log_printf(sigar, SIGAR_LOG_WARN, + "[arp] failed to parse hwaddr='%s' (%s)\n", hwaddr); + --arplist->number; + continue; + } + arp->hwaddr.family = SIGAR_AF_LINK; + + SIGAR_SSTRCPY(arp->type, get_hw_type(type)); + } + + fclose(fp); + + return SIGAR_OK; +} + +int sigar_proc_port_get(sigar_t *sigar, int protocol, + unsigned long port, sigar_pid_t *pid) +{ + int status; + sigar_net_connection_t netconn; + DIR *dirp; + struct dirent *ent, dbuf; + + SIGAR_ZERO(&netconn); + *pid = 0; + + status = sigar_net_connection_get(sigar, &netconn, port, + SIGAR_NETCONN_SERVER|protocol); + + if (status != SIGAR_OK) { + return status; + } + + if (netconn.local_port != port) { + return SIGAR_OK; /* XXX or ENOENT? */ + } + + if (!(dirp = opendir(PROCP_FS_ROOT))) { + return errno; + } + + while (readdir_r(dirp, &dbuf, &ent) == 0) { + DIR *fd_dirp; + struct dirent *fd_ent, fd_dbuf; + struct stat sb; + char fd_name[BUFSIZ], pid_name[BUFSIZ]; + int len, slen; + + if (ent == NULL) { + break; + } + + if (!sigar_isdigit(*ent->d_name)) { + continue; + } + + /* sprintf(pid_name, "/proc/%s", ent->d_name) */ + memcpy(&pid_name[0], PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT)); + len = SSTRLEN(PROCP_FS_ROOT); + pid_name[len++] = '/'; + + slen = strlen(ent->d_name); + memcpy(&pid_name[len], ent->d_name, slen); + len += slen; + pid_name[len] = '\0'; + + if (stat(pid_name, &sb) < 0) { + continue; + } + if (sb.st_uid != netconn.uid) { + continue; + } + + /* sprintf(fd_name, "%s/fd", pid_name) */ + memcpy(&fd_name[0], pid_name, len); + memcpy(&fd_name[len], "/fd", 3); + fd_name[len+=3] = '\0'; + + if (!(fd_dirp = opendir(fd_name))) { + continue; + } + + while (readdir_r(fd_dirp, &fd_dbuf, &fd_ent) == 0) { + char fd_ent_name[BUFSIZ]; + + if (fd_ent == NULL) { + break; + } + + if (!sigar_isdigit(*fd_ent->d_name)) { + continue; + } + + /* sprintf(fd_ent_name, "%s/%s", fd_name, fd_ent->d_name) */ + slen = strlen(fd_ent->d_name); + memcpy(&fd_ent_name[0], fd_name, len); + fd_ent_name[len] = '/'; + memcpy(&fd_ent_name[len+1], fd_ent->d_name, slen); + fd_ent_name[len+1+slen] = '\0'; + + if (stat(fd_ent_name, &sb) < 0) { + continue; + } + + if (sb.st_ino == netconn.inode) { + closedir(fd_dirp); + closedir(dirp); + *pid = strtoul(ent->d_name, NULL, 10); + return SIGAR_OK; + } + + } + + closedir(fd_dirp); + } + + closedir(dirp); + + return SIGAR_OK; +} + +static void generic_vendor_parse(char *line, sigar_sys_info_t *info) +{ + char *ptr; + int len = 0; + + while (*line) { + SIGAR_SKIP_SPACE(line); + if (!isdigit(*line)) { + ++line; + continue; + } + + ptr = line; + while ((isdigit(*ptr) || (*ptr == '.'))) { + ++ptr; + ++len; + } + + if (len) { + /* sanity check */ + if (len > sizeof(info->vendor_version)) { + continue; + } + memcpy(info->vendor_version, line, len);/*XXX*/ + info->vendor_version[len] = '\0'; + return; + } + } +} + +static void redhat_vendor_parse(char *line, sigar_sys_info_t *info) +{ + char *start, *end; + + generic_vendor_parse(line, info); /* super.parse */ + + if ((start = strchr(line, '('))) { + ++start; + if ((end = strchr(start, ')'))) { + int len = end-start; + memcpy(info->vendor_code_name, start, len);/*XXX*/ + info->vendor_code_name[len] = '\0'; + } + } + +#define RHEL_PREFIX "Red Hat Enterprise Linux " +#define CENTOS_VENDOR "CentOS" +#define SL_VENDOR "Scientific Linux" + + if (strnEQ(line, RHEL_PREFIX, sizeof(RHEL_PREFIX)-1)) { + snprintf(info->vendor_version, + sizeof(info->vendor_version), + "Enterprise Linux %c", + info->vendor_version[0]); + } + else if (strnEQ(line, CENTOS_VENDOR, sizeof(CENTOS_VENDOR)-1)) { + SIGAR_SSTRCPY(info->vendor, CENTOS_VENDOR); + } + else if (strnEQ(line, SL_VENDOR, sizeof(SL_VENDOR)-1)) { + SIGAR_SSTRCPY(info->vendor, SL_VENDOR); + } +} + +#define is_quote(c) ((c == '\'') || (c == '"')) + +static void kv_parse(char *data, sigar_sys_info_t *info, + void (*func)(sigar_sys_info_t *, char *, char *)) +{ + char *ptr = data; + int len = strlen(data); + char *end = data+len; + + while (ptr < end) { + char *val = strchr(ptr, '='); + int klen, vlen; + char key[256], *ix; + + if (!val) { + continue; + } + klen = val - ptr; + SIGAR_SSTRCPY(key, ptr); + key[klen] = '\0'; + ++val; + + if ((ix = strchr(val, '\n'))) { + *ix = '\0'; + } + vlen = strlen(val); + if (is_quote(*val)) { + if (is_quote(val[vlen-1])) { + val[vlen-1] = '\0'; + } + ++val; + } + + func(info, key, val); + + ptr += (klen + 1 + vlen + 1); + } +} + +static void lsb_parse(sigar_sys_info_t *info, + char *key, char *val) +{ + if (strEQ(key, "DISTRIB_ID")) { + SIGAR_SSTRCPY(info->vendor, val); + } + else if (strEQ(key, "DISTRIB_RELEASE")) { + SIGAR_SSTRCPY(info->vendor_version, val); + } + else if (strEQ(key, "DISTRIB_CODENAME")) { + SIGAR_SSTRCPY(info->vendor_code_name, val); + } +} + +static void lsb_vendor_parse(char *data, sigar_sys_info_t *info) +{ + kv_parse(data, info, lsb_parse); +} + +static void xen_parse(sigar_sys_info_t *info, + char *key, char *val) +{ + if (strEQ(key, "PRODUCT_VERSION")) { + SIGAR_SSTRCPY(info->vendor_version, val); + } + else if (strEQ(key, "KERNEL_VERSION")) { + SIGAR_SSTRCPY(info->version, val); + } +} + +static void xen_vendor_parse(char *data, sigar_sys_info_t *info) +{ + kv_parse(data, info, xen_parse); + + snprintf(info->description, + sizeof(info->description), + "XenServer %s", + info->vendor_version); +} + +typedef struct { + const char *name; + const char *file; + void (*parse)(char *, sigar_sys_info_t *); +} linux_vendor_info_t; + +static linux_vendor_info_t linux_vendors[] = { + { "Fedora", "/etc/fedora-release", NULL }, + { "SuSE", "/etc/SuSE-release", NULL }, + { "Gentoo", "/etc/gentoo-release", NULL }, + { "Slackware", "/etc/slackware-version", NULL }, + { "Mandrake", "/etc/mandrake-release", NULL }, + { "VMware", "/proc/vmware/version", NULL }, + { "XenSource", "/etc/xensource-inventory", xen_vendor_parse }, + { "Red Hat", "/etc/redhat-release", redhat_vendor_parse }, + { "lsb", "/etc/lsb-release", lsb_vendor_parse }, + { "Debian", "/etc/debian_version", NULL }, + { NULL } +}; + +static int get_linux_vendor_info(sigar_sys_info_t *info) +{ + int i, status = ENOENT; + /* env vars for testing */ + const char *release_file = getenv("SIGAR_OS_RELEASE_FILE"); + const char *vendor_name = getenv("SIGAR_OS_VENDOR_NAME"); + char buffer[8192], *data; + linux_vendor_info_t *vendor = NULL; + + for (i=0; linux_vendors[i].name; i++) { + struct stat sb; + vendor = &linux_vendors[i]; + + if (release_file && vendor_name) { + if (!strEQ(vendor->name, vendor_name)) { + continue; + } + } + else { + if (stat(vendor->file, &sb) < 0) { + continue; + } + release_file = vendor->file; + } + + status = + sigar_file2str(release_file, buffer, sizeof(buffer)-1); + + break; + } + + if (status != SIGAR_OK) { + return status; + } + + data = buffer; + + SIGAR_SSTRCPY(info->vendor, vendor->name); + + if (vendor->parse) { + vendor->parse(data, info); + } + else { + generic_vendor_parse(data, info); + } + + if (info->description[0] == '\0') { + snprintf(info->description, + sizeof(info->description), + "%s %s", + info->vendor, info->vendor_version); + } + + return SIGAR_OK; +} + +int sigar_os_sys_info_get(sigar_t *sigar, + sigar_sys_info_t *sysinfo) +{ + + get_linux_vendor_info(sysinfo); + + return SIGAR_OK; +} diff --git a/vendor/sigar/src/os/linux/sigar_os.h b/vendor/sigar/src/os/linux/sigar_os.h new file mode 100644 index 0000000..29a2ba3 --- /dev/null +++ b/vendor/sigar/src/os/linux/sigar_os.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2004-2008 Hyperic, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGAR_OS_H +#define SIGAR_OS_H + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +typedef struct { + sigar_pid_t pid; + time_t mtime; + sigar_uint64_t vsize; + sigar_uint64_t rss; + sigar_uint64_t minor_faults; + sigar_uint64_t major_faults; + sigar_uint64_t ppid; + int tty; + int priority; + int nice; + sigar_uint64_t start_time; + sigar_uint64_t utime; + sigar_uint64_t stime; + char name[SIGAR_PROC_NAME_LEN]; + char state; + int processor; +} linux_proc_stat_t; + +typedef enum { + IOSTAT_NONE, + IOSTAT_PARTITIONS, /* 2.4 */ + IOSTAT_DISKSTATS, /* 2.6 */ + IOSTAT_SYS /* 2.6 */ +} linux_iostat_e; + +struct sigar_t { + SIGAR_T_BASE; + int pagesize; + int ram; + int proc_signal_offset; + linux_proc_stat_t last_proc_stat; + int lcpu; + linux_iostat_e iostat; + char *proc_net; + /* Native POSIX Thread Library 2.6+ kernel */ + int has_nptl; +}; + +#define HAVE_STRERROR_R +#ifndef __USE_XOPEN2K +/* use gnu version of strerror_r */ +#define HAVE_STRERROR_R_GLIBC +#endif +#define HAVE_READDIR_R +#define HAVE_GETPWNAM_R +#define HAVE_GETPWUID_R +#define HAVE_GETGRGID_R + +#endif /* SIGAR_OS_H */ diff --git a/vendor/sigar/src/os/solaris/get_mib2.c b/vendor/sigar/src/os/solaris/get_mib2.c new file mode 100644 index 0000000..fbcadc6 --- /dev/null +++ b/vendor/sigar/src/os/solaris/get_mib2.c @@ -0,0 +1,321 @@ +/* + * get_mib2() -- get MIB2 information from Solaris 2.[3-7] kernel + * + * V. Abell + * Purdue University Computing Center + */ + + +/* + * Copyright 1995 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither Victor A Abell nor Purdue University are responsible for + * any consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to Victor A. Abell and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +/* + * Altered for sigar: + * - remove static stuff to make thread-safe by Doug MacEachern (3/11/05) + */ + +#if 0 /*ndef lint -Wall -Werror*/ +static char copyright[] = +"@(#) Copyright 1995 Purdue Research Foundation.\nAll rights reserved.\n"; +#endif + +#include "get_mib2.h" + +#include +#include +#include +#include +#include +#include + +#ifdef DMALLOC +#include +#endif + +/* + * close_mib2() - close MIB2 access + * + * return: + * + * exit = GET_MIB2_OK if close succeeded + * GET_MIB2_* is the error code. + */ + +int +close_mib2(solaris_mib2_t *mib2) +{ + if (mib2->sd < 0) { + (void) strcpy(mib2->errmsg, "close_mib2: socket not open"); + return(GET_MIB2_ERR_NOTOPEN); + } + if (close(mib2->sd)) { + (void) sprintf(mib2->errmsg, "close_mib2: %s", strerror(errno)); + return(GET_MIB2_ERR_CLOSE); + } + mib2->sd = -1; + if (mib2->db_len && mib2->db) { + mib2->db_len = 0; + free((void *)mib2->db); + mib2->db = NULL; + } + if (mib2->smb_len && mib2->smb) { + mib2->smb_len = 0; + free((void *)mib2->smb); + mib2->smb = NULL; + } + return(GET_MIB2_OK); +} + + +/* + * get_mib2() - get MIB2 data + * + * return: + * + * exit = GET_MIB2_OK if get succeeded, and: + * *opt = opthdr structure address + * *data = data buffer address + * *datalen = size of data buffer + * GET_MIB2_* is the error code for failure. + */ + +int +get_mib2(solaris_mib2_t *mib2, + struct opthdr **opt, + char **data, + int *datalen) +{ + struct strbuf d; /* streams data buffer */ + int err; /* error code */ + int f; /* flags */ + int rc; /* reply code */ + + /* + * If MIB2 access isn't open, open it and issue the preliminary stream + * messages. + */ + if (mib2->sd < 0) { + /* + * Open access. Return on error. + */ + if ((err = open_mib2(mib2))) { + return(err); + } + /* + * Set up message request and option. + */ + mib2->req = (struct T_optmgmt_req *)mib2->smb; + mib2->op = (struct opthdr *)&mib2->smb[sizeof(struct T_optmgmt_req)]; + mib2->req->PRIM_type = T_OPTMGMT_REQ; + mib2->req->OPT_offset = sizeof(struct T_optmgmt_req); + mib2->req->OPT_length = sizeof(struct opthdr); + +#if defined(MI_T_CURRENT) + mib2->req->MGMT_flags = MI_T_CURRENT; +#else /* !defined(MI_T_CURRENT) */ +# if defined(T_CURRENT) + mib2->req->MGMT_flags = T_CURRENT; +# else /* !defined(T_CURRENT) */ +#error "Neither MI_T_CURRENT nor T_CURRENT are defined." +# endif /* defined(T_CURRENT) */ +#endif /* defined(MI_T_CURRENT) */ + + mib2->op->level = MIB2_IP; + mib2->op->name = mib2->op->len = 0; + mib2->ctlbuf.buf = mib2->smb; + mib2->ctlbuf.len = mib2->req->OPT_offset + mib2->req->OPT_length; + /* + * Put the message. + */ + if (putmsg(mib2->sd, &mib2->ctlbuf, (struct strbuf *)NULL, 0) == -1) { + (void) sprintf(mib2->errmsg, + "get_mib2: putmsg request: %s", strerror(errno)); + return(GET_MIB2_ERR_PUTMSG); + } + /* + * Set up to process replies. + */ + mib2->op_ack = (struct T_optmgmt_ack *)mib2->smb; + mib2->ctlbuf.maxlen = mib2->smb_len; + mib2->err_ack = (struct T_error_ack *)mib2->smb; + mib2->op = (struct opthdr *)&mib2->smb[sizeof(struct T_optmgmt_ack)]; + } + /* + * Get the next (first) reply message. + */ + f = 0; + if ((rc = getmsg(mib2->sd, &mib2->ctlbuf, NULL, &f)) < 0) { + (void) sprintf(mib2->errmsg, "get_mib2: getmsg(reply): %s", + strerror(errno)); + return(GET_MIB2_ERR_GETMSGR); + } + /* + * Check for end of data. + */ + if (rc == 0 + && mib2->ctlbuf.len >= sizeof(struct T_optmgmt_ack) + && mib2->op_ack->PRIM_type == T_OPTMGMT_ACK + && mib2->op_ack->MGMT_flags == T_SUCCESS + && mib2->op->len == 0) + { + err = close_mib2(mib2); + if (err) { + return(err); + } + return(GET_MIB2_EOD); + } + /* + * Check for error. + */ + if (mib2->ctlbuf.len >= sizeof(struct T_error_ack) + && mib2->err_ack->PRIM_type == T_ERROR_ACK) + { + (void) sprintf(mib2->errmsg, + "get_mib2: T_ERROR_ACK: len=%d, TLI=%#x, UNIX=%#x", + mib2->ctlbuf.len, + (int)mib2->err_ack->TLI_error, + (int)mib2->err_ack->UNIX_error); + return(GET_MIB2_ERR_ACK); + } + /* + * Check for no data. + */ + if (rc != MOREDATA + || mib2->ctlbuf.len < sizeof(struct T_optmgmt_ack) + || mib2->op_ack->PRIM_type != T_OPTMGMT_ACK + || mib2->op_ack->MGMT_flags != T_SUCCESS) + { + (void) sprintf(mib2->errmsg, + "get_mib2: T_OPTMGMT_ACK: " + "rc=%d len=%d type=%#x flags=%#x", + rc, mib2->ctlbuf.len, + (int)mib2->op_ack->PRIM_type, + (int)mib2->op_ack->MGMT_flags); + return(GET_MIB2_ERR_NODATA); + } + /* + * Allocate (or enlarge) the data buffer. + */ + if (mib2->op->len >= mib2->db_len) { + mib2->db_len = mib2->op->len; + if (mib2->db == NULL) { + mib2->db = (char *)malloc(mib2->db_len); + } + else { + mib2->db = (char *)realloc(mib2->db, mib2->db_len); + } + if (mib2->db == NULL) { + (void) sprintf(mib2->errmsg, + "get_mib2: no space for %d byte data buffer", + mib2->db_len); + return(GET_MIB2_ERR_NOSPC); + } + } + /* + * Get the data part of the message -- the MIB2 part. + */ + d.maxlen = mib2->op->len; + d.buf = mib2->db; + d.len = 0; + f = 0; + if ((rc = getmsg(mib2->sd, NULL, &d, &f)) < 0) { + (void) sprintf(mib2->errmsg, "get_mib2: getmsg(data): %s", + strerror(errno)); + return(GET_MIB2_ERR_GETMSGD); + } + if (rc) { + (void) sprintf(mib2->errmsg, + "get_mib2: getmsg(data): rc=%d maxlen=%d len=%d: %s", + rc, d.maxlen, d.len, strerror(errno)); + return(GET_MIB2_ERR_GETMSGD); + } + /* + * Compose a successful return. + */ + *opt = mib2->op; + *data = mib2->db; + *datalen = d.len; + return(GET_MIB2_OK); +} + + +/* + * open_mib2() - open access to MIB2 data + * + * return: + * + * exit = GET_MIB2_OK if open succeeded + * GET_MIB2_* is the error code for failure. + */ + +int +open_mib2(solaris_mib2_t *mib2) +{ + /* + * It's an error if the stream device is already open. + */ + if (mib2->sd >= 0) { + (void) strcpy(mib2->errmsg, "open_mib2: MIB2 access already open"); + return(GET_MIB2_ERR_OPEN); + } + /* + * Open the ARP stream device, push TCP and UDP on it. + */ + if ((mib2->sd = open(GET_MIB2_ARPDEV, O_RDWR, 0600)) < 0) { + (void) sprintf(mib2->errmsg, "open_mib2: %s: %s", GET_MIB2_ARPDEV, + strerror(errno)); + return(GET_MIB2_ERR_ARPOPEN); + } + if (ioctl(mib2->sd, I_PUSH, GET_MIB2_TCPSTREAM) == -1) { + (void) sprintf(mib2->errmsg, "open_mib2: push %s: %s", + GET_MIB2_TCPSTREAM, strerror(errno)); + return(GET_MIB2_ERR_TCPPUSH); + } + if (ioctl(mib2->sd, I_PUSH, GET_MIB2_UDPSTREAM) == -1) { + (void) sprintf(mib2->errmsg, "open_mib2: push %s: %s", + GET_MIB2_UDPSTREAM, strerror(errno)); + return(GET_MIB2_ERR_UDPPUSH); + } + /* + * Allocate a stream message buffer. + */ + mib2->smb_len = sizeof(struct opthdr) + sizeof(struct T_optmgmt_req); + if (mib2->smb_len < (sizeof (struct opthdr) + sizeof(struct T_optmgmt_ack))) { + mib2->smb_len = sizeof (struct opthdr) + sizeof(struct T_optmgmt_ack); + } + if (mib2->smb_len < sizeof(struct T_error_ack)) { + mib2->smb_len = sizeof(struct T_error_ack); + } + if ((mib2->smb = (char *)malloc(mib2->smb_len)) == NULL) { + (void) strcpy(mib2->errmsg, + "open_mib2: no space for stream message buffer"); + return(GET_MIB2_ERR_NOSPC); + } + /* + * All is OK. Return that indication. + */ + return(GET_MIB2_OK); +} diff --git a/vendor/sigar/src/os/solaris/get_mib2.h b/vendor/sigar/src/os/solaris/get_mib2.h new file mode 100644 index 0000000..53116c5 --- /dev/null +++ b/vendor/sigar/src/os/solaris/get_mib2.h @@ -0,0 +1,127 @@ +/* + * get_mib2.h -- definitions for the get_mib2() function + * + * V. Abell + * Purdue University Computing Center + */ + + +/* + * Copyright 1995 Purdue Research Foundation, West Lafayette, Indiana + * 47907. All rights reserved. + * + * Written by Victor A. Abell + * + * This software is not subject to any license of the American Telephone + * and Telegraph Company or the Regents of the University of California. + * + * Permission is granted to anyone to use this software for any purpose on + * any computer system, and to alter it and redistribute it freely, subject + * to the following restrictions: + * + * 1. Neither Victor A Abell nor Purdue University are responsible for + * any consequences of the use of this software. + * + * 2. The origin of this software must not be misrepresented, either by + * explicit claim or by omission. Credit to Victor A. Abell and Purdue + * University must appear in documentation and sources. + * + * 3. Altered versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * + * 4. This notice may not be removed or altered. + */ + +/* + * Altered for sigar: + * - remove static stuff to make thread-safe by Doug MacEachern (3/11/05) + */ + +#if !defined(GET_MIB2_H) +#define GET_MIB2_H + + +/* + * Required header files + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Miscellaneous definitions + */ + +#define GET_MIB2_ARPDEV "/dev/arp" /* ARP stream devi9ce */ +#define GET_MIB2_ERRMSGL 1024 /* ErrMsg buffer length */ +#define GET_MIB2_TCPSTREAM "tcp" /* TCP stream name */ +#define GET_MIB2_UDPSTREAM "udp" /* UDP stream name */ + + +/* + * get_mib2() response codes + * + * -1 End of MIB2 information + * 0 Next MIB2 structure returned + * >0 Error code + */ + +#define GET_MIB2_EOD -1 /* end of data */ +#define GET_MIB2_OK 0 /* function succeeded */ +#define GET_MIB2_ERR_ACK 1 /* getmsg() ACK error received */ +#define GET_MIB2_ERR_ARPOPEN 2 /* error opening ARPDEV */ +#define GET_MIB2_ERR_CLOSE 3 /* MIB2 access close error */ +#define GET_MIB2_ERR_GETMSGD 4 /* error getting message data */ +#define GET_MIB2_ERR_GETMSGR 5 /* error getting message reply */ +#define GET_MIB2_ERR_NODATA 6 /* data expected; not received */ +#define GET_MIB2_ERR_NOSPC 7 /* no malloc() space */ +#define GET_MIB2_ERR_NOTOPEN 8 /* MIB2 access not open */ +#define GET_MIB2_ERR_OPEN 9 /* MIB2 access open error */ +#define GET_MIB2_ERR_PUTMSG 10 /* error putting request message */ +#define GET_MIB2_ERR_TCPPUSH 11 /* error pushing TCPSTREAM */ +#define GET_MIB2_ERR_UDPPUSH 12 /* error pushing UDPSTREAM */ + +#define GET_MIB2_ERR_MAX 13 /* maximum error number + 1 */ + + +typedef struct { + char *db; /* data buffer */ + int db_len; /* data buffer length */ + char *smb; /* stream message buffer */ + size_t smb_len; /* size of Smb[] */ + int sd; /* stream device descriptor */ + char errmsg[GET_MIB2_ERRMSGL]; /* error message buffer */ + struct T_optmgmt_ack *op_ack; /* message ACK pointer */ + struct strbuf ctlbuf; /* streams control buffer */ + struct T_error_ack *err_ack; /* message error pointer */ + struct opthdr *op; /* message option pointer */ + struct T_optmgmt_req *req; /* message request pointer */ +} solaris_mib2_t; + +/* + * Function prototypes + */ + +int close_mib2( /* close acccess to MIB2 information */ + solaris_mib2_t *mib2 + ); +int get_mib2( /* get MIB2 information */ + solaris_mib2_t *mib2, + struct opthdr **opt, /* opthdr pointer return (see + * */ + char **data, /* data buffer return address */ + int *datalen /* data buffer length return + * address */ + ); +int open_mib2( /* open acccess to MIB2 information */ + solaris_mib2_t *mib2 + ); + +#endif /* !defined(GET_MIB2_H) */ diff --git a/vendor/sigar/src/os/solaris/kstats.c b/vendor/sigar/src/os/solaris/kstats.c new file mode 100644 index 0000000..a04ff09 --- /dev/null +++ b/vendor/sigar/src/os/solaris/kstats.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2004-2007 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_util.h" +#include "sigar_os.h" + +int sigar_get_kstats(sigar_t *sigar) +{ + kstat_ctl_t *kc = sigar->kc; + unsigned int i, id, ncpu = sysconf(_SC_NPROCESSORS_CONF); + int is_debug = SIGAR_LOG_IS_DEBUG(sigar); + + if (ncpu != sigar->ncpu) { + if (!sigar->ks.lcpu) { + /* init */ + sigar->ks.lcpu = ncpu; + sigar->ks.cpu = malloc(sizeof(*(sigar->ks.cpu)) * ncpu); + sigar->ks.cpu_info = malloc(sizeof(*(sigar->ks.cpu_info)) * ncpu); + sigar->ks.cpuid = malloc(sizeof(*(sigar->ks.cpuid)) * ncpu); + } + else { + sigar_log_printf(sigar, SIGAR_LOG_INFO, + "ncpu changed from %d to %d", + sigar->ncpu, ncpu); + if (ncpu > sigar->ks.lcpu) { + /* one or more cpus have been added */ + sigar->ks.cpu = realloc(sigar->ks.cpu, + sizeof(*(sigar->ks.cpu)) * ncpu); + sigar->ks.cpu_info = realloc(sigar->ks.cpu_info, + sizeof(*(sigar->ks.cpu_info)) * ncpu); + sigar->ks.cpuid = realloc(sigar->ks.cpuid, + sizeof(*(sigar->ks.cpuid)) * ncpu); + sigar->ks.lcpu = ncpu; + } + /* else or more cpus have been removed */ + } + + sigar->ncpu = ncpu; + + /* from man p_online: + * ``Processor numbers are integers, + * greater than or equal to 0, + * and are defined by the hardware platform. + * Processor numbers are not necessarily contiguous, + * but "not too sparse."`` + * so we maintain our own mapping in ks.cpuid[] + */ + + /* lookup in order, which kstat chain may not be in */ + for (i=0, id=0; iks.cpu_info[i] = cpu_info; + sigar->ks.cpu[i] = cpu_stat; + sigar->ks.cpuid[i] = id; + + if (is_debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "cpu %d id=%d", i, sigar->ks.cpuid[i]); + } + i++; + } + } + + sigar->ks.system = kstat_lookup(kc, "unix", -1, "system_misc"); + sigar->ks.syspages = kstat_lookup(kc, "unix", -1, "system_pages"); + sigar->ks.mempages = kstat_lookup(kc, "bunyip", -1, "mempages"); + + return SIGAR_OK; +} + +SIGAR_INLINE kid_t sigar_kstat_update(sigar_t *sigar) +{ + kid_t id = kstat_chain_update(sigar->kc); + + switch (id) { + case -1: + sigar_log_printf(sigar, SIGAR_LOG_ERROR, + "kstat_chain_update error: %s", + sigar_strerror(sigar, errno)); + break; + case 0: + /* up-to-date */ + break; + default: + sigar_get_kstats(sigar); + sigar_log(sigar, SIGAR_LOG_DEBUG, + "kstat chain updated"); + break; + } + + return id; +} + +/* + * bincompat is not possible with certain kstat data structures between + * solaris 2.6, 2.7, 2.8, etc. alternative is to use kstat_data_lookup() + * which means everytime we want a stat, must do a linear search + * of ksp->ks_data. eek. so we meet half way and do the search for + * each key once per sigar_t instance. once the initial search has + * been done, we have a table of offsets to quickly access the stats via + * ksp->ks_data + offset. this gives us bincompat without the overhead + * of many kstat_data_lookup calls. + */ +static SIGAR_INLINE int kstat_named_offset(kstat_t *ksp, const char *name) +{ + unsigned int i; + kstat_named_t *kn; + + for (i=0, kn=ksp->ks_data; + iks_ndata; + i++, kn++) + { + if (strEQ(kn->name, name)) { + return i; + } + } + + return -2; /* not found */ +} + +static char *kstat_keys_system[] = { + "boot_time", + "avenrun_1min", + "avenrun_5min", + "avenrun_15min", + NULL +}; + +static char *kstat_keys_mempages[] = { + "pages_anon", + "pages_exec", + "pages_vnode", + NULL +}; + +static char *kstat_keys_syspages[] = { + "pagesfree", + NULL +}; + +static char **kstat_keys[] = { + kstat_keys_system, + kstat_keys_mempages, + kstat_keys_syspages, +}; + +void sigar_koffsets_lookup(kstat_t *ksp, int *offsets, int kidx) +{ + int i; + char **keys = kstat_keys[kidx]; + + for (i=0; keys[i]; i++) { + offsets[i] = kstat_named_offset(ksp, keys[i]); + } +} + diff --git a/vendor/sigar/src/os/solaris/procfs.c b/vendor/sigar/src/os/solaris/procfs.c new file mode 100644 index 0000000..743bd5b --- /dev/null +++ b/vendor/sigar/src/os/solaris/procfs.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2004, 2006 Hyperic, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_util.h" +#include "sigar_os.h" + +#define my_pread(fd, ptr, type, offset) \ + (pread(fd, ptr, sizeof(type), offset) == sizeof(type)) + +int sigar_proc_psinfo_get(sigar_t *sigar, sigar_pid_t pid) +{ + int fd, retval = SIGAR_OK; + char buffer[BUFSIZ]; + time_t timenow = time(NULL); + + if (sigar->pinfo == NULL) { + sigar->pinfo = malloc(sizeof(*sigar->pinfo)); + } + + if (sigar->last_pid == pid) { + if ((timenow - sigar->last_getprocs) < SIGAR_LAST_PROC_EXPIRE) { + return SIGAR_OK; + } + } + + sigar->last_pid = pid; + sigar->last_getprocs = timenow; + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/psinfo"); + + if ((fd = open(buffer, O_RDONLY)) < 0) { + return ESRCH; + } + + if (!my_pread(fd, sigar->pinfo, psinfo_t, 0)) { + retval = errno; + } + + close(fd); + + return retval; +} + +int sigar_proc_usage_get(sigar_t *sigar, prusage_t *prusage, sigar_pid_t pid) +{ + int fd, retval = SIGAR_OK; + char buffer[BUFSIZ]; + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/usage"); + + if ((fd = open(buffer, O_RDONLY)) < 0) { + return ESRCH; + } + + if (!my_pread(fd, prusage, prusage_t, 0)) { + retval = errno; + } + + close(fd); + + return retval; +} + +int sigar_proc_status_get(sigar_t *sigar, pstatus_t *pstatus, sigar_pid_t pid) +{ + int fd, retval = SIGAR_OK; + char buffer[BUFSIZ]; + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/status"); + + if ((fd = open(buffer, O_RDONLY)) < 0) { + return ESRCH; + } + + if (!my_pread(fd, pstatus, pstatus_t, 0)) { + retval = errno; + } + + close(fd); + + return retval; +} diff --git a/vendor/sigar/src/os/solaris/sigar_os.h b/vendor/sigar/src/os/solaris/sigar_os.h new file mode 100644 index 0000000..73115d8 --- /dev/null +++ b/vendor/sigar/src/os/solaris/sigar_os.h @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2004-2007 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGAR_OS_H +#define SIGAR_OS_H + +#ifndef _POSIX_PTHREAD_SEMANTICS +#define _POSIX_PTHREAD_SEMANTICS +#endif + +typedef unsigned long long int u_int64_t; + +#include +#include +#ifndef DMALLOC +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "get_mib2.h" + +/* avoid -Wall warning since solaris doesnt have a prototype for this */ +int getdomainname(char *, int); + +typedef struct { + kstat_t **ks; + int num; + char *name; + int nlen; +} kstat_list_t; + +SIGAR_INLINE kid_t sigar_kstat_update(sigar_t *sigar); + +int sigar_get_kstats(sigar_t *sigar); + +void sigar_init_multi_kstats(sigar_t *sigar); + +void sigar_free_multi_kstats(sigar_t *sigar); + +int sigar_get_multi_kstats(sigar_t *sigar, + kstat_list_t *kl, + const char *name, + kstat_t **retval); + +void sigar_koffsets_lookup(kstat_t *ksp, int *offsets, int kidx); + +int sigar_proc_psinfo_get(sigar_t *sigar, sigar_pid_t pid); + +int sigar_proc_usage_get(sigar_t *sigar, prusage_t *prusage, sigar_pid_t pid); + +int sigar_proc_status_get(sigar_t *sigar, pstatus_t *pstatus, sigar_pid_t pid); + +#define CPU_ONLINE(n) \ + (p_online(n, P_STATUS) == P_ONLINE) + +typedef enum { + KSTAT_SYSTEM_BOOT_TIME, + KSTAT_SYSTEM_LOADAVG_1, + KSTAT_SYSTEM_LOADAVG_2, + KSTAT_SYSTEM_LOADAVG_3, + KSTAT_SYSTEM_MAX +} kstat_system_off_e; + +typedef enum { + KSTAT_MEMPAGES_ANON, + KSTAT_MEMPAGES_EXEC, + KSTAT_MEMPAGES_VNODE, + KSTAT_MEMPAGES_MAX +} kstat_mempages_off_e; + +typedef enum { + KSTAT_SYSPAGES_FREE, + KSTAT_SYSPAGES_MAX +} kstat_syspages_off_e; + +enum { + KSTAT_KEYS_system, + KSTAT_KEYS_mempages, + KSTAT_KEYS_syspages, +} kstat_keys_e; + +typedef struct ps_prochandle * (*proc_grab_func_t)(pid_t, int, int *); + +typedef void (*proc_free_func_t)(struct ps_prochandle *); + +typedef int (*proc_create_agent_func_t)(struct ps_prochandle *); + +typedef void (*proc_destroy_agent_func_t)(struct ps_prochandle *); + +typedef void (*proc_objname_func_t)(struct ps_prochandle *, + uintptr_t, const char *, size_t); + +typedef char * (*proc_dirname_func_t)(const char *, char *, size_t); + +typedef char * (*proc_exename_func_t)(struct ps_prochandle *, char *, size_t); + +typedef int (*proc_fstat64_func_t)(struct ps_prochandle *, int, void *); + +typedef int (*proc_getsockopt_func_t)(struct ps_prochandle *, + int, int, int, void *, int *); + +typedef int (*proc_getsockname_func_t)(struct ps_prochandle *, + int, struct sockaddr *, socklen_t *); + +struct sigar_t { + SIGAR_T_BASE; + + int solaris_version; + int use_ucb_ps; + + kstat_ctl_t *kc; + + /* kstat_lookup() as needed */ + struct { + kstat_t **cpu; + kstat_t **cpu_info; + processorid_t *cpuid; + unsigned int lcpu; /* number malloced slots in the cpu array above */ + kstat_t *system; + kstat_t *syspages; + kstat_t *mempages; + } ks; + + struct { + int system[KSTAT_SYSTEM_MAX]; + int mempages[KSTAT_MEMPAGES_MAX]; + int syspages[KSTAT_SYSPAGES_MAX]; + } koffsets; + + int pagesize; + + time_t last_getprocs; + sigar_pid_t last_pid; + psinfo_t *pinfo; + sigar_cpu_list_t cpulist; + + /* libproc.so interface */ + void *plib; + proc_grab_func_t pgrab; + proc_free_func_t pfree; + proc_create_agent_func_t pcreate_agent; + proc_destroy_agent_func_t pdestroy_agent; + proc_objname_func_t pobjname; + proc_dirname_func_t pdirname; + proc_exename_func_t pexename; + proc_fstat64_func_t pfstat64; + proc_getsockopt_func_t pgetsockopt; + proc_getsockname_func_t pgetsockname; + + sigar_cache_t *pargs; + + solaris_mib2_t mib2; +}; + +#ifdef SIGAR_64BIT +#define KSTAT_UINT ui64 +#else +#define KSTAT_UINT ui32 +#endif + +#define kSTAT_exists(v, type) \ + (sigar->koffsets.type[v] != -2) + +#define kSTAT_ptr(v, type) \ + ((kstat_named_t *)ksp->ks_data + sigar->koffsets.type[v]) + +#define kSTAT_uint(v, type) \ + (kSTAT_exists(v, type) ? kSTAT_ptr(v, type)->value.KSTAT_UINT : 0) + +#define kSTAT_ui32(v, type) \ + (kSTAT_exists(v, type) ? kSTAT_ptr(v, type)->value.ui32 : 0) + +#define kSYSTEM(v) kSTAT_ui32(v, system) + +#define kMEMPAGES(v) kSTAT_uint(v, mempages) + +#define kSYSPAGES(v) kSTAT_uint(v, syspages) + +#define sigar_koffsets_init(sigar, ksp, type) \ + if (sigar->koffsets.type[0] == -1) \ + sigar_koffsets_lookup(ksp, sigar->koffsets.type, KSTAT_KEYS_##type) + +#define sigar_koffsets_init_system(sigar, ksp) \ + sigar_koffsets_init(sigar, ksp, system) + +#define sigar_koffsets_init_mempages(sigar, ksp) \ + sigar_koffsets_init(sigar, ksp, mempages) + +#define sigar_koffsets_init_syspages(sigar, ksp) \ + sigar_koffsets_init(sigar, ksp, syspages) + +#define HAVE_READDIR_R +#define HAVE_GETPWNAM_R +#define HAVE_GETPWUID_R + +#define SIGAR_EMIB2 (SIGAR_OS_START_ERROR+1) + +#endif /* SIGAR_OS_H */ + diff --git a/vendor/sigar/src/os/solaris/solaris_sigar.c b/vendor/sigar/src/os/solaris/solaris_sigar.c new file mode 100644 index 0000000..da9a2b6 --- /dev/null +++ b/vendor/sigar/src/os/solaris/solaris_sigar.c @@ -0,0 +1,2717 @@ +/* + * Copyright (c) 2004-2008 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2009-2010 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_util.h" +#include "sigar_os.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PROC_ERRNO ((errno == ENOENT) ? ESRCH : errno) +#define SIGAR_USR_UCB_PS "/usr/ucb/ps" + + +/* like kstat_lookup but start w/ ksp->ks_next instead of kc->kc_chain */ +static kstat_t * +kstat_next(kstat_t *ksp, char *ks_module, int ks_instance, char *ks_name) +{ + if (ksp) { + ksp = ksp->ks_next; + } + for (; ksp; ksp = ksp->ks_next) { + if ((ks_module == NULL || + strcmp(ksp->ks_module, ks_module) == 0) && + (ks_instance == -1 || ksp->ks_instance == ks_instance) && + (ks_name == NULL || strcmp(ksp->ks_name, ks_name) == 0)) + return ksp; + } + + errno = ENOENT; + return NULL; +} + +int sigar_os_open(sigar_t **sig) +{ + kstat_ctl_t *kc; + kstat_t *ksp; + sigar_t *sigar; + int i, status; + struct utsname name; + char *ptr; + + sigar = malloc(sizeof(*sigar)); + *sig = sigar; + + sigar->log_level = -1; /* log nothing by default */ + sigar->log_impl = NULL; + sigar->log_data = NULL; + + uname(&name); + if ((ptr = strchr(name.release, '.'))) { + ptr++; + sigar->solaris_version = atoi(ptr); + } + else { + sigar->solaris_version = 6; + } + + if ((ptr = getenv("SIGAR_USE_UCB_PS"))) { + sigar->use_ucb_ps = strEQ(ptr, "true"); + } + else { + struct stat sb; + if (stat(SIGAR_USR_UCB_PS, &sb) < 0) { + sigar->use_ucb_ps = 0; + } + else { + sigar->use_ucb_ps = 1; + } + } + + sigar->pagesize = 0; + i = sysconf(_SC_PAGESIZE); + while ((i >>= 1) > 0) { + sigar->pagesize++; + } + + sigar->ticks = sysconf(_SC_CLK_TCK); + sigar->kc = kc = kstat_open(); + + if (!kc) { + return errno; + } + + sigar->cpulist.size = 0; + sigar->ncpu = 0; + sigar->ks.cpu = NULL; + sigar->ks.cpu_info = NULL; + sigar->ks.cpuid = NULL; + sigar->ks.lcpu = 0; + + sigar->koffsets.system[0] = -1; + sigar->koffsets.mempages[0] = -1; + sigar->koffsets.syspages[0] = -1; + + if ((status = sigar_get_kstats(sigar)) != SIGAR_OK) { + fprintf(stderr, "status=%d\n", status); + } + + sigar->boot_time = 0; + + if ((ksp = sigar->ks.system) && + (kstat_read(kc, ksp, NULL) >= 0)) + { + sigar_koffsets_init_system(sigar, ksp); + + sigar->boot_time = kSYSTEM(KSTAT_SYSTEM_BOOT_TIME); + } + + sigar->last_pid = -1; + sigar->pinfo = NULL; + + sigar->plib = NULL; + sigar->pgrab = NULL; + sigar->pfree = NULL; + sigar->pobjname = NULL; + + sigar->pargs = NULL; + + SIGAR_ZERO(&sigar->mib2); + sigar->mib2.sd = -1; + + return SIGAR_OK; +} + +int sigar_os_close(sigar_t *sigar) +{ + kstat_close(sigar->kc); + if (sigar->mib2.sd != -1) { + close_mib2(&sigar->mib2); + } + + if (sigar->ks.lcpu) { + free(sigar->ks.cpu); + free(sigar->ks.cpu_info); + free(sigar->ks.cpuid); + } + if (sigar->pinfo) { + free(sigar->pinfo); + } + if (sigar->cpulist.size != 0) { + sigar_cpu_list_destroy(sigar, &sigar->cpulist); + } + if (sigar->plib) { + dlclose(sigar->plib); + } + if (sigar->pargs) { + sigar_cache_destroy(sigar->pargs); + } + free(sigar); + return SIGAR_OK; +} + +char *sigar_os_error_string(sigar_t *sigar, int err) +{ + switch (err) { + case SIGAR_EMIB2: + return sigar->mib2.errmsg; + default: + return NULL; + } +} + +int sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem) +{ + kstat_ctl_t *kc = sigar->kc; + kstat_t *ksp; + sigar_uint64_t kern = 0; + + SIGAR_ZERO(mem); + + /* XXX: is mem hot swappable or can we just do this during open ? */ + mem->total = sysconf(_SC_PHYS_PAGES); + mem->total <<= sigar->pagesize; + + if (sigar_kstat_update(sigar) == -1) { + return errno; + } + + if ((ksp = sigar->ks.syspages) && kstat_read(kc, ksp, NULL) >= 0) { + sigar_koffsets_init_syspages(sigar, ksp); + + mem->free = kSYSPAGES(KSTAT_SYSPAGES_FREE); + mem->free <<= sigar->pagesize; + + mem->used = mem->total - mem->free; + } + + if ((ksp = sigar->ks.mempages) && kstat_read(kc, ksp, NULL) >= 0) { + sigar_koffsets_init_mempages(sigar, ksp); + } + + /* XXX mdb ::memstat cachelist/freelist not available to kstat, see: */ + /* http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6821980 */ + + /* ZFS ARC cache. see: http://opensolaris.org/jive/thread.jspa?messageID=393695 */ + if ((ksp = kstat_lookup(sigar->kc, "zfs", 0, "arcstats")) && + (kstat_read(sigar->kc, ksp, NULL) != -1)) + { + kstat_named_t *kn; + + if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "size"))) { + kern = kn->value.i64; + } + if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "c_min"))) { + /* c_min cannot be reclaimed they say */ + if (kern > kn->value.i64) { + kern -= kn->value.i64; + } + } + } + + mem->actual_free = mem->free + kern; + mem->actual_used = mem->used - kern; + + sigar_mem_calc_ram(sigar, mem); + + return SIGAR_OK; +} + +int sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap) +{ + kstat_t *ksp; + kstat_named_t *kn; + swaptbl_t *stab; + int num, i; + char path[PATH_MAX+1]; /* {un,re}used */ + + /* see: man swapctl(2) */ + if ((num = swapctl(SC_GETNSWP, NULL)) == -1) { + return errno; + } + + stab = malloc(num * sizeof(stab->swt_ent[0]) + sizeof(*stab)); + + stab->swt_n = num; + for (i=0; iswt_ent[i].ste_path = path; + } + + if ((num = swapctl(SC_LIST, stab)) == -1) { + free(stab); + return errno; + } + + num = num < stab->swt_n ? num : stab->swt_n; + swap->total = swap->free = 0; + for (i=0; iswt_ent[i].ste_flags & ST_INDEL) { + continue; /* swap file is being deleted */ + } + swap->total += stab->swt_ent[i].ste_pages; + swap->free += stab->swt_ent[i].ste_free; + } + free(stab); + + swap->total <<= sigar->pagesize; + swap->free <<= sigar->pagesize; + swap->used = swap->total - swap->free; + + if (sigar_kstat_update(sigar) == -1) { + return errno; + } + if (!(ksp = kstat_lookup(sigar->kc, "cpu", -1, "vm"))) { + swap->page_in = swap->page_out = SIGAR_FIELD_NOTIMPL; + return SIGAR_OK; + } + + swap->page_in = swap->page_out = 0; + + /* XXX: these stats do not exist in this form on solaris 8 or 9. + * they are in the raw cpu_stat struct, but thats not + * binary compatible + */ + do { + if (kstat_read(sigar->kc, ksp, NULL) < 0) { + break; + } + + if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "pgin"))) { + swap->page_in += kn->value.i64; /* vmstat -s | grep "page ins" */ + } + if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, "pgout"))) { + swap->page_out += kn->value.i64; /* vmstat -s | grep "page outs" */ + } + } while ((ksp = kstat_next(ksp, "cpu", -1, "vm"))); + + return SIGAR_OK; +} + +#ifndef KSTAT_NAMED_STR_PTR +/* same offset as KSTAT_NAMED_STR_PTR(brand) */ +#define KSTAT_NAMED_STR_PTR(n) (char *)((n)->value.i32) +#endif + +static int get_chip_brand(sigar_t *sigar, int processor, + sigar_cpu_info_t *info) +{ + kstat_t *ksp = sigar->ks.cpu_info[processor]; + kstat_named_t *brand; + + if (sigar->solaris_version < 10) { + /* don't bother; doesn't exist. */ + return 0; + } + + if (ksp && + (kstat_read(sigar->kc, ksp, NULL) != -1) && + (brand = (kstat_named_t *)kstat_data_lookup(ksp, "brand"))) + { + char *name = KSTAT_NAMED_STR_PTR(brand); + + char *vendor = "Sun"; + char *vendors[] = { + "Intel", "AMD", NULL + }; + int i; + + if (!name) { + return 0; + } + + for (i=0; vendors[i]; i++) { + if (strstr(name, vendors[i])) { + vendor = vendors[i]; + break; + } + } + + SIGAR_SSTRCPY(info->vendor, vendor); +#if 0 + SIGAR_SSTRCPY(info->model, name); + sigar_cpu_model_adjust(sigar, info); +#endif + return 1; + } + else { + return 0; + } +} + +static void free_chip_id(void *ptr) +{ + /*noop*/ +} + +static int get_chip_id(sigar_t *sigar, int processor) +{ + kstat_t *ksp = sigar->ks.cpu_info[processor]; + kstat_named_t *chipid; + + if (ksp && + (kstat_read(sigar->kc, ksp, NULL) != -1) && + (chipid = (kstat_named_t *)kstat_data_lookup(ksp, "chip_id"))) + { + return chipid->value.i32; + } + else { + return -1; + } +} + +int sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu) +{ + int status, i; + + status = sigar_cpu_list_get(sigar, &sigar->cpulist); + + if (status != SIGAR_OK) { + return status; + } + + SIGAR_ZERO(cpu); + + for (i=0; icpulist.number; i++) { + sigar_cpu_t *xcpu = &sigar->cpulist.data[i]; + + cpu->user += xcpu->user; + cpu->sys += xcpu->sys; + cpu->idle += xcpu->idle; + cpu->nice += xcpu->nice; + cpu->wait += xcpu->wait; + cpu->total = xcpu->total; + } + + return SIGAR_OK; +} + +int sigar_cpu_list_get(sigar_t *sigar, sigar_cpu_list_t *cpulist) +{ + kstat_ctl_t *kc = sigar->kc; + kstat_t *ksp; + uint_t cpuinfo[CPU_STATES]; + unsigned int i; + int is_debug = SIGAR_LOG_IS_DEBUG(sigar); + sigar_cache_t *chips; + + if (sigar_kstat_update(sigar) == -1) { + return errno; + } + + if (cpulist == &sigar->cpulist) { + if (sigar->cpulist.size == 0) { + /* create once */ + sigar_cpu_list_create(cpulist); + } + else { + /* reset, re-using cpulist.data */ + sigar->cpulist.number = 0; + } + } + else { + sigar_cpu_list_create(cpulist); + } + + if (is_debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[cpu_list] OS reports %d CPUs", + sigar->ncpu); + } + + chips = sigar_cache_new(16); + chips->free_value = free_chip_id; + + for (i=0; incpu; i++) { + sigar_cpu_t *cpu; + char *buf; + int chip_id; + sigar_cache_entry_t *ent; + + if (!CPU_ONLINE(sigar->ks.cpuid[i])) { + sigar_log_printf(sigar, SIGAR_LOG_INFO, + "cpu %d (id=%d) is offline", + i, sigar->ks.cpuid[i]); + continue; + } + + if (!(ksp = sigar->ks.cpu[i])) { + sigar_log_printf(sigar, SIGAR_LOG_ERROR, + "NULL ksp for cpu %d (id=%d)", + i, sigar->ks.cpuid[i]); + continue; /* shouldnot happen */ + } + + if (kstat_read(kc, ksp, NULL) < 0) { + sigar_log_printf(sigar, SIGAR_LOG_ERROR, + "kstat_read failed for cpu %d (id=%d): %s", + i, sigar->ks.cpuid[i], + sigar_strerror(sigar, errno)); + continue; /* shouldnot happen */ + } + + /* + * cpu_stat_t is not binary compatible between solaris versions. + * since cpu_stat is a 'raw' kstat and not 'named' we cannot + * use name based lookups as we do for others. + * the start of the cpu_stat_t structure is binary compatible, + * which looks like so: + * typedef struct cpu_stat { + * kmutex_t cpu_stat_lock; + * cpu_sysinfo_t cpu_sysinfo; + * ... + * typedef struct cpu_sysinfo { + * ulong cpu[CPU_STATES]; + * ... + * we just copy the piece we need below: + */ + buf = ksp->ks_data; + buf += sizeof(kmutex_t); + memcpy(&cpuinfo[0], buf, sizeof(cpuinfo)); + chip_id = sigar->cpu_list_cores ? -1 : get_chip_id(sigar, i); + + if (chip_id == -1) { + SIGAR_CPU_LIST_GROW(cpulist); + cpu = &cpulist->data[cpulist->number++]; + SIGAR_ZERO(cpu); + } + else { + /* merge times of logical processors */ + ent = sigar_cache_get(chips, chip_id); + if (ent->value) { + cpu = &cpulist->data[(long)ent->value-1]; + } + else { + SIGAR_CPU_LIST_GROW(cpulist); + cpu = &cpulist->data[cpulist->number++]; + ent->value = (void *)(long)cpulist->number; + SIGAR_ZERO(cpu); + + if (is_debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[cpu_list] Merging times of" + " logical processors for chip_id=%d", + chip_id); + } + } + } + + cpu->user += SIGAR_TICK2MSEC(cpuinfo[CPU_USER]); + cpu->sys += SIGAR_TICK2MSEC(cpuinfo[CPU_KERNEL]); + cpu->idle += SIGAR_TICK2MSEC(cpuinfo[CPU_IDLE]); + cpu->wait += SIGAR_TICK2MSEC(cpuinfo[CPU_WAIT]); + cpu->nice += 0; /* no cpu->nice */ + cpu->total = cpu->user + cpu->sys + cpu->idle + cpu->wait; + } + + sigar_cache_destroy(chips); + + return SIGAR_OK; +} + +int sigar_uptime_get(sigar_t *sigar, + sigar_uptime_t *uptime) +{ + if (sigar->boot_time) { + uptime->uptime = time(NULL) - sigar->boot_time; + } + else { + uptime->uptime = 0; /* XXX: shouldn't happen */ + } + + return SIGAR_OK; +} + +static int loadavg_keys[] = { + KSTAT_SYSTEM_LOADAVG_1, + KSTAT_SYSTEM_LOADAVG_2, + KSTAT_SYSTEM_LOADAVG_3 +}; + +int sigar_loadavg_get(sigar_t *sigar, + sigar_loadavg_t *loadavg) +{ + kstat_t *ksp; + int i; + + if (sigar_kstat_update(sigar) == -1) { + return errno; + } + + if (!(ksp = sigar->ks.system)) { + return -1; + } + + if (kstat_read(sigar->kc, ksp, NULL) < 0) { + return -1; + } + + sigar_koffsets_init_system(sigar, ksp); + + for (i=0; i<3; i++) { + loadavg->loadavg[i] = (double)kSYSTEM(loadavg_keys[i]) / FSCALE; + } + + return SIGAR_OK; +} + +#define LIBPROC "/usr/lib/libproc.so" + +#define CHECK_PSYM(s) \ + if (!sigar->s) { \ + sigar_log_printf(sigar, SIGAR_LOG_WARN, \ + "[%s] Symbol not found: %s", \ + SIGAR_FUNC, #s); \ + dlclose(sigar->plib); \ + sigar->plib = NULL; \ + return SIGAR_ENOTIMPL; \ + } + +static char *proc_readlink(const char *name, char *buffer, size_t size) +{ + int len; + + if ((len = readlink(name, buffer, size-1)) < 0) { + return NULL; + } + + buffer[len] = '\0'; + return buffer; +} + +static int sigar_init_libproc(sigar_t *sigar) +{ + if (sigar->plib) { + return SIGAR_OK; + } + + /* libproc.so ships with 5.8+ */ + /* interface is undocumented, see libproc.h in the sun jdk sources */ + sigar->plib = dlopen(LIBPROC, RTLD_LAZY); + + if (!sigar->plib) { + sigar_log_printf(sigar, SIGAR_LOG_WARN, + "[%s] dlopen(%s) = %s", + SIGAR_FUNC, LIBPROC, dlerror()); + return SIGAR_ENOTIMPL; + } + + sigar->pgrab = (proc_grab_func_t)dlsym(sigar->plib, "Pgrab"); + sigar->pfree = (proc_free_func_t)dlsym(sigar->plib, "Pfree"); + sigar->pcreate_agent = (proc_create_agent_func_t)dlsym(sigar->plib, "Pcreate_agent"); + sigar->pdestroy_agent = (proc_destroy_agent_func_t)dlsym(sigar->plib, "Pdestroy_agent"); + sigar->pobjname = (proc_objname_func_t)dlsym(sigar->plib, "Pobjname"); + sigar->pexename = (proc_exename_func_t)dlsym(sigar->plib, "Pexecname"); + sigar->pdirname = (proc_dirname_func_t)dlsym(sigar->plib, "proc_dirname"); + sigar->pfstat64 = (proc_fstat64_func_t)dlsym(sigar->plib, "pr_fstat64"); + sigar->pgetsockopt = (proc_getsockopt_func_t)dlsym(sigar->plib, "pr_getsockopt"); + sigar->pgetsockname = (proc_getsockname_func_t)dlsym(sigar->plib, "pr_getsockname"); + + CHECK_PSYM(pgrab); + CHECK_PSYM(pfree); + CHECK_PSYM(pobjname); + + return SIGAR_OK; +} + +/* from libproc.h, not included w/ solaris distro */ +/* Error codes from Pgrab(), Pfgrab_core(), and Pgrab_core() */ +#define G_STRANGE -1 /* Unanticipated error, errno is meaningful */ +#define G_NOPROC 1 /* No such process */ +#define G_NOCORE 2 /* No such core file */ +#define G_NOPROCORCORE 3 /* No such proc or core (for proc_arg_grab) */ +#define G_NOEXEC 4 /* Cannot locate executable file */ +#define G_ZOMB 5 /* Zombie process */ +#define G_PERM 6 /* No permission */ +#define G_BUSY 7 /* Another process has control */ +#define G_SYS 8 /* System process */ +#define G_SELF 9 /* Process is self */ +#define G_INTR 10 /* Interrupt received while grabbing */ +#define G_LP64 11 /* Process is _LP64, self is ILP32 */ +#define G_FORMAT 12 /* File is not an ELF format core file */ +#define G_ELF 13 /* Libelf error, elf_errno() is meaningful */ +#define G_NOTE 14 /* Required PT_NOTE Phdr not present in core */ + +static int sigar_pgrab(sigar_t *sigar, sigar_pid_t pid, + const char *func, + struct ps_prochandle **phandle) +{ + int pstatus; + + if (!(*phandle = sigar->pgrab(pid, 0x01, &pstatus))) { + switch (pstatus) { + case G_NOPROC: + return ESRCH; + case G_PERM: + return EACCES; + default: + sigar_log_printf(sigar, SIGAR_LOG_ERROR, + "[%s] Pgrab error=%d", + func, pstatus); + return ENOTSUP; /*XXX*/ + } + } + + return SIGAR_OK; +} + +int sigar_os_proc_list_get(sigar_t *sigar, + sigar_proc_list_t *proclist) +{ + return sigar_proc_list_procfs_get(sigar, proclist); +} + +int sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_mem_t *procmem) +{ + int status = sigar_proc_psinfo_get(sigar, pid); + psinfo_t *pinfo = sigar->pinfo; + prusage_t usage; + + if (status != SIGAR_OK) { + return status; + } + + procmem->size = pinfo->pr_size << 10; + procmem->resident = pinfo->pr_rssize << 10; + procmem->share = SIGAR_FIELD_NOTIMPL; + + if (sigar_proc_usage_get(sigar, &usage, pid) == SIGAR_OK) { + procmem->minor_faults = usage.pr_minf; + procmem->major_faults = usage.pr_majf; + procmem->page_faults = + procmem->minor_faults + + procmem->major_faults; + } + else { + procmem->minor_faults = SIGAR_FIELD_NOTIMPL; + procmem->major_faults = SIGAR_FIELD_NOTIMPL; + procmem->page_faults = SIGAR_FIELD_NOTIMPL; + } + + return SIGAR_OK; +} + +int sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_cred_t *proccred) +{ + int status = sigar_proc_psinfo_get(sigar, pid); + psinfo_t *pinfo = sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + + proccred->uid = pinfo->pr_uid; + proccred->gid = pinfo->pr_gid; + proccred->euid = pinfo->pr_euid; + proccred->egid = pinfo->pr_egid; + + return SIGAR_OK; +} + +#define TIMESTRUCT_2MSEC(t) \ + ((t.tv_sec * MILLISEC) + (t.tv_nsec / (NANOSEC/MILLISEC))) + +int sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_time_t *proctime) +{ + prusage_t usage; + int status; + + if ((status = sigar_proc_usage_get(sigar, &usage, pid)) != SIGAR_OK) { + return status; + } + + proctime->start_time = usage.pr_create.tv_sec + sigar->boot_time; + proctime->start_time *= MILLISEC; + + if (usage.pr_utime.tv_sec < 0) { + /* XXX wtf? seen on solaris 10, only for the self process */ + pstatus_t pstatus; + + status = sigar_proc_status_get(sigar, &pstatus, pid); + if (status != SIGAR_OK) { + return status; + } + + usage.pr_utime.tv_sec = pstatus.pr_utime.tv_sec; + usage.pr_utime.tv_nsec = pstatus.pr_utime.tv_nsec; + usage.pr_stime.tv_sec = pstatus.pr_stime.tv_sec; + usage.pr_stime.tv_nsec = pstatus.pr_stime.tv_nsec; + } + + proctime->user = TIMESTRUCT_2MSEC(usage.pr_utime); + proctime->sys = TIMESTRUCT_2MSEC(usage.pr_stime); + proctime->total = proctime->user + proctime->sys; + + return SIGAR_OK; +} + +int sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_state_t *procstate) +{ + int status = sigar_proc_psinfo_get(sigar, pid); + psinfo_t *pinfo = sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + + SIGAR_SSTRCPY(procstate->name, pinfo->pr_fname); + procstate->ppid = pinfo->pr_ppid; + procstate->tty = pinfo->pr_ttydev; + procstate->priority = pinfo->pr_lwp.pr_pri; + procstate->nice = pinfo->pr_lwp.pr_nice - NZERO; + procstate->threads = pinfo->pr_nlwp; + procstate->processor = pinfo->pr_lwp.pr_onpro; + + switch (pinfo->pr_lwp.pr_state) { + case SONPROC: + case SRUN: + procstate->state = 'R'; + break; + case SZOMB: + procstate->state = 'Z'; + break; + case SSLEEP: + procstate->state = 'S'; + break; + case SSTOP: + procstate->state = 'T'; + break; + case SIDL: + procstate->state = 'D'; + break; + } + + return SIGAR_OK; +} + +typedef struct { + int timestamp; + char *args; +} pargs_t; + +static void pargs_free(void *value) +{ + pargs_t *pargs = (pargs_t *)value; + if (pargs->args != NULL) { + free(pargs->args); + } + free(pargs); +} + +static int ucb_ps_args_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs, + int timestamp) +{ + char buffer[9086], *args=NULL, *arg; + sigar_cache_entry_t *ent; + FILE *fp; + pargs_t *pargs; + + if (!sigar->pargs) { + sigar->pargs = sigar_cache_new(15); + sigar->pargs->free_value = pargs_free; + } + + ent = sigar_cache_get(sigar->pargs, pid); + if (ent->value) { + pargs = (pargs_t *)ent->value; + if (pargs->timestamp != timestamp) { + if (pargs->args) { + free(pargs->args); + pargs->args = NULL; + } + } + } + else { + pargs = malloc(sizeof(*pargs)); + pargs->args = NULL; + ent->value = pargs; + } + + pargs->timestamp = timestamp; + + if (pargs->args) { + args = pargs->args; + } + else { + snprintf(buffer, sizeof(buffer), + SIGAR_USR_UCB_PS " -ww %ld", (long)pid); + + if (!(fp = popen(buffer, "r"))) { + return errno; + } + /* skip header */ + (void)fgets(buffer, sizeof(buffer), fp); + if ((args = fgets(buffer, sizeof(buffer), fp))) { + int len; + + /* skip PID,TT,S,TIME */ + args = sigar_skip_multiple_token(args, 4); + SIGAR_SKIP_SPACE(args); + len = strlen(args); + if (len > 0) { + args[len-1] = '\0'; /* chop \n */ + } + + pargs->args = malloc(len+1); + memcpy(pargs->args, args, len); + } + + pclose(fp); + + if (!args) { + return ESRCH; + } + } + + while (*args && (arg = sigar_getword(&args, ' '))) { + SIGAR_PROC_ARGS_GROW(procargs); + procargs->data[procargs->number++] = arg; + } + + return SIGAR_OK; +} + +int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs) +{ + psinfo_t *pinfo; + int fd, status; + char buffer[9086]; + char *argvb[56]; + char **argvp = argvb; + + int n; + size_t nread = 0; + unsigned int argv_size; + + if ((status = sigar_proc_psinfo_get(sigar, pid)) != SIGAR_OK) { + return status; + } + pinfo = sigar->pinfo; + + if (pinfo->pr_argc == 0) { + procargs->number = 0; + return SIGAR_OK; + } + else if (pinfo->pr_dmodel != PR_MODEL_NATIVE) { + /* we are compiled in 32bit mode + * punt any 64bit native process, + * sizeof our structures can't handle. + */ + if (sigar->use_ucb_ps) { + return ucb_ps_args_get(sigar, pid, procargs, + pinfo->pr_start.tv_sec); + } + else { + return ENOTSUP; + } + } + + argv_size = sizeof(*argvp) * pinfo->pr_argc; + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/as"); + + if ((fd = open(buffer, O_RDONLY)) < 0) { + if ((errno == EACCES) && sigar->use_ucb_ps) { + return ucb_ps_args_get(sigar, pid, procargs, + pinfo->pr_start.tv_sec); + } + else { + return PROC_ERRNO; + } + } + + if (argv_size > sizeof(argvb)) { + argvp = malloc(argv_size); + } + + if ((nread = pread(fd, argvp, argv_size, pinfo->pr_argv)) <= 0) { + close(fd); + if (argvp != argvb) { + free(argvp); + } + return errno; + } + + for (n = 0; n < pinfo->pr_argc; n++) { + int alen; + char *arg; + + if ((nread = pread(fd, buffer, sizeof(buffer)-1, (off_t)argvp[n])) <= 0) { + close(fd); + if (argvp != argvb) { + free(argvp); + } + return errno; + } + + buffer[nread] = '\0'; + alen = strlen(buffer)+1; + arg = malloc(alen); + memcpy(arg, buffer, alen); + + SIGAR_PROC_ARGS_GROW(procargs); + procargs->data[procargs->number++] = arg; + } + + if (argvp != argvb) { + free(argvp); + } + + close(fd); + + return SIGAR_OK; +} + +int sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_env_t *procenv) +{ + psinfo_t *pinfo; + int fd, status; + char buffer[BUFSIZ], *offsets[512]; + size_t nread; + int n=0, max=sizeof(offsets)/sizeof(char *); + + if ((status = sigar_proc_psinfo_get(sigar, pid)) != SIGAR_OK) { + return status; + } + pinfo = sigar->pinfo; + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/as"); + + if ((fd = open(buffer, O_RDONLY)) < 0) { + return PROC_ERRNO; + } + + if ((nread = pread(fd, offsets, sizeof(offsets), + pinfo->pr_envp)) <= 0) + { + close(fd); + return errno; + } + + while ((n < max) && offsets[n]) { + char *val; + int klen, vlen, status; + char key[128]; /* XXX is there a max key size? */ + + if ((nread = pread(fd, buffer, sizeof(buffer), + (off_t)offsets[n++])) <= 0) + { + close(fd); + return errno; + } + + val = strchr(buffer, '='); + + if (val == NULL) { + break; /*XXX*/ + } + + klen = val - buffer; + SIGAR_SSTRCPY(key, buffer); + key[klen] = '\0'; + ++val; + + vlen = strlen(val); + + status = procenv->env_getter(procenv->data, + key, klen, val, vlen); + + if (status != SIGAR_OK) { + /* not an error; just stop iterating */ + break; + } + } + + close(fd); + + return SIGAR_OK; +} + +int sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_fd_t *procfd) +{ + int status = + sigar_proc_fd_count(sigar, pid, &procfd->total); + + return status; +} + +static int sigar_proc_path_exe_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_exe_t *procexe) +{ + /* solaris 10+ */ + char buffer[BUFSIZ]; + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/path/a.out"); + if (!proc_readlink(buffer, procexe->name, sizeof(procexe->name))) { + procexe->name[0] = '\0'; + } + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/path/cwd"); + if (!proc_readlink(buffer, procexe->cwd, sizeof(procexe->cwd))) { + procexe->cwd[0] = '\0'; + } + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/path/root"); + if (!proc_readlink(buffer, procexe->root, sizeof(procexe->root))) { + procexe->root[0] = '\0'; + } + + return SIGAR_OK; +} + +static int proc_module_get_exe(void *data, char *name, int len) +{ + sigar_proc_exe_t *procexe = (sigar_proc_exe_t *)data; + SIGAR_STRNCPY(procexe->name, name, sizeof(procexe->name)); + return !SIGAR_OK; /* break loop */ +} + +static int sigar_which_exe_get(sigar_t *sigar, sigar_proc_exe_t *procexe) +{ + char *path = getenv("PATH"); + char exe[PATH_MAX]; + if (path == NULL) { + return EINVAL; + } + + while (path) { + char *ptr = strchr(path, ':'); + if (!ptr) { + break; + } + exe[0] = '\0'; + strncat(exe, path, ptr-path); + strncat(exe, "/", 1); + strcat(exe, procexe->name); + if (access(exe, X_OK) == 0) { + SIGAR_STRNCPY(procexe->name, exe, sizeof(procexe->name)); + break; + } + path = ptr+1; + } + + return ENOENT; +} + +int sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_exe_t *procexe) +{ + int status; + char buffer[BUFSIZ]; + struct ps_prochandle *phandle; + + if (sigar->solaris_version >= 10) { + return sigar_proc_path_exe_get(sigar, pid, procexe); + } + + if ((status = sigar_init_libproc(sigar)) != SIGAR_OK) { + return status; + } + + procexe->name[0] = '\0'; + + /* Pgrab would return G_SELF error */ + if (pid == sigar_pid_get(sigar)) { + sigar_proc_modules_t procmods; + procmods.module_getter = proc_module_get_exe; + procmods.data = procexe; + + status = + sigar_dlinfo_modules(sigar, &procmods); + if (status == SIGAR_OK) { + if (procexe->name[0] != '/') { + sigar_which_exe_get(sigar, procexe); + } + } + } + else { + status = sigar_pgrab(sigar, pid, SIGAR_FUNC, &phandle); + + if (status == SIGAR_OK) { + sigar->pexename(phandle, procexe->name, sizeof(procexe->name)); + sigar->pfree(phandle); + } + } + + if (procexe->name[0] == '\0') { + /*XXX*/ + } + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/cwd"); + + if (!sigar->pdirname(buffer, procexe->cwd, sizeof(procexe->cwd))) { + procexe->cwd[0] = '\0'; + } + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/root"); + + if (!(sigar->pdirname(buffer, procexe->root, sizeof(procexe->root)))) { + procexe->root[0] = '\0'; + } + + return SIGAR_OK; +} + +static int sigar_read_xmaps(sigar_t *sigar, + prxmap_t *xmaps, int total, + unsigned long *last_inode, + struct ps_prochandle *phandle, + sigar_proc_modules_t *procmods) +{ + int status, i; + unsigned long inode; + char buffer[BUFSIZ]; + + for (i=0; ipobjname(phandle, xmaps[i].pr_vaddr, buffer, sizeof(buffer)); + + status = + procmods->module_getter(procmods->data, buffer, strlen(buffer)); + + if (status != SIGAR_OK) { + /* not an error; just stop iterating */ + return status; + } + } + + return SIGAR_OK; +} + +static int sigar_pgrab_modules(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_modules_t *procmods) +{ + int fd, pstatus; + off_t map_size, nread; + unsigned long last_inode = 0; + prxmap_t xmaps[15]; /* ~2K */ + struct ps_prochandle *phandle; + struct stat statbuf; + char buffer[BUFSIZ]; + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/xmap"); + + if ((fd = open(buffer, O_RDONLY)) < 0) { + return errno; + } + + if (fstat(fd, &statbuf) < 0) { + close(fd); + return errno; + } + + map_size = statbuf.st_size; + + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[%s] pid=%d, size=%d", + SIGAR_FUNC, pid, map_size); + } + + if ((pstatus = sigar_init_libproc(sigar)) != SIGAR_OK) { + close(fd); + return pstatus; + } + + pstatus = sigar_pgrab(sigar, pid, SIGAR_FUNC, &phandle); + + if (pstatus != SIGAR_OK) { + close(fd); + return pstatus; + } + + for (nread=0; nread sizeof(xmaps) ? sizeof(xmaps) : map_size; + int total = wanted / sizeof(prxmap_t); + + if (pread(fd, xmaps, wanted, nread) != wanted) { + close(fd); + sigar->pfree(phandle); + return errno; + } + + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[%s] nread=%d, map_size=%d, wanted=%d, total=%d", + SIGAR_FUNC, + nread, map_size, wanted, total); + } + + if (sigar_read_xmaps(sigar, xmaps, total, + &last_inode, + phandle, procmods) != SIGAR_OK) + { + break; + } + + nread += wanted; + map_size -= wanted; + } + + close(fd); + + sigar->pfree(phandle); + + return SIGAR_OK; +} + +int sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_modules_t *procmods) +{ + if (pid == sigar_pid_get(sigar)) { + /* Pgrab would return G_SELF, this is faster anyhow */ + /* XXX one difference to Pgrab, first entry is not the exe name */ + return sigar_dlinfo_modules(sigar, procmods); + } + else { + return sigar_pgrab_modules(sigar, pid, procmods); + } +} + +#define TIME_NSEC(t) \ + (SIGAR_SEC2NANO((t).tv_sec) + (sigar_uint64_t)(t).tv_nsec) + +int sigar_thread_cpu_get(sigar_t *sigar, + sigar_uint64_t id, + sigar_thread_cpu_t *cpu) +{ + struct lwpinfo info; + + if (id != 0) { + return SIGAR_ENOTIMPL; + } + + _lwp_info(&info); + + cpu->user = TIME_NSEC(info.lwp_utime); + cpu->sys = TIME_NSEC(info.lwp_stime); + cpu->total = TIME_NSEC(info.lwp_utime) + TIME_NSEC(info.lwp_stime); + + return SIGAR_OK; +} + +#include + +int sigar_os_fs_type_get(sigar_file_system_t *fsp) +{ + char *type = fsp->sys_type_name; + + switch (*type) { + case 'u': + if (strEQ(type, "ufs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + /* XXX */ + } + + return fsp->type; +} + +int sigar_file_system_list_get(sigar_t *sigar, + sigar_file_system_list_t *fslist) +{ + struct mnttab ent; + sigar_file_system_t *fsp; + FILE *fp = fopen(MNTTAB, "r"); + + if (!fp) { + return errno; + } + + sigar_file_system_list_create(fslist); + + while (getmntent(fp, &ent) == 0) { + if (strstr(ent.mnt_mntopts, "ignore")) { + continue; /* e.g. vold */ + } + + SIGAR_FILE_SYSTEM_LIST_GROW(fslist); + + fsp = &fslist->data[fslist->number++]; + + SIGAR_SSTRCPY(fsp->dir_name, ent.mnt_mountp); + SIGAR_SSTRCPY(fsp->dev_name, ent.mnt_special); + SIGAR_SSTRCPY(fsp->sys_type_name, ent.mnt_fstype); + SIGAR_SSTRCPY(fsp->options, ent.mnt_mntopts); + sigar_fs_type_init(fsp); + } + + fclose(fp); + + return SIGAR_OK; +} + +typedef struct { + char device[PATH_MAX]; + char name[8]; + int instance; +} fsdev_path_t; + +typedef struct { + char name[256]; + int is_partition; + sigar_disk_usage_t disk; +} iodev_t; + +static fsdev_path_t *get_fsdev_paths(sigar_t *sigar, + sigar_file_system_list_t *fslist) +{ + int i, ndisk, size; + char buffer[BUFSIZ], *ptr; + char *dev, *inst, *drv; + fsdev_path_t *paths, *mapping; + FILE *fp = fopen("/etc/path_to_inst", "r"); + + if (!fp) { + return NULL; + } + + for (i=0, ndisk=0; inumber; i++) { + sigar_file_system_t *fsp = &fslist->data[i]; + if (fsp->type == SIGAR_FSTYPE_LOCAL_DISK) { + ndisk++; + } + } + + size = sizeof(*paths) * (ndisk+1); + mapping = paths = malloc(size); + memset(mapping, '\0', size); + + while ((ptr = fgets(buffer, sizeof(buffer), fp))) { + /* eat dust java */ + char *q; + + SIGAR_SKIP_SPACE(ptr); + if (*ptr == '#') { + continue; + } + if (*ptr == '"') { + ptr++; + } + dev = ptr; + if (!(q = strchr(ptr, '"'))) { + continue; + } + ptr = q+1; + *q = '\0'; + SIGAR_SKIP_SPACE(ptr); + inst = ptr; + while (sigar_isdigit(*ptr)) { + ptr++; + } + *ptr = '\0'; + ptr++; + SIGAR_SKIP_SPACE(ptr); + if (*ptr == '"') { + ptr++; + } + drv = ptr; + if (!(q = strchr(ptr, '"'))) { + continue; + } + *q = '\0'; + + if (!(strEQ(drv, "sd") || + strEQ(drv, "ssd") || + strEQ(drv, "st") || + strEQ(drv, "dad") || + strEQ(drv, "cmdk"))) + { + continue; + } + + paths->instance = atoi(inst); + if (!kstat_lookup(sigar->kc, drv, paths->instance, NULL)) { + continue; + } + + SIGAR_SSTRCPY(paths->device, dev); + SIGAR_SSTRCPY(paths->name, drv); + + if (--ndisk < 0) { + /* XXX prevent overflow */ + break; + } + paths++; + } + fclose(fp); + + return mapping; +} + +static int create_fsdev_cache(sigar_t *sigar) +{ + fsdev_path_t *paths, *mapping; + sigar_file_system_list_t fslist; + int i, j; + int status; + int debug = SIGAR_LOG_IS_DEBUG(sigar); + + sigar->fsdev = sigar_cache_new(15); + + status = sigar_file_system_list_get(sigar, &fslist); + + if (status != SIGAR_OK) { + return status; + } + + if (!(mapping = get_fsdev_paths(sigar, &fslist))) { + sigar_file_system_list_destroy(sigar, &fslist); + return ENOENT; + } + + for (i=0; itype == SIGAR_FSTYPE_LOCAL_DISK) { + char device[PATH_MAX+1], *ptr=device; + int len = readlink(fsp->dev_name, device, sizeof(device)-1); + char *s; + char partition; + + if (len < 0) { + continue; + } + device[len] = '\0'; + + if (debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "[fsdev] name=%s, dev=%s", + fsp->dev_name, device); + } + + while (strnEQ(ptr, "../", 3)) { + ptr += 3; + } + if (strnEQ(ptr, "devices", 7)) { + ptr += 7; + } + if ((s = strchr(ptr, ':'))) { + partition = *(s+1); + } + else { + continue; + } + + for (j=0, paths=mapping; paths->name[0]; j++) { + if (strnEQ(paths->device, ptr, strlen(paths->device))) { + sigar_cache_entry_t *ent; + struct stat sb; + int retval = stat(fsp->dir_name, &sb); + iodev_t *iodev; + + if (retval == 0) { + iodev = malloc(sizeof(*iodev)); + + SIGAR_DISK_STATS_INIT(&iodev->disk); + /* e.g. sd9,g + * module == sd + * instance == 9 + * partition == 8 + */ + snprintf(iodev->name, sizeof(iodev->name), "%s%d,%c", + paths->name, paths->instance, partition); + + ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb)); + ent->value = iodev; + + if (debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[fsdev] map %s -> %s", + fsp->dir_name, iodev->name); + } + } + break; + } + paths++; + } + } + } + + free(mapping); + sigar_file_system_list_destroy(sigar, &fslist); + + return SIGAR_OK; +} + +static int io_kstat_read(sigar_t *sigar, + sigar_disk_usage_t *disk, + kstat_t *ksp) +{ + kstat_io_t *io; + + kstat_read(sigar->kc, ksp, NULL); + + io = (kstat_io_t *)ksp->ks_data; + + disk->reads = io->reads; + disk->writes = io->writes; + disk->read_bytes = io->nread; + disk->write_bytes = io->nwritten; + disk->qtime = io->wlentime; + disk->rtime = io->rlentime; + disk->wtime = io->wlentime; + disk->time = disk->rtime + disk->wtime; + disk->snaptime = ksp->ks_snaptime; + + return SIGAR_OK; +} + + +static int sigar_kstat_disk_usage_get(sigar_t *sigar, const char *name, + sigar_disk_usage_t *disk, + kstat_t **kio) +{ + kstat_t *ksp; + + if (sigar_kstat_update(sigar) == -1) { + return errno; + } + + for (ksp = sigar->kc->kc_chain; + ksp; + ksp = ksp->ks_next) + { + if (ksp->ks_type != KSTAT_TYPE_IO) { + continue; + } + if (strEQ(ksp->ks_name, name)) { + int status = io_kstat_read(sigar, disk, ksp); + *kio = ksp; + return status; + } + } + + return ENXIO; +} + +static int simple_hash(const char *s) +{ + int hash = 0; + while (*s) { + hash = 31*hash + *s++; + } + return hash; +} + +int sigar_disk_usage_get(sigar_t *sigar, const char *name, + sigar_disk_usage_t *disk) +{ + kstat_t *ksp; + int status; + iodev_t *iodev = NULL; + sigar_cache_entry_t *ent; + sigar_uint64_t id; + + SIGAR_DISK_STATS_INIT(disk); + + if (!sigar->fsdev) { + if (create_fsdev_cache(sigar) != SIGAR_OK) { + return SIGAR_OK; + } + } + + if (*name == '/') { + struct stat sb; + + if (stat(name, &sb) < 0) { + return errno; + } + + id = SIGAR_FSDEV_ID(sb); + ent = sigar_cache_get(sigar->fsdev, id); + if (ent->value == NULL) { + return ENXIO; + } + iodev = (iodev_t *)ent->value; + + status = sigar_kstat_disk_usage_get(sigar, iodev->name, disk, &ksp); + } + else { + status = sigar_kstat_disk_usage_get(sigar, name, disk, &ksp); + if (status != SIGAR_OK) { + return status; + } + id = simple_hash(name); /*XXX*/ + ent = sigar_cache_get(sigar->fsdev, id); + if (ent->value) { + iodev = (iodev_t *)ent->value; + } + else { + ent->value = iodev = malloc(sizeof(*iodev)); + SIGAR_SSTRCPY(iodev->name, name); + SIGAR_DISK_STATS_INIT(&iodev->disk); + } + } + + /* service_time formula derived from opensolaris.org:iostat.c */ + if ((status == SIGAR_OK) && iodev) { + sigar_uint64_t delta; + double avw, avr, tps, mtps; + double etime, hr_etime; + + if (iodev->disk.snaptime) { + delta = disk->snaptime - iodev->disk.snaptime; + } + else { + delta = ksp->ks_crtime - ksp->ks_snaptime; + } + + hr_etime = (double)delta; + if (hr_etime == 0.0) { + hr_etime = (double)NANOSEC; + } + etime = hr_etime / (double)NANOSEC; + + tps = + (((double)(disk->reads - iodev->disk.reads)) / etime) + + (((double)(disk->writes - iodev->disk.writes)) / etime); + + delta = disk->wtime - iodev->disk.wtime; + if (delta) { + avw = (double)delta; + avw /= hr_etime; + } + else { + avw = 0.0; + } + + delta = disk->rtime - iodev->disk.rtime; + if (delta) { + avr = (double)delta; + avr /= hr_etime; + } + else { + avr = 0.0; + } + + disk->queue = avw; + disk->service_time = 0.0; + + if (tps && (avw != 0.0 || avr != 0.0)) { + mtps = 1000.0 / tps; + if (avw != 0.0) { + disk->service_time += avw * mtps; + } + if (avr != 0.0) { + disk->service_time += avr * mtps; + } + } + + memcpy(&iodev->disk, disk, sizeof(iodev->disk)); + } + + return status; +} + +int sigar_file_system_usage_get(sigar_t *sigar, + const char *dirname, + sigar_file_system_usage_t *fsusage) +{ + int status = sigar_statvfs(sigar, dirname, fsusage); + + if (status != SIGAR_OK) { + return status; + } + + fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage); + + sigar_disk_usage_get(sigar, dirname, &fsusage->disk); + + return SIGAR_OK; +} + +int sigar_cpu_info_list_get(sigar_t *sigar, + sigar_cpu_info_list_t *cpu_infos) +{ + processor_info_t stats; + unsigned int i; + int status = SIGAR_OK; + int brand = -1; + sigar_cache_t *chips; + int is_debug = SIGAR_LOG_IS_DEBUG(sigar); + int nsockets = 0; + + if (sigar_kstat_update(sigar) == -1) { /* for sigar->ncpu */ + return errno; + } + + /* + * stats we care about will be the same for each + * online processor, so just grab the first. + */ + for (i=0; incpu; i++) { + processorid_t id = sigar->ks.cpuid[i]; + + if ((status = processor_info(id, &stats)) < 0) { + continue; + } + else { + status = SIGAR_OK; + break; + } + } + + if (status != SIGAR_OK) { + /* should never happen */ + return ENOENT; + } + + sigar_cpu_info_list_create(cpu_infos); + chips = sigar_cache_new(16); + chips->free_value = free_chip_id; + + for (i=0; incpu; i++) { + sigar_cpu_info_t *info; + int chip_id = get_chip_id(sigar, i); + + if (chip_id != -1) { + sigar_cache_entry_t *ent = + sigar_cache_get(chips, chip_id); + + if (ent->value) { + if (!sigar->cpu_list_cores) { + continue; + } + } + else { + ++nsockets; + ent->value = chips; /*anything non-NULL*/ + if (is_debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[cpu_list] Merging info of" + " logical processors for chip_id=%d", + chip_id); + } + } + } + else { + ++nsockets; + } + + SIGAR_CPU_INFO_LIST_GROW(cpu_infos); + + info = &cpu_infos->data[cpu_infos->number++]; + + SIGAR_SSTRCPY(info->model, stats.pi_processor_type); + + if (brand == -1) { + brand = get_chip_brand(sigar, i, info); + } + + if (strEQ(info->model, "i386")) { + if (!brand) { + /* assume Intel on x86 */ + SIGAR_SSTRCPY(info->vendor, "Intel"); + } + SIGAR_SSTRCPY(info->model, "x86"); + } + else { + if (!brand) { + /* assume Sun */ + SIGAR_SSTRCPY(info->vendor, "Sun"); + } + /* s/sparc/Sparc/ */ + info->model[0] = toupper(info->model[0]); + } + + if (brand) { + SIGAR_SSTRCPY(info->vendor, cpu_infos->data[0].vendor); + } + + info->mhz = stats.pi_clock; + info->cache_size = SIGAR_FIELD_NOTIMPL; /*XXX*/ + } + + sigar_cache_destroy(chips); + + for (i=0; inumber; i++) { + sigar_cpu_info_t *info = &cpu_infos->data[i]; + info->total_sockets = nsockets; + info->total_cores = sigar->ncpu; + info->cores_per_socket = sigar->ncpu / nsockets; + } + + return SIGAR_OK; +} + +int sigar_net_route_list_get(sigar_t *sigar, + sigar_net_route_list_t *routelist) + +{ + char *data; + int len, rc; + struct opthdr *op; + size_t nread=0, size=0; + const char *size_from; + + sigar_net_route_list_create(routelist); + + while ((rc = get_mib2(&sigar->mib2, &op, &data, &len)) == GET_MIB2_OK) { + mib2_ipRouteEntry_t *entry; + char *end; + + if (op->level != MIB2_IP) { + continue; + } + + if (op->name == 0) { + /* we want to use this size for bincompat */ + size = ((mib2_ip_t *)data)->ipRouteEntrySize; + continue; + } + else if (op->name != MIB2_IP_21) { + continue; + } + + if (size == 0) { + size_from = "sizeof"; + size = sizeof(*entry); + } + else { + size_from = "mib2_ip"; + } + + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[route_list] ipRouteEntrySize=%d (from %s)", + size, size_from); + } + + for (entry = (mib2_ipRouteEntry_t *)data, end = data + len; + (char *)entry < end; + nread+=size, entry = (mib2_ipRouteEntry_t *)((char *)data+nread)) + { + sigar_net_route_t *route; + int type = entry->ipRouteInfo.re_ire_type; + + /* filter same as netstat -r */ + if ((type == IRE_CACHE) || + (type == IRE_BROADCAST) || + (type == IRE_LOCAL)) + { + continue; + } + + SIGAR_NET_ROUTE_LIST_GROW(routelist); + route = &routelist->data[routelist->number++]; + + sigar_net_address_set(route->destination, + entry->ipRouteDest); + + sigar_net_address_set(route->gateway, + entry->ipRouteNextHop); + + sigar_net_address_set(route->mask, + entry->ipRouteMask); + + route->refcnt = entry->ipRouteInfo.re_ref; + route->irtt = entry->ipRouteInfo.re_rtt; + route->metric = entry->ipRouteMetric1; + + SIGAR_SSTRCPY(route->ifname, entry->ipRouteIfIndex.o_bytes); + + route->flags = RTF_UP; + if ((route->destination.addr.in == 0) && + (route->mask.addr.in == 0)) + { + route->flags |= RTF_GATEWAY; + } + + route->use = route->window = route->mtu = + SIGAR_FIELD_NOTIMPL; /*XXX*/ + } + } + + if (rc != GET_MIB2_EOD) { + close_mib2(&sigar->mib2); + return SIGAR_EMIB2; + } + + return SIGAR_OK; +} + +static void ifstat_kstat_common(sigar_net_interface_stat_t *ifstat, + kstat_named_t *data, int ndata) +{ + int i; + + for (i=0; itx_collisions = value; + } + break; + case 'd': + if (strEQ(ptr, "drop")) { + ifstat->rx_dropped = value; + ifstat->tx_dropped = value; + } + break; + case 'i': + if (strEQ(ptr, "ipackets")) { + if (ifstat->rx_packets == 0) { + ifstat->rx_packets = value; + } + } + else if (strEQ(ptr, "ipackets64")) { + ifstat->rx_packets = data[i].value.ui64; + } + else if (strEQ(ptr, "ierrors")) { + ifstat->rx_errors = value; + } + else if (strEQ(ptr, "ifspeed")) { + ifstat->speed = value; + } + break; + case 'f': + if (strEQ(ptr, "framing")) { + ifstat->rx_frame = value; + } + break; + case 'm': + if (strEQ(ptr, "missed")) { + ifstat->rx_dropped = value; + ifstat->tx_dropped = value; + } + break; + case 'n': + if (strEQ(ptr, "nocarrier")) { + ifstat->tx_carrier = value; + } + break; + case 'o': + if (strEQ(ptr, "obytes")) { + if (ifstat->tx_bytes == 0) { + ifstat->tx_bytes = value; + } + } + else if (strEQ(ptr, "obytes64")) { + ifstat->tx_bytes = data[i].value.ui64; + } + else if (strEQ(ptr, "oerrors")) { + ifstat->tx_errors = value; + } + else if (strEQ(ptr, "oflo")) { + ifstat->tx_overruns = value; + } + else if (strEQ(ptr, "opackets")) { + if (ifstat->tx_packets == 0) { + ifstat->tx_packets = value; + } + } + else if (strEQ(ptr, "opackets64")) { + ifstat->tx_packets = data[i].value.ui64; + } + else if (strEQ(ptr, "toolong_errors")) { + ifstat->tx_overruns = value; + } + break; + case 'r': + if (strEQ(ptr, "rbytes")) { + if (ifstat->rx_bytes == 0) { + ifstat->rx_bytes = value; + } + } + else if (strEQ(ptr, "rbytes64")) { + ifstat->rx_bytes = data[i].value.ui64; + } + else if (strEQ(ptr, "rx_overflow")) { + ifstat->rx_overruns = value; + } + break; + default: + break; + } + } +} + +static int sigar_net_ifstat_get_any(sigar_t *sigar, const char *name, + sigar_net_interface_stat_t *ifstat) +{ + kstat_ctl_t *kc = sigar->kc; + kstat_t *ksp; + kstat_named_t *data; + + if (sigar_kstat_update(sigar) == -1) { + return errno; + } + + if (!(ksp = kstat_lookup(kc, NULL, -1, (char *)name))) { + return ENXIO; + } + + if (kstat_read(kc, ksp, NULL) < 0) { + return ENOENT; + } + + data = (kstat_named_t *)ksp->ks_data; + + ifstat_kstat_common(ifstat, data, ksp->ks_ndata); + + return SIGAR_OK; +} + +/* loopback interface only has rx/tx packets */ +static int sigar_net_ifstat_get_lo(sigar_t *sigar, const char *name, + sigar_net_interface_stat_t *ifstat) +{ + ifstat->rx_packets = 0; + ifstat->rx_bytes = SIGAR_FIELD_NOTIMPL; + ifstat->rx_errors = SIGAR_FIELD_NOTIMPL; + ifstat->rx_dropped = SIGAR_FIELD_NOTIMPL; + ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL; + ifstat->rx_frame = SIGAR_FIELD_NOTIMPL; + + ifstat->tx_packets = 0; + ifstat->tx_bytes = SIGAR_FIELD_NOTIMPL; + ifstat->tx_errors = SIGAR_FIELD_NOTIMPL; + ifstat->tx_dropped = SIGAR_FIELD_NOTIMPL; + ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL; + ifstat->tx_collisions = SIGAR_FIELD_NOTIMPL; + ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL; + + ifstat->speed = SIGAR_FIELD_NOTIMPL; + + return sigar_net_ifstat_get_any(sigar, name, ifstat); +} + +int sigar_net_interface_stat_get(sigar_t *sigar, const char *name, + sigar_net_interface_stat_t *ifstat) +{ + ifstat->speed = SIGAR_FIELD_NOTIMPL; + + if (strnEQ(name, "lo", 2)) { + return sigar_net_ifstat_get_lo(sigar, name, ifstat); + } + else { + SIGAR_ZERO(ifstat); + return sigar_net_ifstat_get_any(sigar, name, ifstat); + } +} + +int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig) +{ + int sock; + struct lifreq lifr; + + if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + return errno; + } + + SIGAR_SSTRCPY(lifr.lifr_name, name); + + if (ioctl(sock, SIOCGLIFADDR, &lifr) == 0) { + struct in6_addr *addr = SIGAR_SIN6_ADDR(&lifr.lifr_addr); + + sigar_net_address6_set(ifconfig->address6, addr); + sigar_net_interface_scope6_set(ifconfig, addr); + ifconfig->prefix6_length = lifr.lifr_addrlen; + } + + close(sock); + return SIGAR_OK; +} + +#define TCPQ_SIZE(s) ((s) >= 0 ? (s) : 0) + +static int tcp_connection_get(sigar_net_connection_walker_t *walker, + struct mib2_tcpConnEntry *entry, + int len) +{ + int flags = walker->flags; + int status; + char *end = (char *)entry + len; + + while ((char *)entry < end) { + int state = entry->tcpConnEntryInfo.ce_state; + + if (((flags & SIGAR_NETCONN_SERVER) && (state == TCPS_LISTEN)) || + ((flags & SIGAR_NETCONN_CLIENT) && (state != TCPS_LISTEN))) + { + sigar_net_connection_t conn; + + SIGAR_ZERO(&conn); + + sigar_net_address_set(conn.local_address, entry->tcpConnLocalAddress); + sigar_net_address_set(conn.remote_address, entry->tcpConnRemAddress); + + conn.local_port = entry->tcpConnLocalPort; + conn.remote_port = entry->tcpConnRemPort; + conn.type = SIGAR_NETCONN_TCP; + conn.send_queue = + TCPQ_SIZE(entry->tcpConnEntryInfo.ce_snxt - + entry->tcpConnEntryInfo.ce_suna - 1); + conn.receive_queue = + TCPQ_SIZE(entry->tcpConnEntryInfo.ce_rnxt - + entry->tcpConnEntryInfo.ce_rack); + + switch (state) { + case TCPS_CLOSED: + conn.state = SIGAR_TCP_CLOSE; + break; + case TCPS_IDLE: + conn.state = SIGAR_TCP_IDLE; + break; + case TCPS_BOUND: + conn.state = SIGAR_TCP_BOUND; + break; + case TCPS_LISTEN: + conn.state = SIGAR_TCP_LISTEN; + break; + case TCPS_SYN_SENT: + conn.state = SIGAR_TCP_SYN_SENT; + break; + case TCPS_SYN_RCVD: + conn.state = SIGAR_TCP_SYN_RECV; + break; + case TCPS_ESTABLISHED: + conn.state = SIGAR_TCP_ESTABLISHED; + break; + case TCPS_CLOSE_WAIT: + conn.state = SIGAR_TCP_CLOSE_WAIT; + break; + case TCPS_FIN_WAIT_1: + conn.state = SIGAR_TCP_FIN_WAIT1; + break; + case TCPS_CLOSING: + conn.state = SIGAR_TCP_CLOSING; + break; + case TCPS_LAST_ACK: + conn.state = SIGAR_TCP_LAST_ACK; + break; + case TCPS_FIN_WAIT_2: + conn.state = SIGAR_TCP_FIN_WAIT2; + break; + case TCPS_TIME_WAIT: + conn.state = SIGAR_TCP_TIME_WAIT; + break; + default: + conn.state = SIGAR_TCP_UNKNOWN; + break; + } + + status = walker->add_connection(walker, &conn); + if (status != SIGAR_OK) { + return status; + } + } + + entry++; + } + + return SIGAR_OK; +} + +static int udp_connection_get(sigar_net_connection_walker_t *walker, + struct mib2_udpEntry *entry, + int len) +{ + int flags = walker->flags; + int status; + char *end = (char *)entry + len; + + while ((char *)entry < end) { + int state = entry->udpEntryInfo.ue_state; + + /* XXX dunno if this state check is right */ + if (((flags & SIGAR_NETCONN_SERVER) && (state == MIB2_UDP_idle)) || + ((flags & SIGAR_NETCONN_CLIENT) && (state != MIB2_UDP_idle))) + { + sigar_net_connection_t conn; + + SIGAR_ZERO(&conn); + + sigar_net_address_set(conn.local_address, entry->udpLocalAddress); + sigar_net_address_set(conn.remote_address, 0); + + conn.local_port = entry->udpLocalPort; + conn.remote_port = 0; + conn.type = SIGAR_NETCONN_UDP; + + status = walker->add_connection(walker, &conn); + if (status != SIGAR_OK) { + return status; + } + } + + entry++; + } + + return SIGAR_OK; +} + +int sigar_net_connection_walk(sigar_net_connection_walker_t *walker) +{ + sigar_t *sigar = walker->sigar; + int flags = walker->flags; + int status; + int want_tcp = flags & SIGAR_NETCONN_TCP; + int want_udp = flags & SIGAR_NETCONN_UDP; + char *data; + int len; + int rc; + struct opthdr *op; + + while ((rc = get_mib2(&sigar->mib2, &op, &data, &len)) == GET_MIB2_OK) { + if ((op->level == MIB2_TCP) && + (op->name == MIB2_TCP_13) && + want_tcp) + { + status = + tcp_connection_get(walker, + (struct mib2_tcpConnEntry *)data, + len); + } + else if ((op->level == MIB2_UDP) && + (op->name == MIB2_UDP_5) && + want_udp) + { + status = + udp_connection_get(walker, + (struct mib2_udpEntry *)data, + len); + } + else { + status = SIGAR_OK; + } + + if (status != SIGAR_OK) { + break; + } + } + + if (rc != GET_MIB2_EOD) { + close_mib2(&sigar->mib2); + return SIGAR_EMIB2; + } + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) +sigar_tcp_get(sigar_t *sigar, + sigar_tcp_t *tcp) +{ + char *data; + int len; + int rc; + struct opthdr *op; + mib2_tcp_t *mib = NULL; + + while ((rc = get_mib2(&sigar->mib2, &op, &data, &len)) == GET_MIB2_OK) { + if ((op->level == MIB2_TCP) && (op->name == 0)) { + mib = (mib2_tcp_t *)data; + break; + } + } + + if (mib) { + tcp->active_opens = mib->tcpActiveOpens; + tcp->passive_opens = mib->tcpPassiveOpens; + tcp->attempt_fails = mib->tcpAttemptFails; + tcp->estab_resets = mib->tcpEstabResets; + tcp->curr_estab = mib->tcpCurrEstab; + tcp->in_segs = mib->tcpInSegs; + tcp->out_segs = mib->tcpOutSegs; + tcp->retrans_segs = mib->tcpRetransSegs; + tcp->in_errs = SIGAR_FIELD_NOTIMPL; /* XXX mib2_ip_t.tcpInErrs */ + tcp->out_rsts = mib->tcpOutRsts; + return SIGAR_OK; + } + else { + return SIGAR_ENOTIMPL; + } +} + +static int sigar_nfs_get(sigar_t *sigar, + char *type, + char **names, + char *nfs) +{ + size_t offset; + kstat_t *ksp; + int i; + + if (sigar_kstat_update(sigar) == -1) { + return errno; + } + + if (!(ksp = kstat_lookup(sigar->kc, "nfs", 0, type))) { + return SIGAR_ENOTIMPL; + } + + if (kstat_read(sigar->kc, ksp, NULL) < 0) { + return errno; + } + + for (i=0, offset=0; + names[i]; + i++, offset+=sizeof(sigar_uint64_t)) + { + sigar_uint64_t val; + kstat_named_t *kv = + kstat_data_lookup(ksp, names[i]); + + if (kv) { + val = kv->value.ui64; + } + else { + val = -1; + } + + *(sigar_uint64_t *)((char *)nfs + offset) = val; + } + + return SIGAR_OK; +} + +static char *nfs_v2_names[] = { + "null", + "getattr", + "setattr", + "root", + "lookup", + "readlink", + "read", + "wrcache", + "write", + "create", + "remove", + "rename", + "link", + "symlink", + "mkdir", + "rmdir", + "readdir", + "statfs", + NULL +}; + +int sigar_nfs_client_v2_get(sigar_t *sigar, + sigar_nfs_client_v2_t *nfs) +{ + return sigar_nfs_get(sigar, "rfsreqcnt_v2", nfs_v2_names, (char *)nfs); +} + +int sigar_nfs_server_v2_get(sigar_t *sigar, + sigar_nfs_server_v2_t *nfs) +{ + return sigar_nfs_get(sigar, "rfsproccnt_v2", nfs_v2_names, (char *)nfs); +} + +static char *nfs_v3_names[] = { + "null", + "getattr", + "setattr", + "lookup", + "access", + "readlink", + "read", + "write", + "create", + "mkdir", + "symlink", + "mknod", + "remove", + "rmdir", + "rename", + "link", + "readdir", + "readdirplus", + "fsstat", + "fsinfo", + "pathconf", + "commit", + NULL +}; + +int sigar_nfs_client_v3_get(sigar_t *sigar, + sigar_nfs_client_v3_t *nfs) +{ + return sigar_nfs_get(sigar, "rfsreqcnt_v3", nfs_v3_names, (char *)nfs); +} + +int sigar_nfs_server_v3_get(sigar_t *sigar, + sigar_nfs_server_v3_t *nfs) +{ + return sigar_nfs_get(sigar, "rfsproccnt_v3", nfs_v3_names, (char *)nfs); +} + +int sigar_arp_list_get(sigar_t *sigar, + sigar_arp_list_t *arplist) +{ + char *data; + int len, rc; + struct opthdr *op; + size_t nread=0, size=0; + const char *size_from; + + sigar_arp_list_create(arplist); + + while ((rc = get_mib2(&sigar->mib2, &op, &data, &len)) == GET_MIB2_OK) { + mib2_ipNetToMediaEntry_t *entry; + char *end; + + if (op->level != MIB2_IP) { + continue; + } + + if (op->name == 0) { + /* we want to use this size for bincompat */ + size = ((mib2_ip_t *)data)->ipNetToMediaEntrySize; + continue; + } + else if (op->name != MIB2_IP_MEDIA) { + continue; + } + + if (size == 0) { + size_from = "sizeof"; + size = sizeof(*entry); + } + else { + size_from = "mib2_ip"; + } + + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[arp_list] ipNetToMediaEntrySize=%d (from %s)", + size, size_from); + } + + for (entry = (mib2_ipNetToMediaEntry_t *)data, end = data + len; + (char *)entry < end; + nread+=size, entry = (mib2_ipNetToMediaEntry_t *)((char *)data+nread)) + { + sigar_arp_t *arp; + + SIGAR_ARP_LIST_GROW(arplist); + arp = &arplist->data[arplist->number++]; + + sigar_net_address_set(arp->address, + entry->ipNetToMediaNetAddress); + + sigar_net_address_mac_set(arp->hwaddr, + entry->ipNetToMediaPhysAddress.o_bytes, + entry->ipNetToMediaPhysAddress.o_length); + + SIGAR_SSTRCPY(arp->ifname, entry->ipNetToMediaIfIndex.o_bytes); + + arp->flags = entry->ipNetToMediaInfo.ntm_flags; + SIGAR_SSTRCPY(arp->type, "ether"); /*XXX*/ + } + } + + if (rc != GET_MIB2_EOD) { + close_mib2(&sigar->mib2); + return SIGAR_EMIB2; + } + + return SIGAR_OK; +} + +static int find_port(sigar_t *sigar, struct ps_prochandle *phandle, + sigar_pid_t pid, unsigned long port) +{ + DIR *dirp; + struct dirent *ent; + char pname[PATH_MAX]; + struct stat64 statb; + int found=0; + + sprintf(pname, "/proc/%d/fd", (int)pid); + + if (!(dirp = opendir(pname))) { + return 0; + } + + while ((ent = readdir(dirp))) { + int fd; + + if (!sigar_isdigit(ent->d_name[0])) { + continue; + } + fd = atoi(ent->d_name); + + if (sigar->pfstat64(phandle, fd, &statb) == -1) { + continue; + } + + if ((statb.st_mode & S_IFMT) == S_IFSOCK) { + struct sockaddr_in sin; + struct sockaddr *sa = (struct sockaddr *)&sin; + socklen_t len = sizeof(sin); + int opt, optsz, rc; + + optsz = sizeof(opt); + rc = sigar->pgetsockopt(phandle, fd, SOL_SOCKET, SO_TYPE, &opt, &optsz); + if (rc != 0) { + continue; + } + if (opt != SOCK_STREAM) { + continue; + } + optsz = sizeof(opt); + rc = sigar->pgetsockopt(phandle, fd, SOL_SOCKET, SO_ACCEPTCONN, &opt, &optsz); + if (rc != 0) { + continue; + } + if (opt != SO_ACCEPTCONN) { + continue; + } + + rc = sigar->pgetsockname(phandle, fd, sa, &len); + if (rc != 0) { + continue; + } + + if ((sa->sa_family == AF_INET) || + (sa->sa_family == AF_INET6)) + { + if (ntohs(sin.sin_port) == port) { + found = 1; + break; + } + } + } + } + + closedir(dirp); + + return found; +} + +/* derived from /usr/bin/pfiles.c */ +int sigar_proc_port_get(sigar_t *sigar, int protocol, + unsigned long port, sigar_pid_t *pid) +{ + sigar_proc_list_t pids; + int i, status, found=0; + + if (sigar->solaris_version < 10) { + return SIGAR_ENOTIMPL; + } + + if ((status = sigar_init_libproc(sigar)) != SIGAR_OK) { + return SIGAR_ENOTIMPL; + } + status = sigar_proc_list_get(sigar, &pids); + if (status != SIGAR_OK) { + return status; + } + + for (i=0; ipcreate_agent(phandle) == 0) { + found = find_port(sigar, phandle, ps_id, port); + sigar->pdestroy_agent(phandle); + } + + sigar->pfree(phandle); + if (found) { + *pid = ps_id; + break; + } + } + + sigar_proc_list_destroy(sigar, &pids); + + return found ? SIGAR_OK : ENOENT; +} + +int sigar_os_sys_info_get(sigar_t *sigar, + sigar_sys_info_t *sys_info) +{ + char *vendor_version; + + sysinfo(SI_ARCHITECTURE, sys_info->arch, sizeof(sys_info->arch)); + + SIGAR_SSTRCPY(sys_info->name, "Solaris"); + SIGAR_SSTRCPY(sys_info->vendor, "Sun Microsystems"); + + if (strEQ(sys_info->version, "5.6")) { + vendor_version = "2.6"; + } + else { + if ((vendor_version = strchr(sys_info->version, '.'))) { + ++vendor_version; + } + else { + vendor_version = sys_info->version; + } + } + + SIGAR_SSTRCPY(sys_info->vendor_version, vendor_version); + + snprintf(sys_info->description, + sizeof(sys_info->description), + "%s %s", + sys_info->name, sys_info->vendor_version); + + return SIGAR_OK; +} diff --git a/vendor/sigar/src/os/win32/peb.c b/vendor/sigar/src/os/win32/peb.c new file mode 100644 index 0000000..d8b2eca --- /dev/null +++ b/vendor/sigar/src/os/win32/peb.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2004, 2006-2008 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2009 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * functions for getting info from the Process Environment Block + */ +#define UNICODE +#define _UNICODE + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_os.h" +#include + +void dllmod_init_ntdll(sigar_t *sigar); + +#define sigar_NtQueryInformationProcess \ + sigar->ntdll.query_proc_info.func + +static int sigar_pbi_get(sigar_t *sigar, HANDLE proc, PEB *peb) +{ + int status; + PROCESS_BASIC_INFORMATION pbi; + DWORD size=sizeof(pbi); + + dllmod_init_ntdll(sigar); + + if (!sigar_NtQueryInformationProcess) { + return SIGAR_ENOTIMPL; + } + + SIGAR_ZERO(&pbi); + status = + sigar_NtQueryInformationProcess(proc, + ProcessBasicInformation, + &pbi, + size, NULL); + if (status != ERROR_SUCCESS) { + return status; + } + + if (!pbi.PebBaseAddress) { + /* likely we are 32-bit, pid process is 64-bit */ + return ERROR_DATATYPE_MISMATCH; + } + + size = sizeof(*peb); + + if (ReadProcessMemory(proc, pbi.PebBaseAddress, peb, size, NULL)) { + return SIGAR_OK; + } + else { + return GetLastError(); + } +} + +static int sigar_rtl_get(sigar_t *sigar, HANDLE proc, + RTL_USER_PROCESS_PARAMETERS *rtl) +{ + PEB peb; + int status = sigar_pbi_get(sigar, proc, &peb); + DWORD size=sizeof(*rtl); + + if (status != SIGAR_OK) { + return status; + } + + if (ReadProcessMemory(proc, peb.ProcessParameters, rtl, size, NULL)) { + return SIGAR_OK; + } + else { + return GetLastError(); + } +} + +#define rtl_bufsize(buf, uc) \ + ((sizeof(buf) < uc.Length) ? sizeof(buf) : uc.Length) + +int sigar_proc_exe_peb_get(sigar_t *sigar, HANDLE proc, + sigar_proc_exe_t *procexe) +{ + int status; + WCHAR buf[MAX_PATH+1]; + RTL_USER_PROCESS_PARAMETERS rtl; + DWORD size; + + procexe->name[0] = '\0'; + procexe->cwd[0] = '\0'; + + if ((status = sigar_rtl_get(sigar, proc, &rtl)) != SIGAR_OK) { + return status; + } + + size = rtl_bufsize(buf, rtl.ImagePathName); + memset(buf, '\0', sizeof(buf)); + + if ((size > 0) && + ReadProcessMemory(proc, rtl.ImagePathName.Buffer, buf, size, NULL)) + { + SIGAR_W2A(buf, procexe->name, sizeof(procexe->name)); + } + + size = rtl_bufsize(buf, rtl.CurrentDirectoryName); + memset(buf, '\0', sizeof(buf)); + + if ((size > 0) && + ReadProcessMemory(proc, rtl.CurrentDirectoryName.Buffer, buf, size, NULL)) + { + SIGAR_W2A(buf, procexe->cwd, sizeof(procexe->cwd)); + } + + return SIGAR_OK; +} + +int sigar_parse_proc_args(sigar_t *sigar, WCHAR *buf, + sigar_proc_args_t *procargs) +{ + char arg[SIGAR_CMDLINE_MAX]; + LPWSTR *args; + int num, i; + + if (!buf) { + buf = GetCommandLine(); + } + + args = CommandLineToArgvW(buf, &num); + + if (args == NULL) { + return SIGAR_OK; + } + + for (i=0; idata[procargs->number++] = sigar_strdup(arg); + } + + GlobalFree(args); + + return SIGAR_OK; +} + +int sigar_proc_args_peb_get(sigar_t *sigar, HANDLE proc, + sigar_proc_args_t *procargs) +{ + int status; + WCHAR buf[SIGAR_CMDLINE_MAX]; + RTL_USER_PROCESS_PARAMETERS rtl; + DWORD size; + + if ((status = sigar_rtl_get(sigar, proc, &rtl)) != SIGAR_OK) { + return status; + } + + size = rtl_bufsize(buf, rtl.CommandLine); + if (size <= 0) { + return ERROR_DATATYPE_MISMATCH; /* fallback to wmi */ + } + memset(buf, '\0', sizeof(buf)); + + if (ReadProcessMemory(proc, rtl.CommandLine.Buffer, buf, size, NULL)) { + return sigar_parse_proc_args(sigar, buf, procargs); + } + else { + return GetLastError(); + } +} + +int sigar_proc_env_peb_get(sigar_t *sigar, HANDLE proc, + WCHAR *buf, DWORD size) +{ + int status; + RTL_USER_PROCESS_PARAMETERS rtl; + MEMORY_BASIC_INFORMATION info; + + if ((status = sigar_rtl_get(sigar, proc, &rtl)) != SIGAR_OK) { + return status; + } + + memset(buf, '\0', size); + /* -2 to ensure \0\0 terminator */ + size -= 2; + + if (VirtualQueryEx(proc, rtl.Environment, &info, sizeof(info))) { + if (size > info.RegionSize) { + /* ReadProcessMemory beyond region would fail */ + size = info.RegionSize; + } + } + + if (ReadProcessMemory(proc, rtl.Environment, buf, size, NULL)) { + return SIGAR_OK; + } + else { + return GetLastError(); + } +} diff --git a/vendor/sigar/src/os/win32/sigar_os.h b/vendor/sigar/src/os/win32/sigar_os.h new file mode 100755 index 0000000..cf61c25 --- /dev/null +++ b/vendor/sigar/src/os/win32/sigar_os.h @@ -0,0 +1,676 @@ +/* + * Copyright (c) 2004-2009 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2009-2010 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGAR_OS_H +#define SIGAR_OS_H + +#if !defined(MSVC) && defined(_MSC_VER) +#define MSVC +#endif + +#ifdef MSVC +#define WIN32_LEAN_AND_MEAN +#define snprintf _snprintf +#if _MSC_VER <= 1200 +#define SIGAR_USING_MSC6 /* Visual Studio version 6 */ +#define HAVE_MIB_IPADDRROW_WTYPE 0 +#else +#define HAVE_MIB_IPADDRROW_WTYPE 1 +#endif +#else +/* Cross compiling */ +#define _WIN32_WINNT 0x0501 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sigar_util.h" + +#ifdef MSVC +# define INT64_C(val) val##i64 +# define SIGAR_DLLFUNC(api, name) \ + struct { \ + const char *name; \ + ##api##_##name func; \ + } ##name +#else +/* The GCC compiler doesn't require/accept the ## prefix */ +# define INT64_C(val) val##L +# define SIGAR_DLLFUNC(api, name) \ + struct { \ + const char *name; \ + api##_##name func; \ + } name +#endif + +/* see apr/include/arch/win32/atime.h */ +#define EPOCH_DELTA INT64_C(11644473600000000) + +#define SIGAR_CMDLINE_MAX 4096<<2 + +/* XXX: support CP_UTF8 ? */ + +#define SIGAR_A2W(lpa, lpw, bytes) \ + (lpw[0] = 0, MultiByteToWideChar(CP_ACP, 0, \ + lpa, -1, lpw, (bytes/sizeof(WCHAR)))) + +#define SIGAR_W2A(lpw, lpa, chars) \ + (lpa[0] = '\0', WideCharToMultiByte(CP_ACP, 0, \ + lpw, -1, (LPSTR)lpa, chars, \ + NULL, NULL)) + +/* iptypes.h from vc7, not available in vc6 */ +/* copy from PSDK if using vc6 */ +#include "iptypes.h" + +/* from wtsapi32.h not in vs6.0 */ +typedef enum { + WTSInitialProgram, + WTSApplicationName, + WTSWorkingDirectory, + WTSOEMId, + WTSSessionId, + WTSUserName, + WTSWinStationName, + WTSDomainName, + WTSConnectState, + WTSClientBuildNumber, + WTSClientName, + WTSClientDirectory, + WTSClientProductId, + WTSClientHardwareId, + WTSClientAddress, + WTSClientDisplay, + WTSClientProtocolType, +} WTS_INFO_CLASS; + +typedef enum _WTS_CONNECTSTATE_CLASS { + WTSActive, + WTSConnected, + WTSConnectQuery, + WTSShadow, + WTSDisconnected, + WTSIdle, + WTSListen, + WTSReset, + WTSDown, + WTSInit +} WTS_CONNECTSTATE_CLASS; + +#define WTS_PROTOCOL_TYPE_CONSOLE 0 +#define WTS_PROTOCOL_TYPE_ICA 1 +#define WTS_PROTOCOL_TYPE_RDP 2 + +typedef struct _WTS_SESSION_INFO { + DWORD SessionId; + LPTSTR pWinStationName; + DWORD State; +} WTS_SESSION_INFO, *PWTS_SESSION_INFO; + +typedef struct _WTS_PROCESS_INFO { + DWORD SessionId; + DWORD ProcessId; + LPSTR pProcessName; + PSID pUserSid; +} WTS_PROCESS_INFO, *PWTS_PROCESS_INFO; + +typedef struct _WTS_CLIENT_ADDRESS { + DWORD AddressFamily; + BYTE Address[20]; +} WTS_CLIENT_ADDRESS, *PWTS_CLIENT_ADDRESS; + +/* the WINSTATION_INFO stuff here is undocumented + * got the howto from google groups: + * http://redirx.com/?31gy + */ +typedef enum _WINSTATION_INFO_CLASS { + WinStationInformation = 8 +} WINSTATION_INFO_CLASS; + +typedef struct _WINSTATION_INFO { + BYTE Reserved1[72]; + ULONG SessionId; + BYTE Reserved2[4]; + FILETIME ConnectTime; + FILETIME DisconnectTime; + FILETIME LastInputTime; + FILETIME LoginTime; + BYTE Reserved3[1096]; + FILETIME CurrentTime; +} WINSTATION_INFO, *PWINSTATION_INFO; + +/* end wtsapi32.h */ + +#ifdef SIGAR_USING_MSC6 + +/* from winbase.h not in vs6.0 */ +typedef struct { + DWORD dwLength; + DWORD dwMemoryLoad; + DWORDLONG ullTotalPhys; + DWORDLONG ullAvailPhys; + DWORDLONG ullTotalPageFile; + DWORDLONG ullAvailPageFile; + DWORDLONG ullTotalVirtual; + DWORDLONG ullAvailVirtual; + DWORDLONG ullAvailExtendedVirtual; +} MEMORYSTATUSEX; + +/* service manager stuff not in vs6.0 */ +typedef struct _SERVICE_STATUS_PROCESS { + DWORD dwServiceType; + DWORD dwCurrentState; + DWORD dwControlsAccepted; + DWORD dwWin32ExitCode; + DWORD dwServiceSpecificExitCode; + DWORD dwCheckPoint; + DWORD dwWaitHint; + DWORD dwProcessId; + DWORD dwServiceFlags; +} SERVICE_STATUS_PROCESS; + +typedef enum { + SC_STATUS_PROCESS_INFO = 0 +} SC_STATUS_TYPE; + +#ifndef ERROR_DATATYPE_MISMATCH +#define ERROR_DATATYPE_MISMATCH 1629L +#endif + +#endif /* _MSC_VER */ + +#include + +/* undocumented structures */ +typedef struct { + DWORD dwState; + DWORD dwLocalAddr; + DWORD dwLocalPort; + DWORD dwRemoteAddr; + DWORD dwRemotePort; + DWORD dwProcessId; +} MIB_TCPEXROW, *PMIB_TCPEXROW; + +typedef struct { + DWORD dwNumEntries; + MIB_TCPEXROW table[ANY_SIZE]; +} MIB_TCPEXTABLE, *PMIB_TCPEXTABLE; + +typedef struct { + DWORD dwLocalAddr; + DWORD dwLocalPort; + DWORD dwProcessId; +} MIB_UDPEXROW, *PMIB_UDPEXROW; + +typedef struct { + DWORD dwNumEntries; + MIB_UDPEXROW table[ANY_SIZE]; +} MIB_UDPEXTABLE, *PMIB_UDPEXTABLE; + +/* end undocumented structures */ + +/* no longer in the standard header files */ +typedef struct { + LARGE_INTEGER IdleTime; + LARGE_INTEGER KernelTime; + LARGE_INTEGER UserTime; + LARGE_INTEGER DpcTime; + LARGE_INTEGER InterruptTime; + ULONG InterruptCount; +} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION; + +#define SystemProcessorPerformanceInformation 8 + +/* PEB decls from msdn docs w/ slight mods */ +#define ProcessBasicInformation 0 + +typedef struct _UNICODE_STRING { + USHORT Length; + USHORT MaximumLength; + PWSTR Buffer; +} UNICODE_STRING, *PUNICODE_STRING; + +typedef struct _PEB_LDR_DATA { + BYTE Reserved1[8]; + PVOID Reserved2[3]; + LIST_ENTRY InMemoryOrderModuleList; +} PEB_LDR_DATA, *PPEB_LDR_DATA; + +typedef struct RTL_DRIVE_LETTER_CURDIR { + USHORT Flags; + USHORT Length; + ULONG TimeStamp; + UNICODE_STRING DosPath; +} RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR; + +/* from: http://source.winehq.org/source/include/winternl.h */ +typedef struct _RTL_USER_PROCESS_PARAMETERS { + ULONG AllocationSize; + ULONG Size; + ULONG Flags; + ULONG DebugFlags; + HANDLE hConsole; + ULONG ProcessGroup; + HANDLE hStdInput; + HANDLE hStdOutput; + HANDLE hStdError; + UNICODE_STRING CurrentDirectoryName; + HANDLE CurrentDirectoryHandle; + UNICODE_STRING DllPath; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; + PWSTR Environment; + ULONG dwX; + ULONG dwY; + ULONG dwXSize; + ULONG dwYSize; + ULONG dwXCountChars; + ULONG dwYCountChars; + ULONG dwFillAttribute; + ULONG dwFlags; + ULONG wShowWindow; + UNICODE_STRING WindowTitle; + UNICODE_STRING Desktop; + UNICODE_STRING ShellInfo; + UNICODE_STRING RuntimeInfo; + RTL_DRIVE_LETTER_CURDIR DLCurrentDirectory[0x20]; +} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; + +/* from msdn docs +typedef struct _RTL_USER_PROCESS_PARAMETERS { + BYTE Reserved1[16]; + PVOID Reserved2[10]; + UNICODE_STRING ImagePathName; + UNICODE_STRING CommandLine; +} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS; +*/ + +typedef struct _PEB { + BYTE Reserved1[2]; + BYTE BeingDebugged; + BYTE Reserved2[1]; + PVOID Reserved3[2]; + PPEB_LDR_DATA Ldr; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + BYTE Reserved4[104]; + PVOID Reserved5[52]; + /*PPS_POST_PROCESS_INIT_ROUTINE*/ PVOID PostProcessInitRoutine; + BYTE Reserved6[128]; + PVOID Reserved7[1]; + ULONG SessionId; +} PEB, *PPEB; + +typedef struct _PROCESS_BASIC_INFORMATION { + PVOID Reserved1; + PPEB PebBaseAddress; + PVOID Reserved2[2]; + /*ULONG_PTR*/ UINT_PTR UniqueProcessId; + PVOID Reserved3; +} PROCESS_BASIC_INFORMATION; + +typedef struct { + sigar_pid_t pid; + int ppid; + int priority; + time_t mtime; + sigar_uint64_t size; + sigar_uint64_t resident; + char name[SIGAR_PROC_NAME_LEN]; + char state; + sigar_uint64_t handles; + sigar_uint64_t threads; + sigar_uint64_t page_faults; +} sigar_win32_pinfo_t; + +typedef struct { + const char *name; + HINSTANCE handle; +} sigar_dll_handle_t; + +typedef struct { + const char *name; + FARPROC func; +} sigar_dll_func_t; + +typedef struct { + const char *name; + HINSTANCE handle; + sigar_dll_func_t funcs[12]; +} sigar_dll_module_t; + +/* wtsapi.dll */ +typedef BOOL (CALLBACK *wtsapi_enum_sessions)(HANDLE, + DWORD, + DWORD, + PWTS_SESSION_INFO *, + DWORD *); + +typedef void (CALLBACK *wtsapi_free_mem)(PVOID); + +typedef BOOL (CALLBACK *wtsapi_query_session)(HANDLE, + DWORD, + WTS_INFO_CLASS, + LPSTR *, DWORD *); +/* iphlpapi.dll */ + +typedef DWORD (CALLBACK *iphlpapi_get_ipforward_table)(PMIB_IPFORWARDTABLE, + PULONG, + BOOL); + +typedef DWORD (CALLBACK *iphlpapi_get_ipaddr_table)(PMIB_IPADDRTABLE, + PULONG, + BOOL); + +typedef DWORD (CALLBACK *iphlpapi_get_if_table)(PMIB_IFTABLE, + PULONG, + BOOL); + +typedef DWORD (CALLBACK *iphlpapi_get_if_entry)(PMIB_IFROW); + +typedef DWORD (CALLBACK *iphlpapi_get_num_if)(PDWORD); + +typedef DWORD (CALLBACK *iphlpapi_get_tcp_table)(PMIB_TCPTABLE, + PDWORD, + BOOL); + +typedef DWORD (CALLBACK *iphlpapi_get_udp_table)(PMIB_UDPTABLE, + PDWORD, + BOOL); + +typedef DWORD (CALLBACK *iphlpapi_get_tcpx_table)(PMIB_TCPEXTABLE *, + BOOL, + HANDLE, + DWORD, + DWORD); + +typedef DWORD (CALLBACK *iphlpapi_get_udpx_table)(PMIB_UDPEXTABLE *, + BOOL, + HANDLE, + DWORD, + DWORD); + +typedef DWORD (CALLBACK *iphlpapi_get_tcp_stats)(PMIB_TCPSTATS); + +typedef DWORD (CALLBACK *iphlpapi_get_net_params)(PFIXED_INFO, + PULONG); + +typedef DWORD (CALLBACK *iphlpapi_get_adapters_info)(PIP_ADAPTER_INFO, + PULONG); + +typedef ULONG (CALLBACK *iphlpapi_get_adapters_addrs)(ULONG, + ULONG, + PVOID, + PIP_ADAPTER_ADDRESSES, + PULONG); + +/* advapi32.dll */ +typedef BOOL (CALLBACK *advapi_convert_string_sid)(LPCSTR, + PSID *); + +typedef BOOL (CALLBACK *advapi_query_service_status)(SC_HANDLE, + SC_STATUS_TYPE, + LPBYTE, + DWORD, + LPDWORD); + +typedef DWORD (CALLBACK *iphlpapi_get_ipnet_table)(PMIB_IPNETTABLE, + PDWORD, + BOOL); + +/* ntdll.dll */ +typedef DWORD (CALLBACK *ntdll_query_sys_info)(DWORD, + PVOID, + ULONG, + PULONG); + +typedef DWORD (CALLBACK *ntdll_query_proc_info)(HANDLE, + DWORD, + PVOID, + ULONG, + PULONG); + +/* psapi.dll */ +typedef BOOL (CALLBACK *psapi_enum_modules)(HANDLE, + HMODULE *, + DWORD, + LPDWORD); + +typedef DWORD (CALLBACK *psapi_get_module_name)(HANDLE, + HMODULE, + LPTSTR, + DWORD); + +typedef BOOL (CALLBACK *psapi_enum_processes)(DWORD *, + DWORD, + DWORD *); + +/* winsta.dll */ +typedef BOOLEAN (CALLBACK *winsta_query_info)(HANDLE, + ULONG, + WINSTATION_INFO_CLASS, + PVOID, + ULONG, + PULONG); + +/* kernel32.dll */ +typedef BOOL (CALLBACK *kernel_memory_status)(MEMORYSTATUSEX *); + +/* mpr.dll */ +typedef BOOL (CALLBACK *mpr_get_net_connection)(LPCTSTR, + LPTSTR, + LPDWORD); + +typedef struct { + sigar_dll_handle_t handle; + + SIGAR_DLLFUNC(wtsapi, enum_sessions); + SIGAR_DLLFUNC(wtsapi, free_mem); + SIGAR_DLLFUNC(wtsapi, query_session); + + sigar_dll_func_t end; +} sigar_wtsapi_t; + +typedef struct { + sigar_dll_handle_t handle; + + SIGAR_DLLFUNC(iphlpapi, get_ipforward_table); + SIGAR_DLLFUNC(iphlpapi, get_ipaddr_table); + SIGAR_DLLFUNC(iphlpapi, get_if_table); + SIGAR_DLLFUNC(iphlpapi, get_if_entry); + SIGAR_DLLFUNC(iphlpapi, get_num_if); + SIGAR_DLLFUNC(iphlpapi, get_tcp_table); + SIGAR_DLLFUNC(iphlpapi, get_udp_table); + SIGAR_DLLFUNC(iphlpapi, get_tcpx_table); + SIGAR_DLLFUNC(iphlpapi, get_udpx_table); + SIGAR_DLLFUNC(iphlpapi, get_tcp_stats); + SIGAR_DLLFUNC(iphlpapi, get_net_params); + SIGAR_DLLFUNC(iphlpapi, get_adapters_info); + SIGAR_DLLFUNC(iphlpapi, get_adapters_addrs); + SIGAR_DLLFUNC(iphlpapi, get_ipnet_table); + + sigar_dll_func_t end; +} sigar_iphlpapi_t; + +typedef struct { + sigar_dll_handle_t handle; + + SIGAR_DLLFUNC(advapi, convert_string_sid); + SIGAR_DLLFUNC(advapi, query_service_status); + + sigar_dll_func_t end; +} sigar_advapi_t; + +typedef struct { + sigar_dll_handle_t handle; + + SIGAR_DLLFUNC(ntdll, query_sys_info); + SIGAR_DLLFUNC(ntdll, query_proc_info); + + sigar_dll_func_t end; +} sigar_ntdll_t; + +typedef struct { + sigar_dll_handle_t handle; + + SIGAR_DLLFUNC(psapi, enum_modules); + SIGAR_DLLFUNC(psapi, enum_processes); + SIGAR_DLLFUNC(psapi, get_module_name); + + sigar_dll_func_t end; +} sigar_psapi_t; + +typedef struct { + sigar_dll_handle_t handle; + + SIGAR_DLLFUNC(winsta, query_info); + + sigar_dll_func_t end; +} sigar_winsta_t; + +typedef struct { + sigar_dll_handle_t handle; + + SIGAR_DLLFUNC(kernel, memory_status); + + sigar_dll_func_t end; +} sigar_kernel_t; + +typedef struct { + sigar_dll_handle_t handle; + + SIGAR_DLLFUNC(mpr, get_net_connection); + + sigar_dll_func_t end; +} sigar_mpr_t; + +struct sigar_t { + SIGAR_T_BASE; + char *machine; + int using_wide; + long pagesize; + HKEY handle; + char *perfbuf; + DWORD perfbuf_size; + sigar_wtsapi_t wtsapi; + sigar_iphlpapi_t iphlpapi; + sigar_advapi_t advapi; + sigar_ntdll_t ntdll; + sigar_psapi_t psapi; + sigar_winsta_t winsta; + sigar_kernel_t kernel; + sigar_mpr_t mpr; + sigar_win32_pinfo_t pinfo; + sigar_cache_t *netif_adapters; + sigar_cache_t *netif_mib_rows; + sigar_cache_t *netif_addr_rows; + sigar_cache_t *netif_names; /* dwIndex -> net_interface_config.name */ + int netif_name_short; + + WORD ws_version; + int ws_error; + int ht_enabled; + int lcpu; //number of logical cpus + int winnt; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +sigar_uint64_t sigar_FileTimeToTime(FILETIME *ft); + +int sigar_wsa_init(sigar_t *sigar); + +int sigar_proc_exe_peb_get(sigar_t *sigar, HANDLE proc, + sigar_proc_exe_t *procexe); + +int sigar_proc_args_peb_get(sigar_t *sigar, HANDLE proc, + sigar_proc_args_t *procargs); + +int sigar_proc_env_peb_get(sigar_t *sigar, HANDLE proc, + WCHAR *env, DWORD envlen); + +int sigar_proc_args_wmi_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs); + +int sigar_proc_exe_wmi_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_exe_t *procexe); + +int sigar_parse_proc_args(sigar_t *sigar, WCHAR *buf, + sigar_proc_args_t *procargs); + +int sigar_service_pid_get(sigar_t *sigar, char *name, sigar_pid_t *pid); + +typedef struct { + DWORD size; + DWORD count; + ENUM_SERVICE_STATUS *services; + SC_HANDLE handle; +} sigar_services_status_t; + +int sigar_services_status_get(sigar_services_status_t *ss, DWORD state); + +void sigar_services_status_close(sigar_services_status_t *ss); + +typedef struct sigar_services_walker_t sigar_services_walker_t; + +struct sigar_services_walker_t { + sigar_t *sigar; + int flags; + void *data; /* user data */ + int (*add_service)(sigar_services_walker_t *walker, char *name); +}; + +int sigar_services_query(char *ptql, + sigar_ptql_error_t *error, + sigar_services_walker_t *walker); + +char *sigar_service_exe_get(char *path, char *buffer, int basename); + +typedef struct { + WORD product_major; + WORD product_minor; + WORD product_build; + WORD product_revision; + WORD file_major; + WORD file_minor; + WORD file_build; + WORD file_revision; +} sigar_file_version_t; + +int sigar_file_version_get(sigar_file_version_t *version, + char *name, + sigar_proc_env_t *infocb); + +#ifdef __cplusplus +} +#endif + +#define SIGAR_NO_SUCH_PROCESS (SIGAR_OS_START_ERROR+1) + +#endif /* SIGAR_OS_H */ diff --git a/vendor/sigar/src/os/win32/sigar_pdh.h b/vendor/sigar/src/os/win32/sigar_pdh.h new file mode 100644 index 0000000..86a481a --- /dev/null +++ b/vendor/sigar/src/os/win32/sigar_pdh.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2004, 2006 Hyperic, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SIGAR_PDH_H +#define SIGAR_PDH_H + +/* performance data helpers */ + +#define PdhFirstObject(block) \ + ((PERF_OBJECT_TYPE *)((BYTE *) block + block->HeaderLength)) + +#define PdhNextObject(object) \ + ((PERF_OBJECT_TYPE *)((BYTE *) object + object->TotalByteLength)) + +#define PdhFirstCounter(object) \ + ((PERF_COUNTER_DEFINITION *)((BYTE *) object + object->HeaderLength)) + +#define PdhNextCounter(counter) \ + ((PERF_COUNTER_DEFINITION *)((BYTE *) counter + counter->ByteLength)) + +#define PdhGetCounterBlock(inst) \ + ((PERF_COUNTER_BLOCK *)((BYTE *) inst + inst->ByteLength)) + +#define PdhFirstInstance(object) \ + ((PERF_INSTANCE_DEFINITION *)((BYTE *) object + object->DefinitionLength)) + +#define PdhNextInstance(inst) \ + ((PERF_INSTANCE_DEFINITION *)((BYTE *)inst + inst->ByteLength + \ + PdhGetCounterBlock(inst)->ByteLength)) + +#define PdhInstanceName(inst) \ + ((wchar_t *)((BYTE *)inst + inst->NameOffset)) + +#endif /* SIGAR_PDH_H */ diff --git a/vendor/sigar/src/os/win32/win32_sigar.c b/vendor/sigar/src/os/win32/win32_sigar.c new file mode 100755 index 0000000..4288f08 --- /dev/null +++ b/vendor/sigar/src/os/win32/win32_sigar.c @@ -0,0 +1,3992 @@ +/* + * Copyright (c) 2004-2009 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2009-2010 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_pdh.h" +#include "sigar_os.h" +#include "sigar_util.h" +#include "sigar_format.h" +#include +#ifndef MSVC +#include +#endif + +#define USING_WIDE_S(s) (s)->using_wide +#define USING_WIDE() USING_WIDE_S(sigar) + +#define PERFBUF_SIZE 8192 + +#define PERF_TITLE_PROC 230 +#define PERF_TITLE_SYS_KEY "2" +#define PERF_TITLE_MEM_KEY "4" +#define PERF_TITLE_PROC_KEY "230" +#define PERF_TITLE_CPU_KEY "238" +#define PERF_TITLE_DISK_KEY "236" + +#define PERF_TITLE_CPU_USER 142 +#define PERF_TITLE_CPU_IDLE 1746 +#define PERF_TITLE_CPU_SYS 144 +#define PERF_TITLE_CPU_IRQ 698 + +typedef enum { + PERF_IX_CPU_USER, + PERF_IX_CPU_IDLE, + PERF_IX_CPU_SYS, + PERF_IX_CPU_IRQ, + PERF_IX_CPU_MAX +} perf_cpu_offsets_t; + +#define PERF_TITLE_CPUTIME 6 +#define PERF_TITLE_PAGE_FAULTS 28 +#define PERF_TITLE_MEM_VSIZE 174 +#define PERF_TITLE_MEM_SIZE 180 +#define PERF_TITLE_THREAD_CNT 680 +#define PERF_TITLE_HANDLE_CNT 952 +#define PERF_TITLE_PID 784 +#define PERF_TITLE_PPID 1410 +#define PERF_TITLE_PRIORITY 682 +#define PERF_TITLE_START_TIME 684 + +typedef enum { + PERF_IX_CPUTIME, + PERF_IX_PAGE_FAULTS, + PERF_IX_MEM_VSIZE, + PERF_IX_MEM_SIZE, + PERF_IX_THREAD_CNT, + PERF_IX_HANDLE_CNT, + PERF_IX_PID, + PERF_IX_PPID, + PERF_IX_PRIORITY, + PERF_IX_START_TIME, + PERF_IX_MAX +} perf_proc_offsets_t; + +typedef enum { + PERF_IX_DISK_TIME, + PERF_IX_DISK_READ_TIME, + PERF_IX_DISK_WRITE_TIME, + PERF_IX_DISK_READ, + PERF_IX_DISK_WRITE, + PERF_IX_DISK_READ_BYTES, + PERF_IX_DISK_WRITE_BYTES, + PERF_IX_DISK_QUEUE, + PERF_IX_DISK_MAX +} perf_disk_offsets_t; + +#define PERF_TITLE_DISK_TIME 200 /* % Disk Time */ +#define PERF_TITLE_DISK_READ_TIME 202 /* % Disk Read Time */ +#define PERF_TITLE_DISK_WRITE_TIME 204 /* % Disk Write Time */ +#define PERF_TITLE_DISK_READ 214 /* Disk Reads/sec */ +#define PERF_TITLE_DISK_WRITE 216 /* Disk Writes/sec */ +#define PERF_TITLE_DISK_READ_BYTES 220 /* Disk Read Bytes/sec */ +#define PERF_TITLE_DISK_WRITE_BYTES 222 /* Disk Write Bytes/sec */ +#define PERF_TITLE_DISK_QUEUE 198 /* Current Disk Queue Length */ + +/* + * diff is: + * ExW -> ExA + * wcounter -> counter + */ +#define MyRegQueryValue() \ + (USING_WIDE() ? \ + RegQueryValueExW(sigar->handle, \ + wcounter_key, NULL, &type, \ + sigar->perfbuf, \ + &bytes) : \ + RegQueryValueExA(sigar->handle, \ + counter_key, NULL, &type, \ + sigar->perfbuf, \ + &bytes)) + +#define PERF_VAL(ix) \ + perf_offsets[ix] ? \ + *((DWORD *)((BYTE *)counter_block + perf_offsets[ix])) : 0 + +/* 1/100ns units to milliseconds */ +#define NS100_2MSEC(t) ((t) / 10000) + +#define PERF_VAL_CPU(ix) \ + NS100_2MSEC(PERF_VAL(ix)) + +#define MS_LOOPBACK_ADAPTER "Microsoft Loopback Adapter" +#define NETIF_LA "la" + +static int get_proc_info(sigar_t *sigar, sigar_pid_t pid); +static int netif_hash(char *s); + +sigar_uint64_t sigar_FileTimeToTime(FILETIME *ft) +{ + sigar_uint64_t time; + time = ft->dwHighDateTime; + time = time << 32; + time |= ft->dwLowDateTime; + time /= 10; + time -= EPOCH_DELTA; + return time; +} + +static DWORD perfbuf_init(sigar_t *sigar) +{ + if (!sigar->perfbuf) { + sigar->perfbuf = malloc(PERFBUF_SIZE); + sigar->perfbuf_size = PERFBUF_SIZE; + } + + return sigar->perfbuf_size; +} + +static DWORD perfbuf_grow(sigar_t *sigar) +{ + sigar->perfbuf_size += PERFBUF_SIZE; + + sigar->perfbuf = + realloc(sigar->perfbuf, sigar->perfbuf_size); + + return sigar->perfbuf_size; +} + +static char *get_counter_name(char *key) +{ + if (strEQ(key, PERF_TITLE_MEM_KEY)) { + return "Memory"; + } + else if (strEQ(key, PERF_TITLE_PROC_KEY)) { + return "Process"; + } + else if (strEQ(key, PERF_TITLE_CPU_KEY)) { + return "Processor"; + } + else if (strEQ(key, PERF_TITLE_DISK_KEY)) { + return "LogicalDisk"; + } + else { + return key; + } +} + +static PERF_OBJECT_TYPE *get_perf_object_inst(sigar_t *sigar, + char *counter_key, + DWORD inst, DWORD *err) +{ + DWORD retval, type, bytes; + WCHAR wcounter_key[MAX_PATH+1]; + PERF_DATA_BLOCK *block; + PERF_OBJECT_TYPE *object; + + *err = SIGAR_OK; + + if (USING_WIDE()) { + SIGAR_A2W(counter_key, wcounter_key, sizeof(wcounter_key)); + } + + bytes = perfbuf_init(sigar); + + while ((retval = MyRegQueryValue()) != ERROR_SUCCESS) { + if (retval == ERROR_MORE_DATA) { + bytes = perfbuf_grow(sigar); + } + else { + *err = retval; + return NULL; + } + } + + block = (PERF_DATA_BLOCK *)sigar->perfbuf; + if (block->NumObjectTypes == 0) { + counter_key = get_counter_name(counter_key); + sigar_strerror_printf(sigar, "No %s counters defined (disabled?)", + counter_key); + *err = -1; + return NULL; + } + object = PdhFirstObject(block); + + /* + * only seen on windows 2003 server when pdh.dll + * functions are in use by the same process. + * confucius say what the fuck. + */ + if (inst && (object->NumInstances == PERF_NO_INSTANCES)) { + int i; + + for (i=0; iNumObjectTypes; i++) { + if (object->NumInstances != PERF_NO_INSTANCES) { + return object; + } + object = PdhNextObject(object); + } + return NULL; + } + else { + return object; + } +} + +#define get_perf_object(sigar, counter_key, err) \ + get_perf_object_inst(sigar, counter_key, 1, err) + +static int get_mem_counters(sigar_t *sigar, sigar_swap_t *swap, sigar_mem_t *mem) +{ + int status; + PERF_OBJECT_TYPE *object = + get_perf_object_inst(sigar, PERF_TITLE_MEM_KEY, 0, &status); + PERF_INSTANCE_DEFINITION *inst; + PERF_COUNTER_DEFINITION *counter; + BYTE *data; + DWORD i; + + if (!object) { + return status; + } + + data = (BYTE *)((BYTE *)object + object->DefinitionLength); + + for (i=0, counter = PdhFirstCounter(object); + iNumCounters; + i++, counter = PdhNextCounter(counter)) + { + DWORD offset = counter->CounterOffset; + + switch (counter->CounterNameTitleIndex) { + case 48: /* "Pages Output/sec" */ + if (swap) swap->page_out = *((DWORD *)(data + offset)); + break; + case 76: /* "System Cache Resident Bytes" aka file cache */ + if (mem) { + sigar_uint64_t kern = *((DWORD *)(data + offset)); + mem->actual_free = mem->free + kern; + mem->actual_used = mem->used - kern; + return SIGAR_OK; + } + case 822: /* "Pages Input/sec" */ + if (swap) swap->page_in = *((DWORD *)(data + offset)); + break; + default: + continue; + } + } + + return SIGAR_OK; +} + +static void get_sysinfo(sigar_t *sigar) +{ + SYSTEM_INFO sysinfo; + + GetSystemInfo(&sysinfo); + + sigar->ncpu = sysinfo.dwNumberOfProcessors; + sigar->pagesize = sysinfo.dwPageSize; +} + +/* for C# bindings */ +SIGAR_DECLARE(sigar_t *) sigar_new(void) +{ + sigar_t *sigar; + if (sigar_open(&sigar) != SIGAR_OK) { + return NULL; + } + return sigar; +} + +static sigar_wtsapi_t sigar_wtsapi = { + "wtsapi32.dll", + NULL, + { "WTSEnumerateSessionsA", NULL }, + { "WTSFreeMemory", NULL }, + { "WTSQuerySessionInformationA", NULL }, + { NULL, NULL } +}; + +static sigar_iphlpapi_t sigar_iphlpapi = { + "iphlpapi.dll", + NULL, + { "GetIpForwardTable", NULL }, + { "GetIpAddrTable", NULL }, + { "GetIfTable", NULL }, + { "GetIfEntry", NULL }, + { "GetNumberOfInterfaces", NULL }, + { "GetTcpTable", NULL }, + { "GetUdpTable", NULL }, + { "AllocateAndGetTcpExTableFromStack", NULL }, + { "AllocateAndGetUdpExTableFromStack", NULL }, + { "GetTcpStatistics", NULL }, + { "GetNetworkParams", NULL }, + { "GetAdaptersInfo", NULL }, + { "GetAdaptersAddresses", NULL }, + { "GetIpNetTable", NULL }, + { NULL, NULL } +}; + +static sigar_advapi_t sigar_advapi = { + "advapi32.dll", + NULL, + { "ConvertStringSidToSidA", NULL }, + { "QueryServiceStatusEx", NULL }, + { NULL, NULL } +}; + +static sigar_ntdll_t sigar_ntdll = { + "ntdll.dll", + NULL, + { "NtQuerySystemInformation", NULL }, + { "NtQueryInformationProcess", NULL }, + { NULL, NULL } +}; + +static sigar_psapi_t sigar_psapi = { + "psapi.dll", + NULL, + { "EnumProcessModules", NULL }, + { "EnumProcesses", NULL }, + { "GetModuleFileNameExA", NULL }, + { NULL, NULL } +}; + +static sigar_psapi_t sigar_winsta = { + "winsta.dll", + NULL, + { "WinStationQueryInformationW", NULL }, + { NULL, NULL } +}; + +static sigar_psapi_t sigar_kernel = { + "kernel32.dll", + NULL, + { "GlobalMemoryStatusEx", NULL }, + { NULL, NULL } +}; + +static sigar_mpr_t sigar_mpr = { + "mpr.dll", + NULL, + { "WNetGetConnectionA", NULL }, + { NULL, NULL } +}; + +#define DLLMOD_COPY(name) \ + memcpy(&(sigar->name), &sigar_##name, sizeof(sigar_##name)) + +#define DLLMOD_INIT(name, all) \ + sigar_dllmod_init(sigar, (sigar_dll_module_t *)&(sigar->name), all) + +#define DLLMOD_FREE(name) \ + sigar_dllmod_free((sigar_dll_module_t *)&(sigar->name)) + +static void sigar_dllmod_free(sigar_dll_module_t *module) +{ + if (module->handle) { + FreeLibrary(module->handle); + module->handle = NULL; + } +} + +static int sigar_dllmod_init(sigar_t *sigar, + sigar_dll_module_t *module, + int all) +{ + sigar_dll_func_t *funcs = &module->funcs[0]; + int is_debug = SIGAR_LOG_IS_DEBUG(sigar); + int rc, success; + + if (module->handle == INVALID_HANDLE_VALUE) { + return ENOENT; /* XXX better rc */ + } + + if (module->handle) { + return SIGAR_OK; + } + + module->handle = LoadLibrary(module->name); + if (!(success = (module->handle ? TRUE : FALSE))) { + rc = GetLastError(); + /* dont try again */ + module->handle = INVALID_HANDLE_VALUE; + } + + if (is_debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "LoadLibrary(%s): %s", + module->name, + success ? + "OK" : + sigar_strerror(sigar, rc)); + } + + if (!success) { + return rc; + } + + while (funcs->name) { + funcs->func = GetProcAddress(module->handle, funcs->name); + + if (!(success = (funcs->func ? TRUE : FALSE))) { + rc = GetLastError(); + } + + if (is_debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "GetProcAddress(%s:%s): %s", + module->name, funcs->name, + success ? + "OK" : + sigar_strerror(sigar, rc)); + } + + if (all && !success) { + return rc; + } + + funcs++; + } + + return SIGAR_OK; +} + +int sigar_wsa_init(sigar_t *sigar) +{ + if (sigar->ws_version == 0) { + WSADATA data; + + if (WSAStartup(MAKEWORD(2, 0), &data)) { + sigar->ws_error = WSAGetLastError(); + WSACleanup(); + return sigar->ws_error; + } + + sigar->ws_version = data.wVersion; + } + + return SIGAR_OK; +} + +static int sigar_enable_privilege(char *name) +{ + int status; + HANDLE handle; + TOKEN_PRIVILEGES tok; + + SIGAR_ZERO(&tok); + + if (!OpenProcessToken(GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, + &handle)) + { + return GetLastError(); + } + + if (LookupPrivilegeValue(NULL, name, + &tok.Privileges[0].Luid)) + { + tok.PrivilegeCount = 1; + tok.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (AdjustTokenPrivileges(handle, FALSE, &tok, 0, NULL, 0)) { + status = SIGAR_OK; + } + else { + status = GetLastError(); + } + } + else { + status = GetLastError(); + } + + CloseHandle(handle); + + return status; +} + +static int netif_name_short(void) +{ + char value[32767]; /* max size from msdn docs */ + DWORD retval = + GetEnvironmentVariable("SIGAR_NETIF_NAME_SHORT", value, sizeof(value)); + if ((retval > 0) && (strEQ(value, "1") || (strEQ(value, "true")))) { + return 1; + } + else { + return 0; + } +} + +int sigar_os_open(sigar_t **sigar_ptr) +{ + LONG result; + HINSTANCE h; + OSVERSIONINFO version; + int i; + sigar_t *sigar; + + *sigar_ptr = sigar = malloc(sizeof(*sigar)); + sigar->machine = ""; /* local machine */ + sigar->using_wide = 0; /*XXX*/ + + sigar->perfbuf = NULL; + sigar->perfbuf_size = 0; + + version.dwOSVersionInfoSize = sizeof(version); + GetVersionEx(&version); + + /* + * 4 == NT 4.0 + * 5 == 2000, XP, 2003 Server + */ + sigar->winnt = (version.dwMajorVersion == 4); + + if (USING_WIDE_S(sigar)) { + WCHAR wmachine[MAX_PATH+1]; + + SIGAR_A2W(sigar->machine, wmachine, sizeof(wmachine)); + + result = RegConnectRegistryW(wmachine, + HKEY_PERFORMANCE_DATA, + &sigar->handle); + } + else { + result = RegConnectRegistryA(sigar->machine, + HKEY_PERFORMANCE_DATA, + &sigar->handle); + } + + get_sysinfo(sigar); + + DLLMOD_COPY(wtsapi); + DLLMOD_COPY(iphlpapi); + DLLMOD_COPY(advapi); + DLLMOD_COPY(ntdll); + DLLMOD_COPY(psapi); + DLLMOD_COPY(winsta); + DLLMOD_COPY(kernel); + DLLMOD_COPY(mpr); + + sigar->log_level = -1; /* else below segfaults */ + /* XXX init early for use by javasigar.c */ + sigar_dllmod_init(sigar, + (sigar_dll_module_t *)&sigar->advapi, + FALSE); + + sigar->netif_mib_rows = NULL; + sigar->netif_addr_rows = NULL; + sigar->netif_adapters = NULL; + sigar->netif_names = NULL; + sigar->netif_name_short = netif_name_short(); + + sigar->pinfo.pid = -1; + sigar->ws_version = 0; + sigar->lcpu = -1; + + /* increase process visibility */ + sigar_enable_privilege(SE_DEBUG_NAME); + + return result; +} + +void dllmod_init_ntdll(sigar_t *sigar) +{ + DLLMOD_INIT(ntdll, FALSE); +} + +int sigar_os_close(sigar_t *sigar) +{ + int retval; + + DLLMOD_FREE(wtsapi); + DLLMOD_FREE(iphlpapi); + DLLMOD_FREE(advapi); + DLLMOD_FREE(ntdll); + DLLMOD_FREE(psapi); + DLLMOD_FREE(winsta); + DLLMOD_FREE(kernel); + DLLMOD_FREE(mpr); + + if (sigar->perfbuf) { + free(sigar->perfbuf); + } + + retval = RegCloseKey(sigar->handle); + + if (sigar->ws_version != 0) { + WSACleanup(); + } + + if (sigar->netif_mib_rows) { + sigar_cache_destroy(sigar->netif_mib_rows); + } + + if (sigar->netif_addr_rows) { + sigar_cache_destroy(sigar->netif_addr_rows); + } + + if (sigar->netif_adapters) { + sigar_cache_destroy(sigar->netif_adapters); + } + + if (sigar->netif_names) { + sigar_cache_destroy(sigar->netif_names); + } + + free(sigar); + + return retval; +} + +char *sigar_os_error_string(sigar_t *sigar, int err) +{ + switch (err) { + case SIGAR_NO_SUCH_PROCESS: + return "No such process"; + break; + } + return NULL; +} + +#define sigar_GlobalMemoryStatusEx \ + sigar->kernel.memory_status.func + +SIGAR_DECLARE(int) sigar_mem_get(sigar_t *sigar, sigar_mem_t *mem) +{ + DLLMOD_INIT(kernel, TRUE); + + if (sigar_GlobalMemoryStatusEx) { + MEMORYSTATUSEX memstat; + + memstat.dwLength = sizeof(memstat); + + if (!sigar_GlobalMemoryStatusEx(&memstat)) { + return GetLastError(); + } + + mem->total = memstat.ullTotalPhys; + mem->free = memstat.ullAvailPhys; + } + else { + MEMORYSTATUS memstat; + GlobalMemoryStatus(&memstat); + mem->total = memstat.dwTotalPhys; + mem->free = memstat.dwAvailPhys; + } + + mem->used = mem->total - mem->free; + + mem->actual_free = mem->free; + mem->actual_used = mem->used; + /* set actual_{free,used} */ + get_mem_counters(sigar, NULL, mem); + + sigar_mem_calc_ram(sigar, mem); + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_swap_get(sigar_t *sigar, sigar_swap_t *swap) +{ + int status; + DLLMOD_INIT(kernel, TRUE); + + if (sigar_GlobalMemoryStatusEx) { + MEMORYSTATUSEX memstat; + + memstat.dwLength = sizeof(memstat); + + if (!sigar_GlobalMemoryStatusEx(&memstat)) { + return GetLastError(); + } + + swap->total = memstat.ullTotalPageFile; + swap->free = memstat.ullAvailPageFile; + } + else { + MEMORYSTATUS memstat; + GlobalMemoryStatus(&memstat); + swap->total = memstat.dwTotalPageFile; + swap->free = memstat.dwAvailPageFile; + } + + swap->used = swap->total - swap->free; + + if (get_mem_counters(sigar, swap, NULL) != SIGAR_OK) { + swap->page_in = SIGAR_FIELD_NOTIMPL; + swap->page_out = SIGAR_FIELD_NOTIMPL; + } + + return SIGAR_OK; +} + +static PERF_INSTANCE_DEFINITION *get_cpu_instance(sigar_t *sigar, + DWORD *perf_offsets, + DWORD *num, DWORD *err) +{ + PERF_OBJECT_TYPE *object = get_perf_object(sigar, PERF_TITLE_CPU_KEY, err); + PERF_INSTANCE_DEFINITION *inst; + PERF_COUNTER_DEFINITION *counter; + DWORD i; + + if (!object) { + return NULL; + } + + for (i=0, counter = PdhFirstCounter(object); + iNumCounters; + i++, counter = PdhNextCounter(counter)) + { + DWORD offset = counter->CounterOffset; + + switch (counter->CounterNameTitleIndex) { + case PERF_TITLE_CPU_SYS: + perf_offsets[PERF_IX_CPU_SYS] = offset; + break; + case PERF_TITLE_CPU_USER: + perf_offsets[PERF_IX_CPU_USER] = offset; + break; + case PERF_TITLE_CPU_IDLE: + perf_offsets[PERF_IX_CPU_IDLE] = offset; + break; + case PERF_TITLE_CPU_IRQ: + perf_offsets[PERF_IX_CPU_IRQ] = offset; + break; + } + } + + if (num) { + *num = object->NumInstances; + } + + return PdhFirstInstance(object); +} + +#define SPPI_MAX 128 /* XXX unhardcode; should move off this api anyhow */ + +#define sigar_NtQuerySystemInformation \ + sigar->ntdll.query_sys_info.func + +static int get_idle_cpu(sigar_t *sigar, sigar_cpu_t *cpu, + DWORD idx, + PERF_COUNTER_BLOCK *counter_block, + DWORD *perf_offsets) +{ + cpu->idle = 0; + + if (perf_offsets[PERF_IX_CPU_IDLE]) { + cpu->idle = PERF_VAL_CPU(PERF_IX_CPU_IDLE); + } + else { + /* windows NT and 2000 do not have an Idle counter */ + DLLMOD_INIT(ntdll, FALSE); + if (sigar_NtQuerySystemInformation) { + DWORD retval, num; + SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX]; + /* into the lungs of hell */ + sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation, + &info, sizeof(info), &retval); + + if (!retval) { + return GetLastError(); + } + num = retval/sizeof(info[0]); + + if (idx == -1) { + int i; + for (i=0; iidle += NS100_2MSEC(info[i].IdleTime.QuadPart); + } + } + else if (idx < num) { + cpu->idle = NS100_2MSEC(info[idx].IdleTime.QuadPart); + } + else { + return ERROR_INVALID_DATA; + } + } + else { + return ERROR_INVALID_FUNCTION; + } + } + + return SIGAR_OK; +} + +static int sigar_cpu_perflib_get(sigar_t *sigar, sigar_cpu_t *cpu) +{ + int status; + PERF_INSTANCE_DEFINITION *inst; + PERF_COUNTER_BLOCK *counter_block; + DWORD perf_offsets[PERF_IX_CPU_MAX], err; + + SIGAR_ZERO(cpu); + memset(&perf_offsets, 0, sizeof(perf_offsets)); + + inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, 0, &err); + + if (!inst) { + return err; + } + + /* first instance is total, rest are per-cpu */ + counter_block = PdhGetCounterBlock(inst); + + cpu->sys = PERF_VAL_CPU(PERF_IX_CPU_SYS); + cpu->user = PERF_VAL_CPU(PERF_IX_CPU_USER); + status = get_idle_cpu(sigar, cpu, -1, counter_block, perf_offsets); + cpu->irq = PERF_VAL_CPU(PERF_IX_CPU_IRQ); + cpu->nice = 0; /* no nice here */ + cpu->wait = 0; /*N/A?*/ + cpu->total = cpu->sys + cpu->user + cpu->idle + cpu->wait + cpu->irq; + + if (status != SIGAR_OK) { + sigar_log_printf(sigar, SIGAR_LOG_WARN, + "unable to determine idle cpu time: %s", + sigar_strerror(sigar, status)); + } + + return SIGAR_OK; +} + +static int sigar_cpu_ntsys_get(sigar_t *sigar, sigar_cpu_t *cpu) +{ + DWORD retval, num; + int i; + SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX]; + /* into the lungs of hell */ + sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation, + &info, sizeof(info), &retval); + + if (!retval) { + return GetLastError(); + } + num = retval/sizeof(info[0]); + SIGAR_ZERO(cpu); + + for (i=0; iidle += NS100_2MSEC(info[i].IdleTime.QuadPart); + cpu->user += NS100_2MSEC(info[i].UserTime.QuadPart); + cpu->sys += NS100_2MSEC(info[i].KernelTime.QuadPart - + info[i].IdleTime.QuadPart); + cpu->irq += NS100_2MSEC(info[i].InterruptTime.QuadPart); + cpu->total += cpu->idle + cpu->user + cpu->sys; + } + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_cpu_get(sigar_t *sigar, sigar_cpu_t *cpu) +{ + DLLMOD_INIT(ntdll, FALSE); + if (sigar_NtQuerySystemInformation) { + return sigar_cpu_ntsys_get(sigar, cpu); + } + else { + return sigar_cpu_perflib_get(sigar, cpu); + } +} + +static int sigar_cpu_list_perflib_get(sigar_t *sigar, + sigar_cpu_list_t *cpulist) +{ + int status, i, j; + PERF_INSTANCE_DEFINITION *inst; + DWORD perf_offsets[PERF_IX_CPU_MAX], num, err; + int core_rollup = sigar_cpu_core_rollup(sigar); + + memset(&perf_offsets, 0, sizeof(perf_offsets)); + + /* first instance is total, rest are per-cpu */ + inst = get_cpu_instance(sigar, (DWORD*)&perf_offsets, &num, &err); + + if (!inst) { + return err; + } + + if (!sigar->winnt) { + /* skip Processor _Total instance (NT doesnt have one) */ + --num; + inst = PdhNextInstance(inst); + } + + sigar_cpu_list_create(cpulist); + + /* verify there's a counter for each logical cpu */ + if (core_rollup && (sigar->ncpu != num)) { + core_rollup = 0; + } + + for (i=0; ilcpu)) { + /* merge times of logical processors */ + cpu = &cpulist->data[cpulist->number-1]; + } + else { + SIGAR_CPU_LIST_GROW(cpulist); + cpu = &cpulist->data[cpulist->number++]; + SIGAR_ZERO(cpu); + } + + counter_block = PdhGetCounterBlock(inst); + + cpu->sys += PERF_VAL_CPU(PERF_IX_CPU_SYS); + cpu->user += PERF_VAL_CPU(PERF_IX_CPU_USER); + cpu->irq += PERF_VAL_CPU(PERF_IX_CPU_IRQ); + get_idle_cpu(sigar, cpu, i, counter_block, perf_offsets); + cpu->nice = cpu->wait = 0; /*N/A*/ + + /*XXX adding up too much here if xeon, but not using this atm*/ + cpu->total += cpu->sys + cpu->user + cpu->idle + cpu->irq; + + inst = PdhNextInstance(inst); + } + + return SIGAR_OK; +} + +static int sigar_cpu_list_ntsys_get(sigar_t *sigar, + sigar_cpu_list_t *cpulist) +{ + DWORD retval, num; + int status, i, j; + int core_rollup = sigar_cpu_core_rollup(sigar); + + SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION info[SPPI_MAX]; + /* into the lungs of hell */ + sigar_NtQuerySystemInformation(SystemProcessorPerformanceInformation, + &info, sizeof(info), &retval); + + if (!retval) { + return GetLastError(); + } + num = retval/sizeof(info[0]); + + sigar_cpu_list_create(cpulist); + + /* verify there's a counter for each logical cpu */ + if (core_rollup && (sigar->ncpu != num)) { + core_rollup = 0; + } + + for (i=0; ilcpu)) { + /* merge times of logical processors */ + cpu = &cpulist->data[cpulist->number-1]; + } + else { + SIGAR_CPU_LIST_GROW(cpulist); + cpu = &cpulist->data[cpulist->number++]; + SIGAR_ZERO(cpu); + } + + idle = NS100_2MSEC(info[i].IdleTime.QuadPart); + user = NS100_2MSEC(info[i].UserTime.QuadPart); + sys = NS100_2MSEC(info[i].KernelTime.QuadPart - + info[i].IdleTime.QuadPart); + cpu->idle += idle; + cpu->user += user; + cpu->sys += sys; + cpu->nice = cpu->wait = 0; /*N/A*/ + cpu->total += idle + user + sys; + } + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_cpu_list_get(sigar_t *sigar, + sigar_cpu_list_t *cpulist) +{ + DLLMOD_INIT(ntdll, FALSE); + if (sigar_NtQuerySystemInformation) { + return sigar_cpu_list_ntsys_get(sigar, cpulist); + } + else { + return sigar_cpu_list_perflib_get(sigar, cpulist); + } +} + +#define PERF_TITLE_UPTIME_KEY 674 /* System Up Time */ + +SIGAR_DECLARE(int) sigar_uptime_get(sigar_t *sigar, + sigar_uptime_t *uptime) +{ + int status; + PERF_OBJECT_TYPE *object = + get_perf_object_inst(sigar, PERF_TITLE_SYS_KEY, 0, &status); + PERF_INSTANCE_DEFINITION *inst; + PERF_COUNTER_DEFINITION *counter; + BYTE *data; + DWORD i; + + if (!object) { + return status; + } + + data = (BYTE *)((BYTE *)object + object->DefinitionLength); + + for (i=0, counter = PdhFirstCounter(object); + iNumCounters; + i++, counter = PdhNextCounter(counter)) + { + if (counter->CounterNameTitleIndex == PERF_TITLE_UPTIME_KEY) { + DWORD offset = counter->CounterOffset; + LONGLONG time = object->PerfTime.QuadPart; + LONGLONG freq = object->PerfFreq.QuadPart; + LONGLONG counter = *((LONGLONG *)(data + offset)); + uptime->uptime = (time - counter) / freq; + return SIGAR_OK; + } + } + + /* http://msdn.microsoft.com/en-us/library/ms724408.aspx */ + return GetTickCount() / 1000; +} + +/* + * there is no api for this info. + * closest i've seen is enumerating the entire process table + * and calculating an average based on process times. + */ +SIGAR_DECLARE(int) sigar_loadavg_get(sigar_t *sigar, + sigar_loadavg_t *loadavg) +{ + return SIGAR_ENOTIMPL; +} + +#define get_process_object(sigar, err) \ + get_perf_object(sigar, PERF_TITLE_PROC_KEY, err) + +static int sigar_proc_list_get_perf(sigar_t *sigar, + sigar_proc_list_t *proclist) +{ + + PERF_OBJECT_TYPE *object; + PERF_INSTANCE_DEFINITION *inst; + PERF_COUNTER_DEFINITION *counter; + DWORD i, err; + DWORD perf_offsets[PERF_IX_MAX]; + + perf_offsets[PERF_IX_PID] = 0; + + object = get_process_object(sigar, &err); + + if (!object) { + return err; + } + + /* + * note we assume here: + * block->NumObjectTypes == 1 + * object->ObjectNameTitleIndex == PERF_TITLE_PROC + * + * which should always be the case. + */ + + for (i=0, counter = PdhFirstCounter(object); + iNumCounters; + i++, counter = PdhNextCounter(counter)) + { + DWORD offset = counter->CounterOffset; + + switch (counter->CounterNameTitleIndex) { + case PERF_TITLE_PID: + perf_offsets[PERF_IX_PID] = offset; + break; + } + } + + for (i=0, inst = PdhFirstInstance(object); + iNumInstances; + i++, inst = PdhNextInstance(inst)) + { + PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst); + DWORD pid = PERF_VAL(PERF_IX_PID); + + if (pid == 0) { + continue; /* dont include the system Idle process */ + } + + SIGAR_PROC_LIST_GROW(proclist); + + proclist->data[proclist->number++] = pid; + } + + return SIGAR_OK; +} + +#define sigar_EnumProcesses \ + sigar->psapi.enum_processes.func + +int sigar_os_proc_list_get(sigar_t *sigar, + sigar_proc_list_t *proclist) +{ + DLLMOD_INIT(psapi, FALSE); + + if (sigar_EnumProcesses) { + DWORD retval, *pids; + DWORD size = 0, i; + + do { + /* re-use the perfbuf */ + if (size == 0) { + size = perfbuf_init(sigar); + } + else { + size = perfbuf_grow(sigar); + } + + if (!sigar_EnumProcesses((DWORD *)sigar->perfbuf, + sigar->perfbuf_size, + &retval)) + { + return GetLastError(); + } + } while (retval == sigar->perfbuf_size); //unlikely + + pids = (DWORD *)sigar->perfbuf; + + size = retval / sizeof(DWORD); + + for (i=0; idata[proclist->number++] = pid; + } + + return SIGAR_OK; + } + else { + return sigar_proc_list_get_perf(sigar, proclist); + } +} + +#define PROCESS_DAC (PROCESS_QUERY_INFORMATION|PROCESS_VM_READ) + +static HANDLE open_process(sigar_pid_t pid) +{ + return OpenProcess(PROCESS_DAC, 0, (DWORD)pid); +} + +/* + * Pretty good explanation of counters: + * http://www.semack.net/wiki/default.asp?db=SemackNetWiki&o=VirtualMemory + */ +SIGAR_DECLARE(int) sigar_proc_mem_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_mem_t *procmem) +{ + int status = get_proc_info(sigar, pid); + sigar_win32_pinfo_t *pinfo = &sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + + procmem->size = pinfo->size; /* "Virtual Bytes" */ + procmem->resident = pinfo->resident; /* "Working Set" */ + procmem->share = SIGAR_FIELD_NOTIMPL; + procmem->page_faults = pinfo->page_faults; + procmem->minor_faults = SIGAR_FIELD_NOTIMPL; + procmem->major_faults = SIGAR_FIELD_NOTIMPL; + + return SIGAR_OK; +} + +#define TOKEN_DAC (STANDARD_RIGHTS_READ | READ_CONTROL | TOKEN_QUERY) + +SIGAR_DECLARE(int) +sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_cred_name_t *proccredname) +{ + HANDLE proc, token; + DWORD len; + int success; + TOKEN_USER *user = NULL; + TOKEN_PRIMARY_GROUP *group = NULL; + SID_NAME_USE type; + char domain[SIGAR_CRED_NAME_MAX]; + + /* XXX cache lookup */ + + if (!(proc = open_process(pid))) { + return GetLastError(); + } + + if (!OpenProcessToken(proc, TOKEN_DAC, &token)) { + CloseHandle(proc); + return GetLastError(); + } + + CloseHandle(proc); + + success = + !GetTokenInformation(token, TokenUser, NULL, 0, &len) && + (GetLastError() == ERROR_INSUFFICIENT_BUFFER) && + (user = malloc(len)) && + GetTokenInformation(token, TokenUser, user, len, &len); + + if (success) { + DWORD domain_len = sizeof(domain); + DWORD user_len = sizeof(proccredname->user); + + success = LookupAccountSid(NULL, user->User.Sid, + proccredname->user, &user_len, + domain, &domain_len, &type); + } + + if (user != NULL) { + free(user); + } + if (!success) { + CloseHandle(token); + return GetLastError(); + } + + success = + !GetTokenInformation(token, TokenPrimaryGroup, NULL, 0, &len) && + (GetLastError() == ERROR_INSUFFICIENT_BUFFER) && + (group = malloc(len)) && + GetTokenInformation(token, TokenPrimaryGroup, group, len, &len); + + if (success) { + DWORD domain_len = sizeof(domain); + DWORD group_len = sizeof(proccredname->group); + + success = LookupAccountSid(NULL, group->PrimaryGroup, + proccredname->group, &group_len, + domain, &domain_len, &type); + } + + if (group != NULL) { + free(group); + } + + CloseHandle(token); + + if (!success) { + return GetLastError(); + } + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_proc_cred_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_cred_t *proccred) +{ + return SIGAR_ENOTIMPL; +} + +#define FILETIME2MSEC(ft) \ + NS100_2MSEC(((ft.dwHighDateTime << 32) | ft.dwLowDateTime)) + +sigar_int64_t sigar_time_now_millis(void) +{ + SYSTEMTIME st; + FILETIME time; + + GetSystemTime(&st); + SystemTimeToFileTime(&st, &time); + + return sigar_FileTimeToTime(&time) / 1000; +} + +SIGAR_DECLARE(int) sigar_proc_time_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_time_t *proctime) +{ + HANDLE proc = open_process(pid); + FILETIME start_time, exit_time, system_time, user_time; + int status = ERROR_SUCCESS; + + if (!proc) { + return GetLastError(); + } + + if (!GetProcessTimes(proc, + &start_time, &exit_time, + &system_time, &user_time)) + { + status = GetLastError(); + } + + CloseHandle(proc); + + if (status != ERROR_SUCCESS) { + return status; + } + + if (start_time.dwHighDateTime) { + proctime->start_time = + sigar_FileTimeToTime(&start_time) / 1000; + } + else { + proctime->start_time = 0; + } + + proctime->user = FILETIME2MSEC(user_time); + proctime->sys = FILETIME2MSEC(system_time); + proctime->total = proctime->user + proctime->sys; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_proc_state_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_state_t *procstate) +{ + int status = get_proc_info(sigar, pid); + sigar_win32_pinfo_t *pinfo = &sigar->pinfo; + + if (status != SIGAR_OK) { + return status; + } + + memcpy(procstate->name, pinfo->name, sizeof(procstate->name)); + procstate->state = pinfo->state; + procstate->ppid = pinfo->ppid; + procstate->priority = pinfo->priority; + procstate->nice = SIGAR_FIELD_NOTIMPL; + procstate->tty = SIGAR_FIELD_NOTIMPL; + procstate->threads = pinfo->threads; + procstate->processor = SIGAR_FIELD_NOTIMPL; + + return SIGAR_OK; +} + +static int get_proc_info(sigar_t *sigar, sigar_pid_t pid) +{ + PERF_OBJECT_TYPE *object; + PERF_INSTANCE_DEFINITION *inst; + PERF_COUNTER_DEFINITION *counter; + DWORD i, err; + DWORD perf_offsets[PERF_IX_MAX]; + sigar_win32_pinfo_t *pinfo = &sigar->pinfo; + time_t timenow = time(NULL); + + if (pinfo->pid == pid) { + if ((timenow - pinfo->mtime) < SIGAR_LAST_PROC_EXPIRE) { + return SIGAR_OK; + } + } + + memset(&perf_offsets, 0, sizeof(perf_offsets)); + + object = get_process_object(sigar, &err); + + if (object == NULL) { + return err; + } + + pinfo->pid = pid; + pinfo->mtime = timenow; + + /* + * note we assume here: + * block->NumObjectTypes == 1 + * object->ObjectNameTitleIndex == PERF_TITLE_PROC + * + * which should always be the case. + */ + + for (i=0, counter = PdhFirstCounter(object); + iNumCounters; + i++, counter = PdhNextCounter(counter)) + { + DWORD offset = counter->CounterOffset; + + switch (counter->CounterNameTitleIndex) { + case PERF_TITLE_CPUTIME: + perf_offsets[PERF_IX_CPUTIME] = offset; + break; + case PERF_TITLE_PAGE_FAULTS: + perf_offsets[PERF_IX_PAGE_FAULTS] = offset; + break; + case PERF_TITLE_MEM_VSIZE: + perf_offsets[PERF_IX_MEM_VSIZE] = offset; + break; + case PERF_TITLE_MEM_SIZE: + perf_offsets[PERF_IX_MEM_SIZE] = offset; + break; + case PERF_TITLE_THREAD_CNT: + perf_offsets[PERF_IX_THREAD_CNT] = offset; + break; + case PERF_TITLE_HANDLE_CNT: + perf_offsets[PERF_IX_HANDLE_CNT] = offset; + break; + case PERF_TITLE_PID: + perf_offsets[PERF_IX_PID] = offset; + break; + case PERF_TITLE_PPID: + perf_offsets[PERF_IX_PPID] = offset; + break; + case PERF_TITLE_PRIORITY: + perf_offsets[PERF_IX_PRIORITY] = offset; + break; + case PERF_TITLE_START_TIME: + perf_offsets[PERF_IX_START_TIME] = offset; + break; + } + } + + for (i=0, inst = PdhFirstInstance(object); + iNumInstances; + i++, inst = PdhNextInstance(inst)) + { + PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst); + sigar_pid_t this_pid = PERF_VAL(PERF_IX_PID); + + if (this_pid != pid) { + continue; + } + + pinfo->state = 'R'; /* XXX? */ + SIGAR_W2A(PdhInstanceName(inst), + pinfo->name, sizeof(pinfo->name)); + + pinfo->size = PERF_VAL(PERF_IX_MEM_VSIZE); + pinfo->resident = PERF_VAL(PERF_IX_MEM_SIZE); + pinfo->ppid = PERF_VAL(PERF_IX_PPID); + pinfo->priority = PERF_VAL(PERF_IX_PRIORITY); + pinfo->handles = PERF_VAL(PERF_IX_HANDLE_CNT); + pinfo->threads = PERF_VAL(PERF_IX_THREAD_CNT); + pinfo->page_faults = PERF_VAL(PERF_IX_PAGE_FAULTS); + + return SIGAR_OK; + } + + return SIGAR_NO_SUCH_PROCESS; +} + +static int sigar_remote_proc_args_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs) +{ + int status; + char cmdline[SIGAR_CMDLINE_MAX], *ptr = cmdline, *arg; + HANDLE proc = open_process(pid); + + if (proc) { + status = sigar_proc_args_peb_get(sigar, proc, procargs); + + CloseHandle(proc); + + if (status == SIGAR_OK) { + return status; + } + } + + /* likely we are 32-bit, pid process is 64-bit */ +#ifdef MSVC + status = sigar_proc_args_wmi_get(sigar, pid, procargs); +#endif + if (status == ERROR_NOT_FOUND) { + status = SIGAR_NO_SUCH_PROCESS; + } + return status; +} + +int sigar_os_proc_args_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs) +{ + if (pid == sigar->pid) { + return sigar_parse_proc_args(sigar, NULL, procargs); + } + else { + return sigar_remote_proc_args_get(sigar, pid, procargs); + } +} + +static int sigar_proc_env_parse(UCHAR *ptr, sigar_proc_env_t *procenv, + int multi) +{ + while (*ptr) { + char *val; + int klen, vlen, status; + char key[128]; /* XXX is there a max key size? */ + + if (*ptr == '=') { + ptr += strlen(ptr)+1; + continue; + } + + val = strchr(ptr, '='); + + if (val == NULL) { + break; /*XXX*/ + } + + klen = val - (char*)ptr; + SIGAR_SSTRCPY(key, ptr); + key[klen] = '\0'; + ++val; + + vlen = strlen(val); + + status = procenv->env_getter(procenv->data, + key, klen, val, vlen); + + if (status != SIGAR_OK) { + /* not an error; just stop iterating */ + return status; + } + + if (!multi) { + break; /* caller only provided 1 key=val pair */ + } + + ptr += klen + 1 + vlen + 1; + } + + return SIGAR_OK; +} + +static int sigar_local_proc_env_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_env_t *procenv) +{ + UCHAR *env = (UCHAR*)GetEnvironmentStrings(); + + sigar_proc_env_parse(env, procenv, TRUE); + + FreeEnvironmentStrings(env); + + return SIGAR_OK; +} + +static int sigar_remote_proc_env_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_env_t *procenv) +{ + int status; + HANDLE proc = open_process(pid); + WCHAR env[4096]; + + if (!proc) { + return GetLastError(); + } + + status = sigar_proc_env_peb_get(sigar, proc, env, sizeof(env)); + + CloseHandle(proc); + + if (status == SIGAR_OK) { + LPBYTE ptr = (LPBYTE)env; + DWORD size = sizeof(env); + UCHAR ent[4096]; + + while ((size > 0) && (*ptr != L'\0')) { + DWORD len = (wcslen((LPWSTR)ptr) + 1) * sizeof(WCHAR); + /* multi=FALSE so no need to: memset(ent, '\0', sizeof(ent)) */ + SIGAR_W2A((WCHAR *)ptr, ent, sizeof(ent)); + if (sigar_proc_env_parse(ent, procenv, FALSE) != SIGAR_OK) { + break; + } + size -= len; + ptr += len; + } + } + + return status; +} + +SIGAR_DECLARE(int) sigar_proc_env_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_env_t *procenv) +{ + if (pid == sigar->pid) { + if (procenv->type == SIGAR_PROC_ENV_KEY) { + char value[32767]; /* max size from msdn docs */ + DWORD retval = + GetEnvironmentVariable(procenv->key, value, sizeof(value)); + + if (retval == 0) { + if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) { + return SIGAR_OK; + } + return GetLastError(); + } + else if (retval > sizeof(value)) { + /* XXX shouldnt happen */ + return GetLastError(); + } + + procenv->env_getter(procenv->data, + procenv->key, procenv->klen, + value, retval); + return SIGAR_OK; + } + else { + return sigar_local_proc_env_get(sigar, pid, procenv); + } + } + else { + return sigar_remote_proc_env_get(sigar, pid, procenv); + } +} + +SIGAR_DECLARE(int) sigar_proc_fd_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_fd_t *procfd) +{ + int status; + sigar_win32_pinfo_t *pinfo = &sigar->pinfo; + + pinfo->pid = -1; /* force update */ + if ((status = get_proc_info(sigar, pid)) != SIGAR_OK) { + return status; + } + + procfd->total = pinfo->handles; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_proc_exe_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_exe_t *procexe) +{ + int status = SIGAR_OK; + HANDLE proc = open_process(pid); + + if (!proc) { + return GetLastError(); + } + + status = sigar_proc_exe_peb_get(sigar, proc, procexe); +#ifdef MSVC + if (procexe->name[0] == '\0') { + /* likely we are 32-bit, pid process is 64-bit */ + /* procexe->cwd[0] = XXX where else can we try? */ + status = sigar_proc_exe_wmi_get(sigar, pid, procexe); + if (status == ERROR_NOT_FOUND) { + status = SIGAR_NO_SUCH_PROCESS; + } + } +#endif + if (procexe->cwd[0] != '\0') { + /* strip trailing '\' */ + int len = strlen(procexe->cwd); + if (procexe->cwd[len-1] == '\\') { + procexe->cwd[len-1] = '\0'; + } + /* uppercase driver letter */ + procexe->cwd[0] = toupper(procexe->cwd[0]); + /* e.g. C:\ */ + strncpy(procexe->root, procexe->cwd, 3); + procexe->root[3] = '\0'; + } + else { + procexe->root[0] = '\0'; + } + + if (procexe->name[0] != '\0') { + /* uppercase driver letter */ + procexe->name[0] = toupper(procexe->name[0]); + } + + CloseHandle(proc); + + return status; +} + +#define sigar_EnumProcessModules \ + sigar->psapi.enum_modules.func + +#define sigar_GetModuleFileNameEx \ + sigar->psapi.get_module_name.func + +SIGAR_DECLARE(int) sigar_proc_modules_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_modules_t *procmods) +{ + HANDLE proc; + HMODULE modules[1024]; + DWORD size = 0; + unsigned int i; + + if (DLLMOD_INIT(psapi, TRUE) != SIGAR_OK) { + return SIGAR_ENOTIMPL; + } + + if (!(proc = open_process(pid))) { + return GetLastError(); + } + + if (!sigar_EnumProcessModules(proc, modules, sizeof(modules), &size)) { + CloseHandle(proc); + return GetLastError(); + } + + for (i=0; i<(size/sizeof(HMODULE)); i++) { + int status; + char name[MAX_PATH]; + + if (!sigar_GetModuleFileNameEx(proc, modules[i], + name, sizeof(name))) + { + continue; + } + + status = procmods->module_getter(procmods->data, + name, strlen(name)); + + if (status != SIGAR_OK) { + /* not an error; just stop iterating */ + break; + } + } + + CloseHandle(proc); + + return SIGAR_OK; +} + +#define FT2INT64(ft) \ + ((__int64)((__int64)(ft).dwHighDateTime << 32 | \ + (__int64)(ft).dwLowDateTime)) + +SIGAR_DECLARE(int) sigar_thread_cpu_get(sigar_t *sigar, + sigar_uint64_t id, + sigar_thread_cpu_t *cpu) +{ + FILETIME start, exit, sys, user; + DWORD retval; + + if (id != 0) { + return SIGAR_ENOTIMPL; + } + + retval = GetThreadTimes(GetCurrentThread(), + &start, &exit, &sys, &user); + + if (retval == 0) { + return GetLastError(); + } + + cpu->user = FT2INT64(user) * 100; + cpu->sys = FT2INT64(sys) * 100; + cpu->total = (FT2INT64(user) + FT2INT64(sys)) * 100; + + return SIGAR_OK; +} + +int sigar_os_fs_type_get(sigar_file_system_t *fsp) +{ + return fsp->type; +} + +#ifndef FILE_READ_ONLY_VOLUME +#define FILE_READ_ONLY_VOLUME 0x00080000 +#endif +#ifndef FILE_NAMED_STREAMS +#define FILE_NAMED_STREAMS 0x00040000 +#endif +#ifndef FILE_SEQUENTIAL_WRITE_ONCE +#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000 +#endif +#ifndef FILE_SUPPORTS_TRANSACTIONS +#define FILE_SUPPORTS_TRANSACTIONS 0x00200000 +#endif + +static void get_fs_options(char *opts, int osize, long flags) +{ + *opts = '\0'; + if (flags & FILE_READ_ONLY_VOLUME) strncat(opts, "ro", osize); + else strncat(opts, "rw", osize); +#if 0 /*XXX*/ + if (flags & FILE_CASE_PRESERVED_NAMES) strncat(opts, ",casepn", osize); + if (flags & FILE_CASE_SENSITIVE_SEARCH) strncat(opts, ",casess", osize); + if (flags & FILE_FILE_COMPRESSION) strncat(opts, ",fcomp", osize); + if (flags & FILE_NAMED_STREAMS) strncat(opts, ",streams", osize); + if (flags & FILE_PERSISTENT_ACLS) strncat(opts, ",acls", osize); + if (flags & FILE_SEQUENTIAL_WRITE_ONCE) strncat(opts, ",wronce", osize); + if (flags & FILE_SUPPORTS_ENCRYPTION) strncat(opts, ",efs", osize); + if (flags & FILE_SUPPORTS_OBJECT_IDS) strncat(opts, ",oids", osize); + if (flags & FILE_SUPPORTS_REPARSE_POINTS) strncat(opts, ",reparse", osize); + if (flags & FILE_SUPPORTS_SPARSE_FILES) strncat(opts, ",sparse", osize); + if (flags & FILE_SUPPORTS_TRANSACTIONS) strncat(opts, ",trans", osize); + if (flags & FILE_UNICODE_ON_DISK) strncat(opts, ",unicode", osize); + if (flags & FILE_VOLUME_IS_COMPRESSED) strncat(opts, ",vcomp", osize); + if (flags & FILE_VOLUME_QUOTAS) strncat(opts, ",quota", osize); +#endif +} + +#define sigar_WNetGetConnection \ + sigar->mpr.get_net_connection.func + +SIGAR_DECLARE(int) sigar_file_system_list_get(sigar_t *sigar, + sigar_file_system_list_t *fslist) +{ + char name[256]; + char *ptr = name; + /* XXX: hmm, Find{First,Next}Volume not available in my sdk */ + DWORD len = GetLogicalDriveStringsA(sizeof(name), name); + + DLLMOD_INIT(mpr, TRUE); + + if (len == 0) { + return GetLastError(); + } + + sigar_file_system_list_create(fslist); + + while (*ptr) { + sigar_file_system_t *fsp; + DWORD flags, serialnum=0; + char fsname[1024]; + UINT drive_type = GetDriveType(ptr); + int type; + + switch (drive_type) { + case DRIVE_FIXED: + type = SIGAR_FSTYPE_LOCAL_DISK; + break; + case DRIVE_REMOTE: + type = SIGAR_FSTYPE_NETWORK; + break; + case DRIVE_CDROM: + type = SIGAR_FSTYPE_CDROM; + break; + case DRIVE_RAMDISK: + type = SIGAR_FSTYPE_RAM_DISK; + break; + case DRIVE_REMOVABLE: + /* skip floppy, usb, etc. drives */ + ptr += strlen(ptr)+1; + continue; + default: + type = SIGAR_FSTYPE_NONE; + break; + } + + fsname[0] = '\0'; + + GetVolumeInformation(ptr, NULL, 0, &serialnum, NULL, + &flags, fsname, sizeof(fsname)); + + if (!serialnum && (drive_type == DRIVE_FIXED)) { + ptr += strlen(ptr)+1; + continue; /* ignore unformatted partitions */ + } + + SIGAR_FILE_SYSTEM_LIST_GROW(fslist); + + fsp = &fslist->data[fslist->number++]; + + fsp->type = type; + SIGAR_SSTRCPY(fsp->dir_name, ptr); + SIGAR_SSTRCPY(fsp->dev_name, ptr); + + if ((drive_type == DRIVE_REMOTE) && sigar_WNetGetConnection) { + DWORD len = sizeof(fsp->dev_name); + char drive[3] = {'\0', ':', '\0'}; /* e.g. "X:" w/o trailing "\" */ + drive[0] = fsp->dir_name[0]; + sigar_WNetGetConnection(drive, fsp->dev_name, &len); + /* ignoring failure, leaving dev_name as dir_name */ + } + + /* we set fsp->type, just looking up sigar.c:fstype_names[type] */ + sigar_fs_type_get(fsp); + + if (*fsname == '\0') { + SIGAR_SSTRCPY(fsp->sys_type_name, fsp->type_name); + } + else { + SIGAR_SSTRCPY(fsp->sys_type_name, fsname); /* CDFS, NTFS, etc */ + } + + get_fs_options(fsp->options, sizeof(fsp->options)-1, flags); + + ptr += strlen(ptr)+1; + } + + return SIGAR_OK; +} + +static PERF_INSTANCE_DEFINITION *get_disk_instance(sigar_t *sigar, + DWORD *perf_offsets, + DWORD *num, DWORD *err) +{ + PERF_OBJECT_TYPE *object = + get_perf_object(sigar, PERF_TITLE_DISK_KEY, err); + PERF_INSTANCE_DEFINITION *inst; + PERF_COUNTER_DEFINITION *counter; + DWORD i, found=0; + + if (!object) { + return NULL; + } + + for (i=0, counter = PdhFirstCounter(object); + iNumCounters; + i++, counter = PdhNextCounter(counter)) + { + DWORD offset = counter->CounterOffset; + + switch (counter->CounterNameTitleIndex) { + case PERF_TITLE_DISK_TIME: + perf_offsets[PERF_IX_DISK_TIME] = offset; + found = 1; + break; + case PERF_TITLE_DISK_READ_TIME: + perf_offsets[PERF_IX_DISK_READ_TIME] = offset; + found = 1; + break; + case PERF_TITLE_DISK_WRITE_TIME: + perf_offsets[PERF_IX_DISK_WRITE_TIME] = offset; + found = 1; + break; + case PERF_TITLE_DISK_READ: + perf_offsets[PERF_IX_DISK_READ] = offset; + found = 1; + break; + case PERF_TITLE_DISK_WRITE: + perf_offsets[PERF_IX_DISK_WRITE] = offset; + found = 1; + break; + case PERF_TITLE_DISK_READ_BYTES: + perf_offsets[PERF_IX_DISK_READ_BYTES] = offset; + found = 1; + break; + case PERF_TITLE_DISK_WRITE_BYTES: + perf_offsets[PERF_IX_DISK_WRITE_BYTES] = offset; + found = 1; + break; + case PERF_TITLE_DISK_QUEUE: + perf_offsets[PERF_IX_DISK_QUEUE] = offset; + found = 1; + break; + } + } + + if (!found) { + *err = ENOENT; + return NULL; + } + + if (num) { + *num = object->NumInstances; + } + + return PdhFirstInstance(object); +} + +SIGAR_DECLARE(int) sigar_disk_usage_get(sigar_t *sigar, + const char *dirname, + sigar_disk_usage_t *disk) +{ + DWORD i, err; + PERF_OBJECT_TYPE *object = + get_perf_object(sigar, PERF_TITLE_DISK_KEY, &err); + PERF_INSTANCE_DEFINITION *inst; + PERF_COUNTER_DEFINITION *counter; + DWORD perf_offsets[PERF_IX_DISK_MAX]; + + SIGAR_DISK_STATS_INIT(disk); + + if (!object) { + return err; + } + + memset(&perf_offsets, 0, sizeof(perf_offsets)); + inst = get_disk_instance(sigar, (DWORD*)&perf_offsets, 0, &err); + + if (!inst) { + return err; + } + + for (i=0, inst = PdhFirstInstance(object); + iNumInstances; + i++, inst = PdhNextInstance(inst)) + { + char drive[MAX_PATH]; + PERF_COUNTER_BLOCK *counter_block = PdhGetCounterBlock(inst); + wchar_t *name = (wchar_t *)((BYTE *)inst + inst->NameOffset); + + SIGAR_W2A(name, drive, sizeof(drive)); + + if (sigar_isdigit(*name)) { + char *ptr = strchr(drive, ' '); /* 2000 Server "0 C:" */ + + if (ptr) { + ++ptr; + SIGAR_SSTRCPY(drive, ptr); + } + else { + /* XXX NT is a number only "0", how to map? */ + } + } + + if (strnEQ(drive, dirname, 2)) { + disk->time = PERF_VAL(PERF_IX_DISK_TIME); + disk->rtime = PERF_VAL(PERF_IX_DISK_READ_TIME); + disk->wtime = PERF_VAL(PERF_IX_DISK_WRITE_TIME); + disk->reads = PERF_VAL(PERF_IX_DISK_READ); + disk->writes = PERF_VAL(PERF_IX_DISK_WRITE); + disk->read_bytes = PERF_VAL(PERF_IX_DISK_READ_BYTES); + disk->write_bytes = PERF_VAL(PERF_IX_DISK_WRITE_BYTES); + disk->queue = PERF_VAL(PERF_IX_DISK_QUEUE); + return SIGAR_OK; + } + } + + return ENXIO; +} + +SIGAR_DECLARE(int) +sigar_file_system_usage_get(sigar_t *sigar, + const char *dirname, + sigar_file_system_usage_t *fsusage) +{ + BOOL retval; + ULARGE_INTEGER avail, total, free; + int status; + + /* prevent dialog box if A:\ drive is empty */ + UINT errmode = SetErrorMode(SEM_FAILCRITICALERRORS); + + retval = GetDiskFreeSpaceEx(dirname, + &avail, &total, &free); + + /* restore previous error mode */ + SetErrorMode(errmode); + + if (!retval) { + return GetLastError(); + } + + fsusage->total = total.QuadPart / 1024; + fsusage->free = free.QuadPart / 1024; + fsusage->avail = avail.QuadPart / 1024; + fsusage->used = fsusage->total - fsusage->free; + fsusage->use_percent = sigar_file_system_usage_calc_used(sigar, fsusage); + + /* N/A */ + fsusage->files = SIGAR_FIELD_NOTIMPL; + fsusage->free_files = SIGAR_FIELD_NOTIMPL; + + status = sigar_disk_usage_get(sigar, dirname, &fsusage->disk); + + return SIGAR_OK; +} + +static int sigar_cpu_info_get(sigar_t *sigar, sigar_cpu_info_t *info) +{ + HKEY key, cpu; + int i = 0; + char id[MAX_PATH + 1]; + DWORD size = 0, rc; + + RegOpenKey(HKEY_LOCAL_MACHINE, + "HARDWARE\\DESCRIPTION\\System\\CentralProcessor", &key); + + //just lookup the first id, then assume all cpus are the same. + rc = RegEnumKey(key, 0, id, sizeof(id)); + if (rc != ERROR_SUCCESS) { + RegCloseKey(key); + return rc; + } + + rc = RegOpenKey(key, id, &cpu); + if (rc != ERROR_SUCCESS) { + RegCloseKey(key); + return rc; + } + + size = sizeof(info->vendor); + if (RegQueryValueEx(cpu, "VendorIdentifier", NULL, NULL, + (LPVOID)&info->vendor, &size) || + strEQ(info->vendor, "GenuineIntel")) + { + SIGAR_SSTRCPY(info->vendor, "Intel"); + } + else { + if (strEQ(info->vendor, "AuthenticAMD")) { + SIGAR_SSTRCPY(info->vendor, "AMD"); + } + } + + size = sizeof(info->model); + if (RegQueryValueEx(cpu, "ProcessorNameString", NULL, NULL, + (LPVOID)&info->model, &size)) + { + size = sizeof(info->model); + if (RegQueryValueEx(cpu, "Identifier", NULL, NULL, + (LPVOID)&info->model, &size)) + { + SIGAR_SSTRCPY(info->model, "x86"); + } + } + else { + sigar_cpu_model_adjust(sigar, info); + } + + size = sizeof(info->mhz); // == sizeof(DWORD) + if (RegQueryValueEx(cpu, "~MHz", NULL, NULL, + (LPVOID)&info->mhz, &size)) + { + info->mhz = -1; + } + + info->cache_size = -1; //XXX + RegCloseKey(key); + RegCloseKey(cpu); + + info->total_cores = sigar->ncpu; + info->cores_per_socket = sigar->lcpu; + info->total_sockets = sigar_cpu_socket_count(sigar); + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_cpu_info_list_get(sigar_t *sigar, + sigar_cpu_info_list_t *cpu_infos) +{ + int i, status; + sigar_cpu_info_t info; + int core_rollup = sigar_cpu_core_rollup(sigar); + + sigar_cpu_info_list_create(cpu_infos); + + status = sigar_cpu_info_get(sigar, &info); + + if (status != SIGAR_OK) { + return status; + } + + for (i=0; incpu; i++) { + SIGAR_CPU_INFO_LIST_GROW(cpu_infos); + + if (core_rollup && (i % sigar->lcpu)) { + continue; /* fold logical processors */ + } + + memcpy(&cpu_infos->data[cpu_infos->number++], + &info, sizeof(info)); + } + + return SIGAR_OK; +} + +#define sigar_GetNetworkParams \ + sigar->iphlpapi.get_net_params.func + +#define sigar_GetAdaptersInfo \ + sigar->iphlpapi.get_adapters_info.func + +#define sigar_GetAdaptersAddresses \ + sigar->iphlpapi.get_adapters_addrs.func + +#define sigar_GetNumberOfInterfaces \ + sigar->iphlpapi.get_num_if.func + +static sigar_cache_t *sigar_netif_cache_new(sigar_t *sigar) +{ + DWORD num = 0; + + DLLMOD_INIT(iphlpapi, FALSE); + + if (sigar_GetNumberOfInterfaces) { + DWORD rc = sigar_GetNumberOfInterfaces(&num); + + if (rc == NO_ERROR) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "GetNumberOfInterfaces=%d", + num); + } + else { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "GetNumberOfInterfaces failed: %s", + sigar_strerror(sigar, rc)); + } + } + + if (num == 0) { + num = 10; /* reasonable default */ + } + + return sigar_cache_new(num); +} + +static int sigar_get_adapters_info(sigar_t *sigar, + PIP_ADAPTER_INFO *adapter) +{ + ULONG size = sigar->ifconf_len; + DWORD rc; + + DLLMOD_INIT(iphlpapi, FALSE); + + if (!sigar_GetAdaptersInfo) { + return SIGAR_ENOTIMPL; + } + + *adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf; + rc = sigar_GetAdaptersInfo(*adapter, &size); + + if (rc == ERROR_BUFFER_OVERFLOW) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "GetAdaptersInfo " + "realloc ifconf_buf old=%d, new=%d", + sigar->ifconf_len, size); + sigar->ifconf_len = size; + sigar->ifconf_buf = realloc(sigar->ifconf_buf, + sigar->ifconf_len); + + *adapter = (PIP_ADAPTER_INFO)sigar->ifconf_buf; + rc = sigar_GetAdaptersInfo(*adapter, &size); + } + + if (rc != NO_ERROR) { + return rc; + } + else { + return SIGAR_OK; + } +} + +static int sigar_get_adapter_info(sigar_t *sigar, + DWORD index, + IP_ADAPTER_INFO **adapter) +{ + sigar_cache_entry_t *entry; + *adapter = NULL; + + if (sigar->netif_adapters) { + entry = sigar_cache_get(sigar->netif_adapters, index); + if (entry->value) { + *adapter = (IP_ADAPTER_INFO *)entry->value; + } + } + else { + int status; + IP_ADAPTER_INFO *info; + + sigar->netif_adapters = + sigar_netif_cache_new(sigar); + + status = sigar_get_adapters_info(sigar, &info); + if (status != SIGAR_OK) { + return status; + } + + while (info) { + entry = sigar_cache_get(sigar->netif_adapters, + info->Index); + if (!entry->value) { + entry->value = malloc(sizeof(*info)); + } + memcpy(entry->value, info, sizeof(*info)); + if (info->Index == index) { + *adapter = info; + } + + info = info->Next; + } + } + + if (*adapter) { + return SIGAR_OK; + } + else { + return ENOENT; + } +} + +static int sigar_get_adapters_addresses(sigar_t *sigar, + ULONG family, ULONG flags, + PIP_ADAPTER_ADDRESSES *addrs, + ULONG *size) +{ + ULONG rc; + + DLLMOD_INIT(iphlpapi, FALSE); + + if (!sigar_GetAdaptersAddresses) { + return SIGAR_ENOTIMPL; + } + + rc = sigar_GetAdaptersAddresses(family, + flags, + NULL, + *addrs, + size); + + if (rc == ERROR_BUFFER_OVERFLOW) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "GetAdaptersAddresses realloc to %d", size); + + *addrs = realloc(*addrs, *size); + + rc = sigar_GetAdaptersAddresses(family, + flags, + NULL, + (PIP_ADAPTER_ADDRESSES)*addrs, + size); + } + + if (rc != ERROR_SUCCESS) { + return rc; + } + else { + return SIGAR_OK; + } +} + +#define sigar_GetIpAddrTable \ + sigar->iphlpapi.get_ipaddr_table.func + +static int sigar_get_ipaddr_table(sigar_t *sigar, + PMIB_IPADDRTABLE *ipaddr) +{ + ULONG size = sigar->ifconf_len; + DWORD rc; + + DLLMOD_INIT(iphlpapi, FALSE); + + if (!sigar_GetIpAddrTable) { + return SIGAR_ENOTIMPL; + } + + *ipaddr = (PMIB_IPADDRTABLE)sigar->ifconf_buf; + rc = sigar_GetIpAddrTable(*ipaddr, &size, FALSE); + + if (rc == ERROR_INSUFFICIENT_BUFFER) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "GetIpAddrTable " + "realloc ifconf_buf old=%d, new=%d", + sigar->ifconf_len, size); + sigar->ifconf_len = size; + sigar->ifconf_buf = realloc(sigar->ifconf_buf, + sigar->ifconf_len); + + *ipaddr = (PMIB_IPADDRTABLE)sigar->ifconf_buf; + rc = sigar_GetIpAddrTable(*ipaddr, &size, FALSE); + } + + if (rc != NO_ERROR) { + return rc; + } + else { + return SIGAR_OK; + } +} + +#ifndef MIB_IPADDR_PRIMARY +#define MIB_IPADDR_PRIMARY 0x0001 +#endif + +static int sigar_get_netif_ipaddr(sigar_t *sigar, + DWORD index, + MIB_IPADDRROW **ipaddr) +{ + sigar_cache_entry_t *entry; + *ipaddr = NULL; + + if (sigar->netif_addr_rows) { + entry = sigar_cache_get(sigar->netif_addr_rows, index); + if (entry->value) { + *ipaddr = (MIB_IPADDRROW *)entry->value; + } + } + else { + int status, i; + MIB_IPADDRTABLE *mib; + + sigar->netif_addr_rows = + sigar_netif_cache_new(sigar); + + status = sigar_get_ipaddr_table(sigar, &mib); + if (status != SIGAR_OK) { + return status; + } + + for (i=0; idwNumEntries; i++) { + MIB_IPADDRROW *row = &mib->table[i]; + short type; + +#if HAVE_MIB_IPADDRROW_WTYPE + type = row->wType; +#else + type = row->unused2; +#endif + if (!(type & MIB_IPADDR_PRIMARY)) { + continue; + } + + entry = sigar_cache_get(sigar->netif_addr_rows, + row->dwIndex); + if (!entry->value) { + entry->value = malloc(sizeof(*row)); + } + memcpy(entry->value, row, sizeof(*row)); + + if (row->dwIndex == index) { + *ipaddr = row; + } + } + } + + if (*ipaddr) { + return SIGAR_OK; + } + else { + return ENOENT; + } +} + +SIGAR_DECLARE(int) sigar_net_info_get(sigar_t *sigar, + sigar_net_info_t *netinfo) +{ + PIP_ADAPTER_INFO adapter; + FIXED_INFO *info; + ULONG len = 0; + IP_ADDR_STRING *ip; + DWORD rc; + + DLLMOD_INIT(iphlpapi, FALSE); + + if (!sigar_GetNetworkParams) { + return SIGAR_ENOTIMPL; + } + + SIGAR_ZERO(netinfo); + + rc = sigar_GetNetworkParams(NULL, &len); + if (rc != ERROR_BUFFER_OVERFLOW) { + return rc; + } + + info = malloc(len); + rc = sigar_GetNetworkParams(info, &len); + if (rc != NO_ERROR) { + free(info); + return rc; + } + + SIGAR_SSTRCPY(netinfo->host_name, info->HostName); + SIGAR_SSTRCPY(netinfo->domain_name, info->DomainName); + SIGAR_SSTRCPY(netinfo->primary_dns, + info->DnsServerList.IpAddress.String); + + if ((ip = info->DnsServerList.Next)) { + SIGAR_SSTRCPY(netinfo->secondary_dns, + ip->IpAddress.String); + } + + free(info); + + if (sigar_get_adapters_info(sigar, &adapter) != SIGAR_OK) { + return SIGAR_OK; + } + + while (adapter) { + /* should only be 1 */ + if (adapter->GatewayList.IpAddress.String[0]) { + SIGAR_SSTRCPY(netinfo->default_gateway, + adapter->GatewayList.IpAddress.String); + } +#if 0 + if (apapters->DhcpEnabled) { + SIGAR_SSTRCPY(netinfo->dhcp_server, + apdaters->DhcpServer.IpAddress.String); + } +#endif + adapter = adapter->Next; + } + + return SIGAR_OK; +} + +#define sigar_GetIpForwardTable \ + sigar->iphlpapi.get_ipforward_table.func + +SIGAR_DECLARE(int) sigar_net_route_list_get(sigar_t *sigar, + sigar_net_route_list_t *routelist) +{ + PMIB_IPFORWARDTABLE buffer = NULL; + ULONG bufsize = 0; + DWORD rc, i; + MIB_IPFORWARDTABLE *ipt; + sigar_net_route_t *route; + + DLLMOD_INIT(iphlpapi, FALSE); + if (!sigar_GetIpForwardTable) { + return SIGAR_ENOTIMPL; + } + + rc = sigar_GetIpForwardTable(buffer, &bufsize, FALSE); + if (rc != ERROR_INSUFFICIENT_BUFFER) { + return GetLastError(); + } + + buffer = malloc(bufsize); + rc = sigar_GetIpForwardTable(buffer, &bufsize, FALSE); + if (rc != NO_ERROR) { + free(buffer); + return GetLastError(); + } + + if (!sigar->netif_names) { + sigar_net_interface_list_get(sigar, NULL); + } + + sigar_net_route_list_create(routelist); + routelist->size = routelist->number = 0; + + ipt = buffer; + + for (i=0; idwNumEntries; i++) { + MIB_IPFORWARDROW *ipr = ipt->table + i; + sigar_cache_entry_t *entry; + + SIGAR_NET_ROUTE_LIST_GROW(routelist); + + route = &routelist->data[routelist->number++]; + SIGAR_ZERO(route); /* XXX: other fields */ + + sigar_net_address_set(route->destination, + ipr->dwForwardDest); + + sigar_net_address_set(route->mask, + ipr->dwForwardMask); + + sigar_net_address_set(route->gateway, + ipr->dwForwardNextHop); + + route->metric = ipr->dwForwardMetric1; + + route->flags = SIGAR_RTF_UP; + if ((ipr->dwForwardDest == 0) && + (ipr->dwForwardMask == 0)) + { + route->flags |= SIGAR_RTF_GATEWAY; + } + + entry = sigar_cache_get(sigar->netif_names, ipr->dwForwardIfIndex); + if (entry->value) { + SIGAR_SSTRCPY(route->ifname, (char *)entry->value); + } + } + + free(buffer); + + return SIGAR_OK; +} + +#define sigar_GetIfTable \ + sigar->iphlpapi.get_if_table.func + +#define sigar_GetIfEntry \ + sigar->iphlpapi.get_if_entry.func + +static int sigar_get_if_table(sigar_t *sigar, PMIB_IFTABLE *iftable) +{ + ULONG size = sigar->ifconf_len; + DWORD rc; + + DLLMOD_INIT(iphlpapi, FALSE); + + if (!sigar_GetIfTable) { + return SIGAR_ENOTIMPL; + } + + *iftable = (PMIB_IFTABLE)sigar->ifconf_buf; + rc = sigar_GetIfTable(*iftable, &size, FALSE); + + if (rc == ERROR_INSUFFICIENT_BUFFER) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "GetIfTable " + "realloc ifconf_buf old=%d, new=%d", + sigar->ifconf_len, size); + sigar->ifconf_len = size; + sigar->ifconf_buf = realloc(sigar->ifconf_buf, + sigar->ifconf_len); + + *iftable = (PMIB_IFTABLE)sigar->ifconf_buf; + rc = sigar_GetIfTable(*iftable, &size, FALSE); + } + + if (rc != NO_ERROR) { + return rc; + } + else { + return SIGAR_OK; + } +} + +static int get_mib_ifrow(sigar_t *sigar, + const char *name, + MIB_IFROW **ifrp) +{ + int status, key, cached=0; + sigar_cache_entry_t *entry; + + if (sigar->netif_mib_rows) { + cached = 1; + } + else { + status = sigar_net_interface_list_get(sigar, NULL); + if (status != SIGAR_OK) { + return status; + } + } + key = netif_hash(name); + entry = sigar_cache_get(sigar->netif_mib_rows, key); + if (!entry->value) { + return ENOENT; + } + + *ifrp = (MIB_IFROW *)entry->value; + if (cached) { + /* refresh */ + if ((status = sigar_GetIfEntry(*ifrp)) != NO_ERROR) { + return status; + } + } + + return SIGAR_OK; +} + +static int netif_hash(char *s) +{ + int hash = 0; + while (*s) { + hash = 31*hash + *s++; + } + return hash; +} + +/* Vista and later, wireless network cards are reported as IF_TYPE_IEEE80211 */ +#ifndef IF_TYPE_IEEE80211 +#define IF_TYPE_IEEE80211 71 +#endif + +static int +sigar_net_interface_name_get(sigar_t *sigar, MIB_IFROW *ifr, PIP_ADAPTER_ADDRESSES address_list, char *name) +{ + PIP_ADAPTER_ADDRESSES iter; + int lpc = 0; + + if (address_list == NULL) { + return SIGAR_ENOTIMPL; + } + + for (iter = address_list; iter != NULL; iter = iter->Next) { + for (lpc = 0; lpc < iter->PhysicalAddressLength; lpc++) { + if (iter->PhysicalAddress[lpc] != ifr->bPhysAddr[lpc]) { + break; + } + } + + if (lpc == iter->PhysicalAddressLength) { + wcstombs(name, iter->FriendlyName, MAX_INTERFACE_NAME_LEN); + name[MAX_INTERFACE_NAME_LEN-1] = '\0'; + return SIGAR_OK; + } + } + + return SIGAR_ENOENT; +} + +SIGAR_DECLARE(int) +sigar_net_interface_list_get(sigar_t *sigar, + sigar_net_interface_list_t *iflist) +{ + MIB_IFTABLE *ift; + int i, status; + int lo=0, eth=0, la=0; + PIP_ADAPTER_ADDRESSES address_list = NULL; + ULONG size = 0; + + status = sigar_get_adapters_addresses(sigar, AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, &address_list, &size); + + if (status != SIGAR_OK) { + address_list = NULL; + } + + if (!sigar->netif_mib_rows) { + sigar->netif_mib_rows = + sigar_netif_cache_new(sigar); + } + + if (!sigar->netif_names) { + sigar->netif_names = + sigar_netif_cache_new(sigar); + } + + if ((status = sigar_get_if_table(sigar, &ift)) != SIGAR_OK) { + if (address_list) { + free(address_list); + } + return status; + } + + if (iflist) { + iflist->number = 0; + iflist->size = ift->dwNumEntries; + iflist->data = + malloc(sizeof(*(iflist->data)) * iflist->size); + } + + for (i=0; idwNumEntries; i++) { + char name[MAX_INTERFACE_NAME_LEN]; + int key; + MIB_IFROW *ifr = ift->table + i; + sigar_cache_entry_t *entry; + + status = SIGAR_ENOENT; + + if (strEQ(ifr->bDescr, MS_LOOPBACK_ADAPTER)) { + /* special-case */ + sprintf(name, NETIF_LA "%d", la++); + } + else if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) { + if (!sigar->netif_name_short) { + status = sigar_net_interface_name_get(sigar, ifr, address_list, name); + } + if (status != SIGAR_OK) { + sprintf(name, "lo%d", lo++); + } + } + else if ((ifr->dwType == MIB_IF_TYPE_ETHERNET) || + (ifr->dwType == IF_TYPE_IEEE80211)) + { + if (!sigar->netif_name_short && + (strstr(ifr->bDescr, "Scheduler") == NULL) && + (strstr(ifr->bDescr, "Filter") == NULL)) + { + status = sigar_net_interface_name_get(sigar, ifr, address_list, name); + } + + if (status != SIGAR_OK) { + if (sigar->netif_name_short) { + sprintf(name, "eth%d", eth++); + } + else { + snprintf(name, ifr->dwDescrLen, "%s", ifr->bDescr); + } + } + } + else { + continue; /*XXX*/ + } + + if (iflist) { + iflist->data[iflist->number++] = sigar_strdup(name); + } + + key = netif_hash(name); + entry = sigar_cache_get(sigar->netif_mib_rows, key); + if (!entry->value) { + entry->value = malloc(sizeof(*ifr)); + } + memcpy(entry->value, ifr, sizeof(*ifr)); + + /* save dwIndex -> name mapping for use by route_list */ + entry = sigar_cache_get(sigar->netif_names, ifr->dwIndex); + if (!entry->value) { + entry->value = sigar_strdup(name); + } + } + + if (address_list != NULL) { + free(address_list); + } + + return SIGAR_OK; +} + +static int sigar_net_interface_ipv6_config_find(sigar_t *sigar, int index, + sigar_net_interface_config_t *ifconfig) +{ +#ifdef SIGAR_USING_MSC6 + return SIGAR_ENOTIMPL; +#else + int status; + PIP_ADAPTER_ADDRESSES aa = (PIP_ADAPTER_ADDRESSES)sigar->ifconf_buf, addrs; + ULONG flags = GAA_FLAG_INCLUDE_PREFIX; + status = sigar_get_adapters_addresses(sigar, AF_UNSPEC, flags, &aa, &sigar->ifconf_len); + + if (status != SIGAR_OK) { + return status; + } + + for (addrs = aa; addrs; addrs = addrs->Next) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + if (addrs->IfIndex != index) { + continue; + } + for (addr = addrs->FirstUnicastAddress; addr; addr = addr->Next) { + struct sockaddr *sa = addr->Address.lpSockaddr; + + if (sa->sa_family == AF_INET6) { + struct in6_addr *inet6 = SIGAR_SIN6_ADDR(sa); + + sigar_net_address6_set(ifconfig->address6, inet6); + sigar_net_interface_scope6_set(ifconfig, inet6); + if (addrs->FirstPrefix) { + ifconfig->prefix6_length = addrs->FirstPrefix->PrefixLength; + } + return SIGAR_OK; + } + } + } + return SIGAR_ENOENT; +#endif +} + +SIGAR_DECLARE(int) +sigar_net_interface_config_get(sigar_t *sigar, + const char *name, + sigar_net_interface_config_t *ifconfig) +{ + MIB_IFROW *ifr; + MIB_IPADDRROW *ipaddr; + int status; + + if (!name) { + return sigar_net_interface_config_primary_get(sigar, ifconfig); + } + + status = get_mib_ifrow(sigar, name, &ifr); + if (status != SIGAR_OK) { + return status; + } + + SIGAR_ZERO(ifconfig); + + SIGAR_SSTRCPY(ifconfig->name, name); + + ifconfig->mtu = ifr->dwMtu; + + sigar_net_address_mac_set(ifconfig->hwaddr, + ifr->bPhysAddr, + SIGAR_IFHWADDRLEN); + + SIGAR_SSTRCPY(ifconfig->description, + ifr->bDescr); + + if (ifr->dwOperStatus & MIB_IF_OPER_STATUS_OPERATIONAL) { + ifconfig->flags |= SIGAR_IFF_UP|SIGAR_IFF_RUNNING; + } + + status = sigar_get_netif_ipaddr(sigar, + ifr->dwIndex, + &ipaddr); + + if (status == SIGAR_OK) { + sigar_net_address_set(ifconfig->address, + ipaddr->dwAddr); + + sigar_net_address_set(ifconfig->netmask, + ipaddr->dwMask); + + if (ifr->dwType != MIB_IF_TYPE_LOOPBACK) { + if (ipaddr->dwBCastAddr) { + long bcast = + ipaddr->dwAddr & ipaddr->dwMask; + + bcast |= ~ipaddr->dwMask; + ifconfig->flags |= SIGAR_IFF_BROADCAST; + + sigar_net_address_set(ifconfig->broadcast, + bcast); + } + } + } + + /* hack for MS_LOOPBACK_ADAPTER */ + if (strnEQ(name, NETIF_LA, sizeof(NETIF_LA)-1)) { + ifr->dwType = MIB_IF_TYPE_LOOPBACK; + } + + if (ifr->dwType == MIB_IF_TYPE_LOOPBACK) { + ifconfig->flags |= SIGAR_IFF_LOOPBACK; + + SIGAR_SSTRCPY(ifconfig->type, + SIGAR_NIC_LOOPBACK); + } + else { + if (ipaddr) { + ifconfig->flags |= SIGAR_IFF_MULTICAST; + } + + SIGAR_SSTRCPY(ifconfig->type, + SIGAR_NIC_ETHERNET); + } + + sigar_net_interface_ipv6_config_init(ifconfig); + sigar_net_interface_ipv6_config_find(sigar, ifr->dwIndex, ifconfig); + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) +sigar_net_interface_stat_get(sigar_t *sigar, const char *name, + sigar_net_interface_stat_t *ifstat) +{ + MIB_IFROW *ifr; + int status; + + status = get_mib_ifrow(sigar, name, &ifr); + if (status != SIGAR_OK) { + return status; + } + + ifstat->rx_bytes = ifr->dwInOctets; + ifstat->rx_packets = ifr->dwInUcastPkts + ifr->dwInNUcastPkts; + ifstat->rx_errors = ifr->dwInErrors; + ifstat->rx_dropped = ifr->dwInDiscards; + ifstat->rx_overruns = SIGAR_FIELD_NOTIMPL; + ifstat->rx_frame = SIGAR_FIELD_NOTIMPL; + + ifstat->tx_bytes = ifr->dwOutOctets; + ifstat->tx_packets = ifr->dwOutUcastPkts + ifr->dwOutNUcastPkts; + ifstat->tx_errors = ifr->dwOutErrors; + ifstat->tx_dropped = ifr->dwOutDiscards; + ifstat->tx_overruns = SIGAR_FIELD_NOTIMPL; + ifstat->tx_collisions = SIGAR_FIELD_NOTIMPL; + ifstat->tx_carrier = SIGAR_FIELD_NOTIMPL; + + ifstat->speed = ifr->dwSpeed; + + return SIGAR_OK; +} + +#define IS_TCP_SERVER(state, flags) \ + ((flags & SIGAR_NETCONN_SERVER) && (state == MIB_TCP_STATE_LISTEN)) + +#define IS_TCP_CLIENT(state, flags) \ + ((flags & SIGAR_NETCONN_CLIENT) && (state != MIB_TCP_STATE_LISTEN)) + +#define sigar_GetTcpTable \ + sigar->iphlpapi.get_tcp_table.func + +static int net_conn_get_tcp(sigar_net_connection_walker_t *walker) +{ + sigar_t *sigar = walker->sigar; + int flags = walker->flags; + int status, i; + DWORD rc, size=0; + PMIB_TCPTABLE tcp; + + DLLMOD_INIT(iphlpapi, FALSE); + + if (!sigar_GetTcpTable) { + return SIGAR_ENOTIMPL; + } + + rc = sigar_GetTcpTable(NULL, &size, FALSE); + if (rc != ERROR_INSUFFICIENT_BUFFER) { + return GetLastError(); + } + tcp = malloc(size); + rc = sigar_GetTcpTable(tcp, &size, FALSE); + if (rc) { + free(tcp); + return GetLastError(); + } + + /* go in reverse to get LISTEN states first */ + for (i = (tcp->dwNumEntries-1); i >= 0; i--) { + sigar_net_connection_t conn; + DWORD state = tcp->table[i].dwState; + + if (!(IS_TCP_SERVER(state, flags) || + IS_TCP_CLIENT(state, flags))) + { + continue; + } + + conn.local_port = htons((WORD)tcp->table[i].dwLocalPort); + conn.remote_port = htons((WORD)tcp->table[i].dwRemotePort); + + conn.type = SIGAR_NETCONN_TCP; + + sigar_net_address_set(conn.local_address, + tcp->table[i].dwLocalAddr); + + sigar_net_address_set(conn.remote_address, + tcp->table[i].dwRemoteAddr); + + conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL; + + switch (state) { + case MIB_TCP_STATE_CLOSED: + conn.state = SIGAR_TCP_CLOSE; + break; + case MIB_TCP_STATE_LISTEN: + conn.state = SIGAR_TCP_LISTEN; + break; + case MIB_TCP_STATE_SYN_SENT: + conn.state = SIGAR_TCP_SYN_SENT; + break; + case MIB_TCP_STATE_SYN_RCVD: + conn.state = SIGAR_TCP_SYN_RECV; + break; + case MIB_TCP_STATE_ESTAB: + conn.state = SIGAR_TCP_ESTABLISHED; + break; + case MIB_TCP_STATE_FIN_WAIT1: + conn.state = SIGAR_TCP_FIN_WAIT1; + break; + case MIB_TCP_STATE_FIN_WAIT2: + conn.state = SIGAR_TCP_FIN_WAIT2; + break; + case MIB_TCP_STATE_CLOSE_WAIT: + conn.state = SIGAR_TCP_CLOSE_WAIT; + break; + case MIB_TCP_STATE_CLOSING: + conn.state = SIGAR_TCP_CLOSING; + break; + case MIB_TCP_STATE_LAST_ACK: + conn.state = SIGAR_TCP_LAST_ACK; + break; + case MIB_TCP_STATE_TIME_WAIT: + conn.state = SIGAR_TCP_TIME_WAIT; + break; + case MIB_TCP_STATE_DELETE_TCB: + default: + conn.state = SIGAR_TCP_UNKNOWN; + break; + } + + if (walker->add_connection(walker, &conn) != SIGAR_OK) { + break; + } + } + + free(tcp); + return SIGAR_OK; +} + +#define IS_UDP_SERVER(conn, flags) \ + ((flags & SIGAR_NETCONN_SERVER) && !conn.remote_port) + +#define IS_UDP_CLIENT(state, flags) \ + ((flags & SIGAR_NETCONN_CLIENT) && conn.remote_port) + +#define sigar_GetUdpTable \ + sigar->iphlpapi.get_udp_table.func + +static int net_conn_get_udp(sigar_net_connection_walker_t *walker) +{ + sigar_t *sigar = walker->sigar; + int flags = walker->flags; + int status; + DWORD rc, size=0, i; + PMIB_UDPTABLE udp; + + DLLMOD_INIT(iphlpapi, FALSE); + + if (!sigar_GetUdpTable) { + return SIGAR_ENOTIMPL; + } + + rc = sigar_GetUdpTable(NULL, &size, FALSE); + if (rc != ERROR_INSUFFICIENT_BUFFER) { + return GetLastError(); + } + udp = malloc(size); + rc = sigar_GetUdpTable(udp, &size, FALSE); + if (rc) { + free(udp); + return GetLastError(); + } + + for (i = 0; i < udp->dwNumEntries; i++) { + sigar_net_connection_t conn; + + if (!(IS_UDP_SERVER(conn, flags) || + IS_UDP_CLIENT(conn, flags))) + { + continue; + } + + conn.local_port = htons((WORD)udp->table[i].dwLocalPort); + conn.remote_port = 0; + + conn.type = SIGAR_NETCONN_UDP; + + sigar_net_address_set(conn.local_address, + udp->table[i].dwLocalAddr); + + sigar_net_address_set(conn.remote_address, 0); + + conn.send_queue = conn.receive_queue = SIGAR_FIELD_NOTIMPL; + + if (walker->add_connection(walker, &conn) != SIGAR_OK) { + break; + } + } + + free(udp); + return SIGAR_OK; +} + +SIGAR_DECLARE(int) +sigar_net_connection_walk(sigar_net_connection_walker_t *walker) +{ + int status; + + if (walker->flags & SIGAR_NETCONN_TCP) { + status = net_conn_get_tcp(walker); + + if (status != SIGAR_OK) { + return status; + } + } + + if (walker->flags & SIGAR_NETCONN_UDP) { + status = net_conn_get_udp(walker); + + if (status != SIGAR_OK) { + return status; + } + } + + return SIGAR_OK; +} + +#define sigar_GetTcpStatistics \ + sigar->iphlpapi.get_tcp_stats.func + +SIGAR_DECLARE(int) +sigar_tcp_get(sigar_t *sigar, + sigar_tcp_t *tcp) +{ + MIB_TCPSTATS mib; + int status; + + DLLMOD_INIT(iphlpapi, FALSE); + + if (!sigar_GetTcpStatistics) { + return SIGAR_ENOTIMPL; + } + + status = sigar_GetTcpStatistics(&mib); + + if (status != NO_ERROR) { + return status; + } + + tcp->active_opens = mib.dwActiveOpens; + tcp->passive_opens = mib.dwPassiveOpens; + tcp->attempt_fails = mib.dwAttemptFails; + tcp->estab_resets = mib.dwEstabResets; + tcp->curr_estab = mib.dwCurrEstab; + tcp->in_segs = mib.dwInSegs; + tcp->out_segs = mib.dwOutSegs; + tcp->retrans_segs = mib.dwRetransSegs; + tcp->in_errs = mib.dwInErrs; + tcp->out_rsts = mib.dwOutRsts; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) +sigar_nfs_client_v2_get(sigar_t *sigar, + sigar_nfs_client_v2_t *nfs) +{ + return SIGAR_ENOTIMPL; +} + +SIGAR_DECLARE(int) +sigar_nfs_server_v2_get(sigar_t *sigar, + sigar_nfs_server_v2_t *nfs) +{ + return SIGAR_ENOTIMPL; +} + +SIGAR_DECLARE(int) +sigar_nfs_client_v3_get(sigar_t *sigar, + sigar_nfs_client_v3_t *nfs) +{ + return SIGAR_ENOTIMPL; +} + +SIGAR_DECLARE(int) +sigar_nfs_server_v3_get(sigar_t *sigar, + sigar_nfs_server_v3_t *nfs) +{ + return SIGAR_ENOTIMPL; +} + +#define sigar_GetTcpExTable \ + sigar->iphlpapi.get_tcpx_table.func + +#define sigar_GetUdpExTable \ + sigar->iphlpapi.get_udpx_table.func + +SIGAR_DECLARE(int) sigar_proc_port_get(sigar_t *sigar, + int protocol, + unsigned long port, + sigar_pid_t *pid) +{ + DWORD rc, i; + + DLLMOD_INIT(iphlpapi, FALSE); + + if (protocol == SIGAR_NETCONN_TCP) { + PMIB_TCPEXTABLE tcp; + + if (!sigar_GetTcpExTable) { + return SIGAR_ENOTIMPL; + } + + rc = sigar_GetTcpExTable(&tcp, FALSE, GetProcessHeap(), + 2, 2); + + if (rc) { + return GetLastError(); + } + + for (i=0; idwNumEntries; i++) { + if (tcp->table[i].dwState != MIB_TCP_STATE_LISTEN) { + continue; + } + + if (htons((WORD)tcp->table[i].dwLocalPort) != port) { + continue; + } + + *pid = tcp->table[i].dwProcessId; + + return SIGAR_OK; + } + } + else if (protocol == SIGAR_NETCONN_UDP) { + PMIB_UDPEXTABLE udp; + + if (!sigar_GetUdpExTable) { + return SIGAR_ENOTIMPL; + } + + rc = sigar_GetUdpExTable(&udp, FALSE, GetProcessHeap(), + 2, 2); + + if (rc) { + return GetLastError(); + } + + for (i=0; idwNumEntries; i++) { + if (htons((WORD)udp->table[i].dwLocalPort) != port) { + continue; + } + + *pid = udp->table[i].dwProcessId; + + return SIGAR_OK; + } + } + else { + return SIGAR_ENOTIMPL; + } + + return ENOENT; +} + +#define sigar_GetIpNetTable \ + sigar->iphlpapi.get_ipnet_table.func + +SIGAR_DECLARE(int) sigar_arp_list_get(sigar_t *sigar, + sigar_arp_list_t *arplist) +{ + int status; + DWORD rc, size=0, i; + PMIB_IPNETTABLE ipnet; + + DLLMOD_INIT(iphlpapi, FALSE); + + if (!sigar_GetIpNetTable) { + return SIGAR_ENOTIMPL; + } + + rc = sigar_GetIpNetTable(NULL, &size, FALSE); + if (rc != ERROR_INSUFFICIENT_BUFFER) { + return GetLastError(); + } + ipnet = malloc(size); + rc = sigar_GetIpNetTable(ipnet, &size, FALSE); + if (rc) { + free(ipnet); + return GetLastError(); + } + + sigar_arp_list_create(arplist); + + if (!sigar->netif_names) { + /* dwIndex -> name map */ + sigar_net_interface_list_get(sigar, NULL); + } + + for (i = 0; i < ipnet->dwNumEntries; i++) { + sigar_arp_t *arp; + PMIB_IPNETROW entry; + sigar_cache_entry_t *ifname; + + entry = &ipnet->table[i]; + SIGAR_ARP_LIST_GROW(arplist); + arp = &arplist->data[arplist->number++]; + + sigar_net_address_set(arp->address, + entry->dwAddr); + + sigar_net_address_mac_set(arp->hwaddr, + entry->bPhysAddr, + entry->dwPhysAddrLen); + + ifname = sigar_cache_get(sigar->netif_names, entry->dwIndex); + if (ifname->value) { + SIGAR_SSTRCPY(arp->ifname, (char *)ifname->value); + } + + arp->flags = 0; /*XXX*/ + SIGAR_SSTRCPY(arp->type, "ether"); /*XXX*/ + } + + free(ipnet); + + return SIGAR_OK; +} + +#include + +static int sigar_who_net_sessions(sigar_t *sigar, + sigar_who_list_t *wholist) +{ + NET_API_STATUS status; + LPSESSION_INFO_10 buffer=NULL, ptr; + DWORD entries=0, total_entries=0; + DWORD resume_handle=0; + DWORD i; + + do { + status = NetSessionEnum(NULL, /* server name */ + NULL, /* client name */ + NULL, /* user name */ + 10, /* level */ + (LPBYTE*)&buffer, + MAX_PREFERRED_LENGTH, + &entries, + &total_entries, + &resume_handle); + + if ((status == NERR_Success) || (status == ERROR_MORE_DATA)) { + if ((ptr = buffer)) { + for (i=0; idata[wholist->number++]; + + who->time = (time(NULL) - ptr->sesi10_time); + SIGAR_W2A((LPCWSTR)ptr->sesi10_username, + who->user, sizeof(who->user)); + SIGAR_W2A((LPCWSTR)ptr->sesi10_cname, + who->host, sizeof(who->host)); + SIGAR_SSTRCPY(who->device, "network share"); + + ptr++; + } + } + } + else { + break; + } + + if (buffer) { + NetApiBufferFree(buffer); + buffer = NULL; + } + } while (status == ERROR_MORE_DATA); + + if (buffer) { + NetApiBufferFree(buffer); + } + + return SIGAR_OK; +} + +static int get_logon_info(HKEY users, + char *username, + sigar_who_t *who) +{ + DWORD status, size, type; + HKEY key; + char key_name[MAX_PATH]; + char value[256]; + FILETIME wtime; + + who->time = 0; + + sprintf(key_name, "%s\\Volatile Environment", username); + if (RegOpenKey(users, key_name, &key) != ERROR_SUCCESS) { + return ENOENT; + } + + status = RegQueryInfoKey(key, + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, + &wtime); + + if (status == ERROR_SUCCESS) { + FileTimeToLocalFileTime(&wtime, &wtime); + who->time = sigar_FileTimeToTime(&wtime) / 1000000; + } + + size = sizeof(value); + status = RegQueryValueEx(key, "CLIENTNAME", + NULL, &type, value, &size); + if (status == ERROR_SUCCESS) { + if ((value[0] != '\0') && !strEQ(value, "Console")) { + SIGAR_SSTRCPY(who->host, value); + } + } + + size = sizeof(value); + status = RegQueryValueEx(key, "SESSIONNAME", + NULL, &type, value, &size); + if (status == ERROR_SUCCESS) { + SIGAR_SSTRCPY(who->device, value); + } + + RegCloseKey(key); + + return SIGAR_OK; +} + +#define sigar_ConvertStringSidToSid \ + sigar->advapi.convert_string_sid.func + +static int sigar_who_registry(sigar_t *sigar, + sigar_who_list_t *wholist) +{ + HKEY users; + DWORD index=0, status; + + if (!sigar_ConvertStringSidToSid) { + return ENOENT; + } + + status = RegOpenKey(HKEY_USERS, NULL, &users); + if (status != ERROR_SUCCESS) { + return status; + } + + while (1) { + char subkey[MAX_PATH]; + char username[SIGAR_CRED_NAME_MAX]; + char domain[SIGAR_CRED_NAME_MAX]; + DWORD subkey_len = sizeof(subkey); + DWORD username_len = sizeof(username); + DWORD domain_len = sizeof(domain); + PSID sid; + SID_NAME_USE type; + + status = RegEnumKeyEx(users, index, subkey, &subkey_len, + NULL, NULL, NULL, NULL); + + if (status != ERROR_SUCCESS) { + break; + } + + index++; + + if ((subkey[0] == '.') || strstr(subkey, "_Classes")) { + continue; + } + + if (!sigar_ConvertStringSidToSid(subkey, &sid)) { + continue; + } + + if (LookupAccountSid(NULL, /* server */ + sid, + username, &username_len, + domain, &domain_len, + &type)) + { + sigar_who_t *who; + + SIGAR_WHO_LIST_GROW(wholist); + who = &wholist->data[wholist->number++]; + + SIGAR_SSTRCPY(who->user, username); + SIGAR_SSTRCPY(who->host, domain); + SIGAR_SSTRCPY(who->device, "console"); + + get_logon_info(users, subkey, who); + } + + LocalFree(sid); + } + + RegCloseKey(users); + + return SIGAR_OK; +} + +#define sigar_WTSEnumerateSessions \ + sigar->wtsapi.enum_sessions.func + +#define sigar_WTSFreeMemory \ + sigar->wtsapi.free_mem.func + +#define sigar_WTSQuerySessionInformation \ + sigar->wtsapi.query_session.func + +#define sigar_WinStationQueryInformation \ + sigar->winsta.query_info.func + +static int sigar_who_wts(sigar_t *sigar, + sigar_who_list_t *wholist) +{ + DWORD count=0, i; + WTS_SESSION_INFO *sessions = NULL; + + if (DLLMOD_INIT(wtsapi, TRUE) != SIGAR_OK) { + sigar_log(sigar, SIGAR_LOG_DEBUG, + "Terminal Services api functions not available"); + return ENOENT; + } + + DLLMOD_INIT(winsta, FALSE); + + if (!sigar_WTSEnumerateSessions(0, 0, 1, &sessions, &count)) { + return GetLastError(); + } + + for (i=0; idata[wholist->number++]; + + SIGAR_SSTRCPY(who->device, sessions[i].pWinStationName); + + buffer = NULL; + bytes = 0; + if (sigar_WTSQuerySessionInformation(0, + sessionId, + WTSClientAddress, + &buffer, + &bytes)) + { + PWTS_CLIENT_ADDRESS client = + (PWTS_CLIENT_ADDRESS)buffer; + + sprintf(who->host, "%u.%u.%u.%u", + client->Address[2], + client->Address[3], + client->Address[4], + client->Address[5]); + + sigar_WTSFreeMemory(buffer); + } + else { + SIGAR_SSTRCPY(who->host, "unknown"); + } + + buffer = NULL; + bytes = 0; + if (sigar_WTSQuerySessionInformation(0, + sessionId, + WTSUserName, + &buffer, + &bytes)) + { + SIGAR_SSTRCPY(who->user, buffer); + sigar_WTSFreeMemory(buffer); + } + else { + SIGAR_SSTRCPY(who->user, "unknown"); + } + + buffer = NULL; + bytes = 0; + if (sigar_WinStationQueryInformation && + sigar_WinStationQueryInformation(0, + sessionId, + WinStationInformation, + &station_info, + sizeof(station_info), + &bytes)) + { + who->time = + sigar_FileTimeToTime(&station_info.ConnectTime) / 1000000; + } + else { + who->time = 0; + } + } + + sigar_WTSFreeMemory(sessions); + + return SIGAR_OK; +} + +int sigar_who_list_get_win32(sigar_t *sigar, + sigar_who_list_t *wholist) +{ + sigar_who_net_sessions(sigar, wholist); + + sigar_who_registry(sigar, wholist); + + sigar_who_wts(sigar, wholist); + + return SIGAR_OK; +} + +/* see: http://msdn2.microsoft.com/en-us/library/ms724833.aspx */ +#ifndef VER_NT_WORKSTATION +#define VER_NT_WORKSTATION 0x0000001 +#endif + +#ifdef SIGAR_USING_MSC6 +#define sigar_wProductType wReserved[1] +#else +#define sigar_wProductType wProductType +#endif +#ifdef _M_X64 +#define SIGAR_ARCH "x64" +#else +#define SIGAR_ARCH "x86" +#endif + +int sigar_os_sys_info_get(sigar_t *sigar, + sigar_sys_info_t *sysinfo) +{ + OSVERSIONINFOEX version; + char *vendor_name, *vendor_version, *code_name=NULL; + + version.dwOSVersionInfoSize = sizeof(version); + GetVersionEx((OSVERSIONINFO *)&version); + + if (version.dwMajorVersion == 4) { + vendor_name = "Windows NT"; + vendor_version = "NT"; + } + else if (version.dwMajorVersion == 5) { + switch (version.dwMinorVersion) { + case 0: + vendor_name = "Windows 2000"; + vendor_version = "2000"; + break; + case 1: + vendor_name = "Windows XP"; + vendor_version = "XP"; + code_name = "Whistler"; + break; + case 2: + vendor_name = "Windows 2003"; + vendor_version = "2003"; + code_name = "Whistler Server"; + break; + default: + vendor_name = "Windows Unknown"; + break; + } + } + else if (version.dwMajorVersion == 6) { + if (version.sigar_wProductType == VER_NT_WORKSTATION) { + if (version.dwMinorVersion == 0) { + vendor_name = "Windows Vista"; + vendor_version = "Vista"; + code_name = "Longhorn"; + } + else { + vendor_name = "Windows 7"; + vendor_version = "7"; + code_name = "Vienna"; + } + } + else { + vendor_name = "Windows 2008"; + vendor_version = "2008"; + code_name = "Longhorn Server"; + } + } + + SIGAR_SSTRCPY(sysinfo->name, "Win32"); + SIGAR_SSTRCPY(sysinfo->vendor, "Microsoft"); + SIGAR_SSTRCPY(sysinfo->vendor_name, vendor_name); + SIGAR_SSTRCPY(sysinfo->vendor_version, vendor_version); + if (code_name) { + SIGAR_SSTRCPY(sysinfo->vendor_code_name, code_name); + } + + SIGAR_SSTRCPY(sysinfo->arch, SIGAR_ARCH); + + sprintf(sysinfo->version, "%d.%d", + version.dwMajorVersion, + version.dwMinorVersion); + + SIGAR_SSTRCPY(sysinfo->patch_level, + version.szCSDVersion); + + sprintf(sysinfo->description, "%s %s", + sysinfo->vendor, sysinfo->vendor_name); + + return SIGAR_OK; +} + +#define sigar_QueryServiceStatusEx \ + sigar->advapi.query_service_status.func + +int sigar_service_pid_get(sigar_t *sigar, char *name, sigar_pid_t *pid) +{ + DWORD rc = ERROR_SUCCESS, len; + SC_HANDLE mgr; + HANDLE svc; + SERVICE_STATUS_PROCESS status; + + if (!sigar_QueryServiceStatusEx) { + return SIGAR_ENOTIMPL; + } + + mgr = OpenSCManager(NULL, + SERVICES_ACTIVE_DATABASE, + SC_MANAGER_ALL_ACCESS); + + if (!mgr) { + return GetLastError(); + } + + if (!(svc = OpenService(mgr, name, SERVICE_ALL_ACCESS))) { + CloseServiceHandle(mgr); + return GetLastError(); + } + + if (sigar_QueryServiceStatusEx(svc, + SC_STATUS_PROCESS_INFO, + (LPBYTE)&status, + sizeof(status), &len)) + { + *pid = status.dwProcessId; + } + else { + *pid = -1; + rc = GetLastError(); + } + + CloseServiceHandle(svc); + CloseServiceHandle(mgr); + + return rc; +} + +int sigar_services_status_get(sigar_services_status_t *ss, DWORD state) +{ + DWORD bytes, resume=0; + BOOL retval; + + if (!ss->handle) { + ss->handle = + OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE); + if (!ss->handle) { + return GetLastError(); + } + } + + retval = EnumServicesStatus(ss->handle, + SERVICE_WIN32, state, + ss->services, ss->size, + &bytes, &ss->count, &resume); + if (retval == FALSE) { + DWORD err = GetLastError(); + if (err != ERROR_MORE_DATA) { + return err; + } + + ss->services = realloc(ss->services, bytes); + ss->size = bytes; + + retval = EnumServicesStatus(ss->handle, + SERVICE_WIN32, state, + ss->services, ss->size, + &bytes, &ss->count, &resume); + + if (retval == FALSE) { + return GetLastError(); + } + } + + return SIGAR_OK; +} + +void sigar_services_status_close(sigar_services_status_t *ss) +{ + if (ss->handle) { + CloseServiceHandle(ss->handle); + } + if (ss->size) { + free(ss->services); + } + SIGAR_ZERO(ss); +} + +/* extract exe from QUERY_SERVICE_CONFIG.lpBinaryPathName + * leaves behind command-line arguments and quotes (if any) + */ +char *sigar_service_exe_get(char *path, char *buffer, int basename) +{ + char *ptr; + + if (path) { + strncpy(buffer, path, SIGAR_CMDLINE_MAX); + } + path = buffer; + + if (*path == '"') { + ++path; + if ((ptr = strchr(path, '"'))) { + *ptr = '\0'; + } + } + else { + ptr = sigar_strcasestr(path, ".exe"); + + if (ptr) { + *(ptr+4) = '\0'; + } + else { + if ((ptr = strchr(path, ' '))) { + *ptr = '\0'; + } + } + } + + if (basename && (ptr = strrchr(path, '\\'))) { + path = ++ptr; + } + + return path; +} + +static char *string_file_info_keys[] = { + "Comments", + "CompanyName", + "FileDescription", + "FileVersion", + "InternalName", + "LegalCopyright", + "LegalTrademarks", + "OriginalFilename", + "ProductName", + "ProductVersion", + "PrivateBuild", + "SpecialBuild", + NULL +}; + +int sigar_file_version_get(sigar_file_version_t *version, + char *name, + sigar_proc_env_t *infocb) +{ + DWORD handle, len; + LPTSTR data; + VS_FIXEDFILEINFO *info; + int status; + + if (!(len = GetFileVersionInfoSize(name, &handle))) { + return GetLastError(); + } + + if (len == 0) { + return !SIGAR_OK; + } + data = malloc(len); + + if (GetFileVersionInfo(name, handle, len, data)) { + if (VerQueryValue(data, "\\", &info, &len)) { + version->product_major = HIWORD(info->dwProductVersionMS); + version->product_minor = LOWORD(info->dwProductVersionMS); + version->product_build = HIWORD(info->dwProductVersionLS); + version->product_revision = LOWORD(info->dwProductVersionLS); + version->file_major = HIWORD(info->dwFileVersionMS); + version->file_minor = LOWORD(info->dwFileVersionMS); + version->file_build = HIWORD(info->dwFileVersionLS); + version->file_revision = LOWORD(info->dwFileVersionLS); + status = SIGAR_OK; + } + else { + status = GetLastError(); + } + } + else { + status = GetLastError(); + } + + if (infocb && (status == SIGAR_OK)) { + struct { + WORD lang; + WORD code_page; + } *trans; + + if (VerQueryValue(data, "\\VarFileInfo\\Translation", + &trans, &len)) + { + int i; + char buf[1024]; + void *ptr; + + for (i=0; string_file_info_keys[i]; i++) { + char *key = string_file_info_keys[i]; + sprintf(buf, "\\StringFileInfo\\%04x%04x\\%s", + trans[0].lang, trans[0].code_page, + key); + if (VerQueryValue(data, buf, &ptr, &len)) { + if (len == 0) { + continue; + } + infocb->env_getter(infocb->data, + key, strlen(key), + (char *)ptr, len); + } + } + } + } + + free(data); + return status; +} diff --git a/vendor/sigar/src/os/win32/wmi.cpp b/vendor/sigar/src/os/win32/wmi.cpp new file mode 100644 index 0000000..bc1019d --- /dev/null +++ b/vendor/sigar/src/os/win32/wmi.cpp @@ -0,0 +1,243 @@ +/* + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2009 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define UNICODE +#define _UNICODE +#define _WIN32_DCOM + +#include +#include +#include +#include +#include "sigar.h" + +#pragma comment(lib, "wbemuuid.lib") + +#ifndef SIGAR_CMDLINE_MAX +#define SIGAR_CMDLINE_MAX 4096<<2 +#endif + +class WMI { + + public: + WMI(); + ~WMI(); + HRESULT Open(LPCTSTR machine=NULL, LPCTSTR user=NULL, LPCTSTR pass=NULL); + void Close(); + HRESULT GetProcStringProperty(DWORD pid, TCHAR *name, TCHAR *value, DWORD len); + HRESULT GetProcExecutablePath(DWORD pid, TCHAR *value); + HRESULT GetProcCommandLine(DWORD pid, TCHAR *value); + int GetLastError(); + + private: + IWbemServices *wbem; + HRESULT result; + BSTR GetProcQuery(DWORD pid); +}; + +WMI::WMI() +{ + wbem = NULL; + result = S_OK; + CoInitializeEx(NULL, COINIT_MULTITHREADED); +} + +WMI::~WMI() +{ + Close(); + CoUninitialize(); +} + +/* XXX must be a better way to map HRESULT */ +int WMI::GetLastError() +{ + switch (result) { + case S_OK: + return ERROR_SUCCESS; + case WBEM_E_NOT_FOUND: + return ERROR_NOT_FOUND; + case WBEM_E_ACCESS_DENIED: + return ERROR_ACCESS_DENIED; + case WBEM_E_NOT_SUPPORTED: + return SIGAR_ENOTIMPL; + default: + return ERROR_INVALID_FUNCTION; + } +} + +HRESULT WMI::Open(LPCTSTR machine, LPCTSTR user, LPCTSTR pass) +{ + IWbemLocator *locator; + wchar_t path[MAX_PATH]; + + if (wbem) { + result = S_OK; + return result; + } + + result = + CoInitializeSecurity(NULL, //Security Descriptor + -1, //COM authentication + NULL, //Authentication services + NULL, //Reserved + RPC_C_AUTHN_LEVEL_DEFAULT, //Default authentication + RPC_C_IMP_LEVEL_IMPERSONATE, //Default Impersonation + NULL, //Authentication info + EOAC_NONE, //Additional capabilities + NULL); //Reserved + + result = CoCreateInstance(CLSID_WbemLocator, + NULL, /* IUnknown */ + CLSCTX_INPROC_SERVER, + IID_IWbemLocator, + (LPVOID *)&locator); + + if (FAILED(result)) { + return result; + } + + if (machine == NULL) { + machine = L"."; + } + + wsprintf(path, L"\\\\%S\\ROOT\\CIMV2", machine); + + result = locator->ConnectServer(bstr_t(path), //Object path of WMI namespace + bstr_t(user), //User name. NULL = current user + bstr_t(pass), //User password. NULL = current + NULL, //Locale. NULL indicates current + 0, //Security flags + NULL, //Authority (e.g. Kerberos) + NULL, //Context object + &wbem); //pointer to IWbemServices proxy + + locator->Release(); + + return result; +} + +void WMI::Close() +{ + if (wbem) { + wbem->Release(); + wbem = NULL; + result = S_OK; + } +} + +BSTR WMI::GetProcQuery(DWORD pid) +{ + wchar_t query[56]; + wsprintf(query, L"Win32_Process.Handle=%d", pid); + return bstr_t(query); +} + +HRESULT WMI::GetProcStringProperty(DWORD pid, TCHAR *name, TCHAR *value, DWORD len) +{ + IWbemClassObject *obj; + VARIANT var; + + result = wbem->GetObject(GetProcQuery(pid), 0, 0, &obj, 0); + + if (FAILED(result)) { + return result; + } + + result = obj->Get(name, 0, &var, 0, 0); + + if (SUCCEEDED(result)) { + if (var.vt == VT_NULL) { + result = E_INVALIDARG; + } + else { + lstrcpyn(value, var.bstrVal, len); + } + VariantClear(&var); + } + + obj->Release(); + + return result; +} + +HRESULT WMI::GetProcExecutablePath(DWORD pid, TCHAR *value) +{ + return GetProcStringProperty(pid, L"ExecutablePath", value, MAX_PATH); +} + +HRESULT WMI::GetProcCommandLine(DWORD pid, TCHAR *value) +{ + return GetProcStringProperty(pid, L"CommandLine", value, SIGAR_CMDLINE_MAX); +} + +/* in peb.c */ +extern "C" int sigar_parse_proc_args(sigar_t *sigar, WCHAR *buf, + sigar_proc_args_t *procargs); + +extern "C" int sigar_proc_args_wmi_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs) +{ + int status; + TCHAR buf[SIGAR_CMDLINE_MAX]; + WMI *wmi = new WMI(); + + if (FAILED(wmi->Open())) { + return wmi->GetLastError(); + } + + if (FAILED(wmi->GetProcCommandLine(pid, buf))) { + status = wmi->GetLastError(); + } + else { + status = sigar_parse_proc_args(sigar, buf, procargs); + } + + wmi->Close(); + delete wmi; + + return status; +} + +extern "C" int sigar_proc_exe_wmi_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_exe_t *procexe) +{ + int status; + TCHAR buf[MAX_PATH+1]; + WMI *wmi = new WMI(); + + if (FAILED(wmi->Open())) { + return wmi->GetLastError(); + } + + procexe->name[0] = '\0'; + + if (FAILED(wmi->GetProcExecutablePath(pid, buf))) { + status = wmi->GetLastError(); + } + else { + status = SIGAR_OK; + /* SIGAR_W2A(buf, procexe->name, sizeof(procexe->name)); */ + WideCharToMultiByte(CP_ACP, 0, buf, -1, + (LPSTR)procexe->name, sizeof(procexe->name), + NULL, NULL); + } + + wmi->Close(); + delete wmi; + + return status; +} diff --git a/vendor/sigar/src/sigar.c b/vendor/sigar/src/sigar.c new file mode 100644 index 0000000..8bd7e91 --- /dev/null +++ b/vendor/sigar/src/sigar.c @@ -0,0 +1,2428 @@ +/* + * Copyright (c) 2004-2009 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2009-2010 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#ifndef WIN32 +#include +#include +#include +#endif +#if defined(__OpenBSD__) || defined(__FreeBSD__) +#include +#endif +#ifndef WIN32 +#include +#endif + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_util.h" +#include "sigar_os.h" +#include "sigar_format.h" + +SIGAR_DECLARE(int) sigar_open(sigar_t **sigar) +{ + int status = sigar_os_open(sigar); + + if (status == SIGAR_OK) { + /* use env to revert to old behavior */ + (*sigar)->cpu_list_cores = getenv("SIGAR_CPU_LIST_SOCKETS") ? 0 : 1; + (*sigar)->pid = 0; + (*sigar)->ifconf_buf = NULL; + (*sigar)->ifconf_len = 0; + (*sigar)->log_level = -1; /* log nothing by default */ + (*sigar)->log_impl = NULL; + (*sigar)->log_data = NULL; + (*sigar)->ptql_re_impl = NULL; + (*sigar)->ptql_re_data = NULL; + (*sigar)->self_path = NULL; + (*sigar)->fsdev = NULL; + (*sigar)->pids = NULL; + (*sigar)->proc_cpu = NULL; + (*sigar)->net_listen = NULL; + (*sigar)->net_services_tcp = NULL; + (*sigar)->net_services_udp = NULL; + } + + return status; +} + +SIGAR_DECLARE(int) sigar_close(sigar_t *sigar) +{ + if (sigar->ifconf_buf) { + free(sigar->ifconf_buf); + } + if (sigar->self_path) { + free(sigar->self_path); + } + if (sigar->pids) { + sigar_proc_list_destroy(sigar, sigar->pids); + free(sigar->pids); + } + if (sigar->fsdev) { + sigar_cache_destroy(sigar->fsdev); + } + if (sigar->proc_cpu) { + sigar_cache_destroy(sigar->proc_cpu); + } + if (sigar->net_listen) { + sigar_cache_destroy(sigar->net_listen); + } + if (sigar->net_services_tcp) { + sigar_cache_destroy(sigar->net_services_tcp); + } + if (sigar->net_services_udp) { + sigar_cache_destroy(sigar->net_services_udp); + } + + return sigar_os_close(sigar); +} + +#ifndef __linux__ /* linux has a special case */ +SIGAR_DECLARE(sigar_pid_t) sigar_pid_get(sigar_t *sigar) +{ + if (!sigar->pid) { + sigar->pid = getpid(); + } + + return sigar->pid; +} +#endif + +/* XXX: add clear() function */ +/* XXX: check for stale-ness using start_time */ +SIGAR_DECLARE(int) sigar_proc_cpu_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_cpu_t *proccpu) +{ + sigar_cache_entry_t *entry; + sigar_proc_cpu_t *prev; + sigar_uint64_t otime, time_now = sigar_time_now_millis(); + sigar_uint64_t time_diff, total_diff; + int status; + + if (!sigar->proc_cpu) { + sigar->proc_cpu = sigar_cache_new(128); + } + + entry = sigar_cache_get(sigar->proc_cpu, pid); + if (entry->value) { + prev = (sigar_proc_cpu_t *)entry->value; + } + else { + prev = entry->value = malloc(sizeof(*prev)); + SIGAR_ZERO(prev); + } + + time_diff = time_now - prev->last_time; + proccpu->last_time = prev->last_time = time_now; + + if (time_diff == 0) { + /* we were just called within < 1 second ago. */ + memcpy(proccpu, prev, sizeof(*proccpu)); + return SIGAR_OK; + } + + otime = prev->total; + + status = + sigar_proc_time_get(sigar, pid, + (sigar_proc_time_t *)proccpu); + + if (status != SIGAR_OK) { + return status; + } + + memcpy(prev, proccpu, sizeof(*prev)); + + if (proccpu->total < otime) { + /* XXX this should not happen */ + otime = 0; + } + + if (otime == 0) { + proccpu->percent = 0.0; + /* first time called */ + return SIGAR_OK; + } + + total_diff = proccpu->total - otime; + proccpu->percent = total_diff / (double)time_diff; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_proc_stat_get(sigar_t *sigar, + sigar_proc_stat_t *procstat) +{ + int status, i; + sigar_proc_list_t *pids; + + SIGAR_ZERO(procstat); + procstat->threads = SIGAR_FIELD_NOTIMPL; + + if ((status = sigar_proc_list_get(sigar, NULL)) != SIGAR_OK) { + return status; + } + + pids = sigar->pids; + procstat->total = pids->number; + + for (i=0; inumber; i++) { + sigar_proc_state_t state; + + status = sigar_proc_state_get(sigar, pids->data[i], &state); + if (status != SIGAR_OK) { + continue; + } + + if (state.threads != SIGAR_FIELD_NOTIMPL) { + procstat->threads += state.threads; + } + + switch (state.state) { + case SIGAR_PROC_STATE_IDLE: + procstat->idle++; + break; + case SIGAR_PROC_STATE_RUN: + procstat->running++; + break; + case SIGAR_PROC_STATE_SLEEP: + procstat->sleeping++; + break; + case SIGAR_PROC_STATE_STOP: + procstat->stopped++; + break; + case SIGAR_PROC_STATE_ZOMBIE: + procstat->zombie++; + break; + default: + break; + } + } + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_sys_info_get(sigar_t *sigar, + sigar_sys_info_t *sysinfo) +{ + SIGAR_ZERO(sysinfo); + +#ifndef WIN32 + sigar_sys_info_get_uname(sysinfo); +#endif + + sigar_os_sys_info_get(sigar, sysinfo); + + return SIGAR_OK; +} + +#ifndef WIN32 + +#include + +int sigar_sys_info_get_uname(sigar_sys_info_t *sysinfo) +{ + struct utsname name; + + uname(&name); + + SIGAR_SSTRCPY(sysinfo->version, name.release); + SIGAR_SSTRCPY(sysinfo->vendor_name, name.sysname); + SIGAR_SSTRCPY(sysinfo->name, name.sysname); + SIGAR_SSTRCPY(sysinfo->machine, name.machine); + SIGAR_SSTRCPY(sysinfo->arch, name.machine); + SIGAR_SSTRCPY(sysinfo->patch_level, "unknown"); + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) +sigar_proc_cred_name_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_cred_name_t *proccredname) +{ + sigar_proc_cred_t cred; + + int status = sigar_proc_cred_get(sigar, pid, &cred); + + if (status != SIGAR_OK) { + return status; + } + + status = sigar_user_name_get(sigar, cred.uid, + proccredname->user, + sizeof(proccredname->user)); + + if (status != SIGAR_OK) { + return status; + } + + status = sigar_group_name_get(sigar, cred.gid, + proccredname->group, + sizeof(proccredname->group)); + + return status; +} + +#endif /* WIN32 */ + +int sigar_proc_list_create(sigar_proc_list_t *proclist) +{ + proclist->number = 0; + proclist->size = SIGAR_PROC_LIST_MAX; + proclist->data = malloc(sizeof(*(proclist->data)) * + proclist->size); + return SIGAR_OK; +} + +int sigar_proc_list_grow(sigar_proc_list_t *proclist) +{ + proclist->data = realloc(proclist->data, + sizeof(*(proclist->data)) * + (proclist->size + SIGAR_PROC_LIST_MAX)); + proclist->size += SIGAR_PROC_LIST_MAX; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_proc_list_destroy(sigar_t *sigar, + sigar_proc_list_t *proclist) +{ + if (proclist->size) { + free(proclist->data); + proclist->number = proclist->size = 0; + } + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_proc_list_get(sigar_t *sigar, + sigar_proc_list_t *proclist) +{ + if (proclist == NULL) { + /* internal re-use */ + if (sigar->pids == NULL) { + sigar->pids = malloc(sizeof(*sigar->pids)); + sigar_proc_list_create(sigar->pids); + } + else { + sigar->pids->number = 0; + } + proclist = sigar->pids; + } + else { + sigar_proc_list_create(proclist); + } + + return sigar_os_proc_list_get(sigar, proclist); +} + +int sigar_proc_args_create(sigar_proc_args_t *procargs) +{ + procargs->number = 0; + procargs->size = SIGAR_PROC_ARGS_MAX; + procargs->data = malloc(sizeof(*(procargs->data)) * + procargs->size); + return SIGAR_OK; +} + +int sigar_proc_args_grow(sigar_proc_args_t *procargs) +{ + procargs->data = realloc(procargs->data, + sizeof(*(procargs->data)) * + (procargs->size + SIGAR_PROC_ARGS_MAX)); + procargs->size += SIGAR_PROC_ARGS_MAX; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_proc_args_destroy(sigar_t *sigar, + sigar_proc_args_t *procargs) +{ + unsigned int i; + + if (procargs->size) { + for (i=0; inumber; i++) { + free(procargs->data[i]); + } + free(procargs->data); + procargs->number = procargs->size = 0; + } + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_proc_args_get(sigar_t *sigar, + sigar_pid_t pid, + sigar_proc_args_t *procargs) +{ + int status; + sigar_proc_args_create(procargs); + status = sigar_os_proc_args_get(sigar, pid, procargs); + if (status != SIGAR_OK) { + sigar_proc_args_destroy(sigar, procargs); + } + return status; +} + +int sigar_file_system_list_create(sigar_file_system_list_t *fslist) +{ + fslist->number = 0; + fslist->size = SIGAR_FS_MAX; + fslist->data = malloc(sizeof(*(fslist->data)) * + fslist->size); + return SIGAR_OK; +} + +int sigar_file_system_list_grow(sigar_file_system_list_t *fslist) +{ + fslist->data = realloc(fslist->data, + sizeof(*(fslist->data)) * + (fslist->size + SIGAR_FS_MAX)); + fslist->size += SIGAR_FS_MAX; + + return SIGAR_OK; +} + +/* indexed with sigar_file_system_type_e */ +static const char *fstype_names[] = { + "unknown", "none", "local", "remote", "ram", "cdrom", "swap" +}; + +static int sigar_common_fs_type_get(sigar_file_system_t *fsp) +{ + char *type = fsp->sys_type_name; + + switch (*type) { + case 'n': + if (strnEQ(type, "nfs", 3)) { + fsp->type = SIGAR_FSTYPE_NETWORK; + } + break; + case 's': + if (strEQ(type, "smbfs")) { /* samba */ + fsp->type = SIGAR_FSTYPE_NETWORK; + } + else if (strEQ(type, "swap")) { + fsp->type = SIGAR_FSTYPE_SWAP; + } + break; + case 'a': + if (strEQ(type, "afs")) { + fsp->type = SIGAR_FSTYPE_NETWORK; + } + break; + case 'i': + if (strEQ(type, "iso9660")) { + fsp->type = SIGAR_FSTYPE_CDROM; + } + break; + case 'c': + if (strEQ(type, "cvfs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + else if (strEQ(type, "cifs")) { + fsp->type = SIGAR_FSTYPE_NETWORK; + } + break; + case 'm': + if (strEQ(type, "msdos") || strEQ(type, "minix")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'h': + if (strEQ(type, "hpfs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'v': + if (strEQ(type, "vxfs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + else if (strEQ(type, "vfat")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + case 'z': + if (strEQ(type, "zfs")) { + fsp->type = SIGAR_FSTYPE_LOCAL_DISK; + } + break; + } + + return fsp->type; +} + +void sigar_fs_type_get(sigar_file_system_t *fsp) +{ + if (!(fsp->type || /* already set */ + sigar_os_fs_type_get(fsp) || /* try os specifics first */ + sigar_common_fs_type_get(fsp))) /* try common ones last */ + { + fsp->type = SIGAR_FSTYPE_NONE; + } + + if (fsp->type >= SIGAR_FSTYPE_MAX) { + fsp->type = SIGAR_FSTYPE_NONE; + } + + strcpy(fsp->type_name, fstype_names[fsp->type]); +} + + +SIGAR_DECLARE(int) +sigar_file_system_list_destroy(sigar_t *sigar, + sigar_file_system_list_t *fslist) +{ + if (fslist->size) { + free(fslist->data); + fslist->number = fslist->size = 0; + } + + return SIGAR_OK; +} + +#ifndef NFS_PROGRAM +#define NFS_PROGRAM 100003 +#endif + +#ifndef NFS_VERSION +#define NFS_VERSION 2 +#endif + +SIGAR_DECLARE(int) +sigar_file_system_ping(sigar_t *sigar, + sigar_file_system_t *fs) +{ + int status = SIGAR_OK; +#ifndef WIN32 + char *ptr; + + if ((fs->type == SIGAR_FSTYPE_NETWORK) && + strEQ(fs->sys_type_name, "nfs") && + (ptr = strchr(fs->dev_name, ':'))) + { + *ptr = '\0'; /* "hostname:/mount" -> "hostname" */ + + status = sigar_rpc_ping(fs->dev_name, + SIGAR_NETCONN_UDP, + NFS_PROGRAM, NFS_VERSION); + + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[fs_ping] %s -> %s: %s", + fs->dir_name, fs->dev_name, + ((status == SIGAR_OK) ? + "OK" : sigar_rpc_strerror(status))); + } + + *ptr = ':'; /* "hostname" -> "hostname:/mount" */ + } +#endif + return status; +} + +int sigar_cpu_info_list_create(sigar_cpu_info_list_t *cpu_infos) +{ + cpu_infos->number = 0; + cpu_infos->size = SIGAR_CPU_INFO_MAX; + cpu_infos->data = malloc(sizeof(*(cpu_infos->data)) * + cpu_infos->size); + return SIGAR_OK; +} + +int sigar_cpu_info_list_grow(sigar_cpu_info_list_t *cpu_infos) +{ + cpu_infos->data = realloc(cpu_infos->data, + sizeof(*(cpu_infos->data)) * + (cpu_infos->size + SIGAR_CPU_INFO_MAX)); + cpu_infos->size += SIGAR_CPU_INFO_MAX; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) +sigar_cpu_info_list_destroy(sigar_t *sigar, + sigar_cpu_info_list_t *cpu_infos) +{ + if (cpu_infos->size) { + free(cpu_infos->data); + cpu_infos->number = cpu_infos->size = 0; + } + + return SIGAR_OK; +} + +int sigar_cpu_list_create(sigar_cpu_list_t *cpulist) +{ + cpulist->number = 0; + cpulist->size = SIGAR_CPU_INFO_MAX; + cpulist->data = malloc(sizeof(*(cpulist->data)) * + cpulist->size); + return SIGAR_OK; +} + +int sigar_cpu_list_grow(sigar_cpu_list_t *cpulist) +{ + cpulist->data = realloc(cpulist->data, + sizeof(*(cpulist->data)) * + (cpulist->size + SIGAR_CPU_INFO_MAX)); + cpulist->size += SIGAR_CPU_INFO_MAX; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_cpu_list_destroy(sigar_t *sigar, + sigar_cpu_list_t *cpulist) +{ + if (cpulist->size) { + free(cpulist->data); + cpulist->number = cpulist->size = 0; + } + + return SIGAR_OK; +} + +int sigar_net_route_list_create(sigar_net_route_list_t *routelist) +{ + routelist->number = 0; + routelist->size = SIGAR_NET_ROUTE_LIST_MAX; + routelist->data = malloc(sizeof(*(routelist->data)) * + routelist->size); + return SIGAR_OK; +} + +int sigar_net_route_list_grow(sigar_net_route_list_t *routelist) +{ + routelist->data = + realloc(routelist->data, + sizeof(*(routelist->data)) * + (routelist->size + SIGAR_NET_ROUTE_LIST_MAX)); + routelist->size += SIGAR_NET_ROUTE_LIST_MAX; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_net_route_list_destroy(sigar_t *sigar, + sigar_net_route_list_t *routelist) +{ + if (routelist->size) { + free(routelist->data); + routelist->number = routelist->size = 0; + } + + return SIGAR_OK; +} + +int sigar_net_interface_list_create(sigar_net_interface_list_t *iflist) +{ + iflist->number = 0; + iflist->size = SIGAR_NET_IFLIST_MAX; + iflist->data = malloc(sizeof(*(iflist->data)) * + iflist->size); + return SIGAR_OK; +} + +int sigar_net_interface_list_grow(sigar_net_interface_list_t *iflist) +{ + iflist->data = realloc(iflist->data, + sizeof(*(iflist->data)) * + (iflist->size + SIGAR_NET_IFLIST_MAX)); + iflist->size += SIGAR_NET_IFLIST_MAX; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) +sigar_net_interface_list_destroy(sigar_t *sigar, + sigar_net_interface_list_t *iflist) +{ + unsigned int i; + + if (iflist->size) { + for (i=0; inumber; i++) { + free(iflist->data[i]); + } + free(iflist->data); + iflist->number = iflist->size = 0; + } + + return SIGAR_OK; +} + +int sigar_net_connection_list_create(sigar_net_connection_list_t *connlist) +{ + connlist->number = 0; + connlist->size = SIGAR_NET_CONNLIST_MAX; + connlist->data = malloc(sizeof(*(connlist->data)) * + connlist->size); + return SIGAR_OK; +} + +int sigar_net_connection_list_grow(sigar_net_connection_list_t *connlist) +{ + connlist->data = + realloc(connlist->data, + sizeof(*(connlist->data)) * + (connlist->size + SIGAR_NET_CONNLIST_MAX)); + connlist->size += SIGAR_NET_CONNLIST_MAX; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) +sigar_net_connection_list_destroy(sigar_t *sigar, + sigar_net_connection_list_t *connlist) +{ + if (connlist->size) { + free(connlist->data); + connlist->number = connlist->size = 0; + } + + return SIGAR_OK; +} + +#if !defined(__linux__) +/* + * implement sigar_net_connection_list_get using sigar_net_connection_walk + * linux has its own list_get impl. + */ +static int net_connection_list_walker(sigar_net_connection_walker_t *walker, + sigar_net_connection_t *conn) +{ + sigar_net_connection_list_t *connlist = + (sigar_net_connection_list_t *)walker->data; + + SIGAR_NET_CONNLIST_GROW(connlist); + memcpy(&connlist->data[connlist->number++], + conn, sizeof(*conn)); + + return SIGAR_OK; /* continue loop */ +} + +SIGAR_DECLARE(int) +sigar_net_connection_list_get(sigar_t *sigar, + sigar_net_connection_list_t *connlist, + int flags) +{ + int status; + sigar_net_connection_walker_t walker; + + sigar_net_connection_list_create(connlist); + + walker.sigar = sigar; + walker.flags = flags; + walker.data = connlist; + walker.add_connection = net_connection_list_walker; + + status = sigar_net_connection_walk(&walker); + + if (status != SIGAR_OK) { + sigar_net_connection_list_destroy(sigar, connlist); + } + + return status; +} +#endif + +static void sigar_net_listen_address_add(sigar_t *sigar, + sigar_net_connection_t *conn) +{ + sigar_cache_entry_t *entry = + sigar_cache_get(sigar->net_listen, conn->local_port); + + if (entry->value) { + if (conn->local_address.family == SIGAR_AF_INET6) { + return; /* prefer ipv4 */ + } + } + else { + entry->value = malloc(sizeof(conn->local_address)); + } + + memcpy(entry->value, &conn->local_address, + sizeof(conn->local_address)); +} + +SIGAR_DECLARE(int) +sigar_net_listen_address_get(sigar_t *sigar, + unsigned long port, + sigar_net_address_t *address) +{ + if (!sigar->net_listen || + !sigar_cache_find(sigar->net_listen, port)) + { + sigar_net_stat_t netstat; + int status = + sigar_net_stat_get(sigar, &netstat, + SIGAR_NETCONN_SERVER|SIGAR_NETCONN_TCP); + + if (status != SIGAR_OK) { + return status; + } + } + + if (sigar_cache_find(sigar->net_listen, port)) { + void *value = sigar_cache_get(sigar->net_listen, port)->value; + memcpy(address, value, sizeof(*address)); + return SIGAR_OK; + } + else { + return ENOENT; + } +} + +typedef struct { + sigar_net_stat_t *netstat; + sigar_net_connection_list_t *connlist; +} net_stat_getter_t; + +static int net_stat_walker(sigar_net_connection_walker_t *walker, + sigar_net_connection_t *conn) +{ + int state = conn->state; + sigar_cache_t *listen_ports = walker->sigar->net_listen; + net_stat_getter_t *getter = + (net_stat_getter_t *)walker->data; + + if (conn->type == SIGAR_NETCONN_TCP) { + getter->netstat->tcp_states[state]++; + + /* XXX listen_ports may get stale */ + if (state == SIGAR_TCP_LISTEN) { + sigar_net_listen_address_add(walker->sigar, conn); + } + else { + if (sigar_cache_find(listen_ports, + conn->local_port)) + { + getter->netstat->tcp_inbound_total++; + } + else { + getter->netstat->tcp_outbound_total++; + } + } + } + else if (conn->type == SIGAR_NETCONN_UDP) { + /*XXX*/ + } + + getter->netstat->all_inbound_total = + getter->netstat->tcp_inbound_total; + + getter->netstat->all_outbound_total = + getter->netstat->tcp_outbound_total; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) +sigar_net_stat_get(sigar_t *sigar, + sigar_net_stat_t *netstat, + int flags) +{ + sigar_net_connection_walker_t walker; + net_stat_getter_t getter; + + if (!sigar->net_listen) { + sigar->net_listen = sigar_cache_new(32); + } + + SIGAR_ZERO(netstat); + + getter.netstat = netstat; + + walker.sigar = sigar; + walker.data = &getter; + walker.add_connection = net_stat_walker; + + walker.flags = flags; + + return sigar_net_connection_walk(&walker); +} + +typedef struct { + sigar_net_stat_t *netstat; + sigar_net_address_t *address; + unsigned long port; +} net_stat_port_getter_t; + +static int net_stat_port_walker(sigar_net_connection_walker_t *walker, + sigar_net_connection_t *conn) +{ + net_stat_port_getter_t *getter = + (net_stat_port_getter_t *)walker->data; + sigar_net_stat_t *netstat = getter->netstat; + + if (conn->type == SIGAR_NETCONN_TCP) { + if (conn->local_port == getter->port) { + netstat->all_inbound_total++; + + if (sigar_net_address_equals(getter->address, + &conn->local_address) == SIGAR_OK) + { + netstat->tcp_inbound_total++; + } + } + else if (conn->remote_port == getter->port) { + netstat->all_outbound_total++; + + if (sigar_net_address_equals(getter->address, + &conn->remote_address) == SIGAR_OK) + { + netstat->tcp_outbound_total++; + } + } + else { + return SIGAR_OK; + } + + netstat->tcp_states[conn->state]++; + } + else if (conn->type == SIGAR_NETCONN_UDP) { + /*XXX*/ + } + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) +sigar_net_stat_port_get(sigar_t *sigar, + sigar_net_stat_t *netstat, + int flags, + sigar_net_address_t *address, + unsigned long port) +{ + sigar_net_connection_walker_t walker; + net_stat_port_getter_t getter; + + SIGAR_ZERO(netstat); + + getter.netstat = netstat; + getter.address = address; + getter.port = port; + + walker.sigar = sigar; + walker.data = &getter; + walker.add_connection = net_stat_port_walker; + + walker.flags = flags; + + if (SIGAR_LOG_IS_DEBUG(sigar)) { + char name[SIGAR_FQDN_LEN]; + sigar_net_address_to_string(sigar, address, name); + + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[net_stat_port] using address '%s:%d'", + name, port); + } + + return sigar_net_connection_walk(&walker); +} + +static int tcp_curr_estab_count(sigar_net_connection_walker_t *walker, + sigar_net_connection_t *conn) +{ + if ((conn->state == SIGAR_TCP_ESTABLISHED) || + (conn->state == SIGAR_TCP_CLOSE_WAIT)) + { + ((sigar_tcp_t *)walker->data)->curr_estab++; + } + + return SIGAR_OK; +} + +/* TCP-MIB::tcpCurrEstab */ +int sigar_tcp_curr_estab(sigar_t *sigar, sigar_tcp_t *tcp) +{ + sigar_net_connection_walker_t walker; + + walker.sigar = sigar; + walker.data = tcp; + walker.add_connection = tcp_curr_estab_count; + walker.flags = SIGAR_NETCONN_CLIENT|SIGAR_NETCONN_TCP; + + tcp->curr_estab = 0; + + return sigar_net_connection_walk(&walker); +} + +int sigar_arp_list_create(sigar_arp_list_t *arplist) +{ + arplist->number = 0; + arplist->size = SIGAR_ARP_LIST_MAX; + arplist->data = malloc(sizeof(*(arplist->data)) * + arplist->size); + return SIGAR_OK; +} + +int sigar_arp_list_grow(sigar_arp_list_t *arplist) +{ + arplist->data = realloc(arplist->data, + sizeof(*(arplist->data)) * + (arplist->size + SIGAR_ARP_LIST_MAX)); + arplist->size += SIGAR_ARP_LIST_MAX; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_arp_list_destroy(sigar_t *sigar, + sigar_arp_list_t *arplist) +{ + if (arplist->size) { + free(arplist->data); + arplist->number = arplist->size = 0; + } + + return SIGAR_OK; +} + +int sigar_who_list_create(sigar_who_list_t *wholist) +{ + wholist->number = 0; + wholist->size = SIGAR_WHO_LIST_MAX; + wholist->data = malloc(sizeof(*(wholist->data)) * + wholist->size); + return SIGAR_OK; +} + +int sigar_who_list_grow(sigar_who_list_t *wholist) +{ + wholist->data = realloc(wholist->data, + sizeof(*(wholist->data)) * + (wholist->size + SIGAR_WHO_LIST_MAX)); + wholist->size += SIGAR_WHO_LIST_MAX; + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_who_list_destroy(sigar_t *sigar, + sigar_who_list_t *wholist) +{ + if (wholist->size) { + free(wholist->data); + wholist->number = wholist->size = 0; + } + + return SIGAR_OK; +} + +#ifdef DARWIN +#include +#endif +#ifdef MAC_OS_X_VERSION_10_5 +# if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 +# define SIGAR_NO_UTMP +# endif +/* else 10.4 and earlier or compiled with -mmacosx-version-min=10.3 */ +#endif + +#if defined(__sun) +# include +# define SIGAR_UTMP_FILE _UTMPX_FILE +# define ut_time ut_tv.tv_sec +#elif defined(WIN32) +/* XXX may not be the default */ +#define SIGAR_UTMP_FILE "C:\\cygwin\\var\\run\\utmp" +#define UT_LINESIZE 16 +#define UT_NAMESIZE 16 +#define UT_HOSTSIZE 256 +#define UT_IDLEN 2 +#define ut_name ut_user + +struct utmp { + short ut_type; + int ut_pid; + char ut_line[UT_LINESIZE]; + char ut_id[UT_IDLEN]; + time_t ut_time; + char ut_user[UT_NAMESIZE]; + char ut_host[UT_HOSTSIZE]; + long ut_addr; +}; +#elif defined(NETWARE) +static char *getpass(const char *prompt) +{ + static char password[BUFSIZ]; + + fputs(prompt, stderr); + fgets((char *)&password, sizeof(password), stdin); + + return (char *)&password; +} +#elif !defined(SIGAR_NO_UTMP) +# include +# ifdef UTMP_FILE +# define SIGAR_UTMP_FILE UTMP_FILE +# else +# define SIGAR_UTMP_FILE _PATH_UTMP +# endif +#endif + +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(DARWIN) +# define ut_user ut_name +#endif + +#ifdef DARWIN +/* XXX from utmpx.h; sizeof changed in 10.5 */ +/* additionally, utmpx does not work on 10.4 */ +#define SIGAR_HAS_UTMPX +#define _PATH_UTMPX "/var/run/utmpx" +#define _UTX_USERSIZE 256 /* matches MAXLOGNAME */ +#define _UTX_LINESIZE 32 +#define _UTX_IDSIZE 4 +#define _UTX_HOSTSIZE 256 +struct utmpx { + char ut_user[_UTX_USERSIZE]; /* login name */ + char ut_id[_UTX_IDSIZE]; /* id */ + char ut_line[_UTX_LINESIZE]; /* tty name */ + pid_t ut_pid; /* process id creating the entry */ + short ut_type; /* type of this entry */ + struct timeval ut_tv; /* time entry was created */ + char ut_host[_UTX_HOSTSIZE]; /* host name */ + __uint32_t ut_pad[16]; /* reserved for future use */ +}; +#define ut_xtime ut_tv.tv_sec +#define UTMPX_USER_PROCESS 7 +/* end utmpx.h */ +#define SIGAR_UTMPX_FILE _PATH_UTMPX +#endif + +#if !defined(NETWARE) && !defined(_AIX) + +#define WHOCPY(dest, src) \ + SIGAR_SSTRCPY(dest, src); \ + if (sizeof(src) < sizeof(dest)) \ + dest[sizeof(src)] = '\0' + +#ifdef SIGAR_HAS_UTMPX +static int sigar_who_utmpx(sigar_t *sigar, + sigar_who_list_t *wholist) +{ + FILE *fp; + struct utmpx ut; + + if (!(fp = fopen(SIGAR_UTMPX_FILE, "r"))) { + return errno; + } + + while (fread(&ut, sizeof(ut), 1, fp) == 1) { + sigar_who_t *who; + + if (*ut.ut_user == '\0') { + continue; + } + +#ifdef UTMPX_USER_PROCESS + if (ut.ut_type != UTMPX_USER_PROCESS) { + continue; + } +#endif + + SIGAR_WHO_LIST_GROW(wholist); + who = &wholist->data[wholist->number++]; + + WHOCPY(who->user, ut.ut_user); + WHOCPY(who->device, ut.ut_line); + WHOCPY(who->host, ut.ut_host); + + who->time = ut.ut_xtime; + } + + fclose(fp); + + return SIGAR_OK; +} +#endif + +#if defined(SIGAR_NO_UTMP) && defined(SIGAR_HAS_UTMPX) +#define sigar_who_utmp sigar_who_utmpx +#else +static int sigar_who_utmp(sigar_t *sigar, + sigar_who_list_t *wholist) +{ + FILE *fp; +#ifdef __sun + /* use futmpx w/ pid32_t for sparc64 */ + struct futmpx ut; +#else + struct utmp ut; +#endif + if (!(fp = fopen(SIGAR_UTMP_FILE, "r"))) { +#ifdef SIGAR_HAS_UTMPX + /* Darwin 10.5 */ + return sigar_who_utmpx(sigar, wholist); +#endif + return errno; + } + + while (fread(&ut, sizeof(ut), 1, fp) == 1) { + sigar_who_t *who; + + if (*ut.ut_name == '\0') { + continue; + } + +#ifdef USER_PROCESS + if (ut.ut_type != USER_PROCESS) { + continue; + } +#endif + + SIGAR_WHO_LIST_GROW(wholist); + who = &wholist->data[wholist->number++]; + + WHOCPY(who->user, ut.ut_user); + WHOCPY(who->device, ut.ut_line); + WHOCPY(who->host, ut.ut_host); + + who->time = ut.ut_time; + } + + fclose(fp); + + return SIGAR_OK; +} +#endif /* SIGAR_NO_UTMP */ +#endif /* NETWARE */ + +#if defined(WIN32) + +int sigar_who_list_get_win32(sigar_t *sigar, + sigar_who_list_t *wholist); + +SIGAR_DECLARE(int) sigar_who_list_get(sigar_t *sigar, + sigar_who_list_t *wholist) +{ + sigar_who_list_create(wholist); + + /* cygwin ssh */ + sigar_who_utmp(sigar, wholist); + + sigar_who_list_get_win32(sigar, wholist); + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_resource_limit_get(sigar_t *sigar, + sigar_resource_limit_t *rlimit) +{ + MEMORY_BASIC_INFORMATION meminfo; + memset(rlimit, 0x7fffffff, sizeof(*rlimit)); + + if (VirtualQuery((LPCVOID)&meminfo, &meminfo, sizeof(meminfo))) { + rlimit->stack_cur = + (DWORD)&meminfo - (DWORD)meminfo.AllocationBase; + rlimit->stack_max = + ((DWORD)meminfo.BaseAddress + meminfo.RegionSize) - + (DWORD)meminfo.AllocationBase; + } + + rlimit->virtual_memory_max = rlimit->virtual_memory_cur = + 0x80000000UL; + + return SIGAR_OK; +} + +#elif defined(NETWARE) +int sigar_resource_limit_get(sigar_t *sigar, + sigar_resource_limit_t *rlimit) +{ + return SIGAR_ENOTIMPL; +} + +int sigar_who_list_get(sigar_t *sigar, + sigar_who_list_t *wholist) +{ + return SIGAR_ENOTIMPL; +} +#else + +#ifndef _AIX +int sigar_who_list_get(sigar_t *sigar, + sigar_who_list_t *wholist) +{ + int status; + + sigar_who_list_create(wholist); + + status = sigar_who_utmp(sigar, wholist); + if (status != SIGAR_OK) { + sigar_who_list_destroy(sigar, wholist); + return status; + } + + return SIGAR_OK; +} +#endif + +static int sigar_get_default_gateway(sigar_t *sigar, + sigar_net_info_t *netinfo) +{ + int status, i; + sigar_net_route_list_t routelist; + + status = sigar_net_route_list_get(sigar, &routelist); + if (status != SIGAR_OK) { + return status; + } + + for (i=0; idefault_gateway); + + SIGAR_STRNCPY(netinfo->default_gateway_interface, + routelist.data[i].ifname, + sizeof(netinfo->default_gateway_interface)); + break; + } + } + + sigar_net_route_list_destroy(sigar, &routelist); + + return SIGAR_OK; +} + +int sigar_net_info_get(sigar_t *sigar, + sigar_net_info_t *netinfo) +{ + int size; + char buffer[BUFSIZ], *ptr; + FILE *fp; + + SIGAR_ZERO(netinfo); + + if ((fp = fopen("/etc/resolv.conf", "r"))) { + while ((ptr = fgets(buffer, sizeof(buffer), fp))) { + int len; + + SIGAR_SKIP_SPACE(ptr); + if ((*ptr == '#') || + !(ptr = strstr(ptr, "nameserver"))) + { + continue; + } + ptr += 10; + SIGAR_SKIP_SPACE(ptr); + + len = strlen(ptr); + ptr[len-1] = '\0'; /* chop \n */ + + if (!netinfo->primary_dns[0]) { + SIGAR_SSTRCPY(netinfo->primary_dns, ptr); + } + else if (!netinfo->secondary_dns[0]) { + SIGAR_SSTRCPY(netinfo->secondary_dns, ptr); + } + else { + break; + } + } + fclose(fp); + } /* else /etc/resolv.conf may not exist if unplugged (MacOSX) */ + + size = sizeof(netinfo->host_name)-1; + if (gethostname(netinfo->host_name, size) == 0) { + netinfo->host_name[size] = '\0'; + } + else { + netinfo->host_name[0] = '\0'; + } + + size = sizeof(netinfo->domain_name)-1; + if (getdomainname(netinfo->domain_name, size) == 0) { + netinfo->domain_name[size] = '\0'; + } + else { + netinfo->domain_name[0] = '\0'; + } + + sigar_get_default_gateway(sigar, netinfo); + + return SIGAR_OK; +} + +#include + +#define OffsetOf(structure, field) \ + (size_t)(&((structure *)NULL)->field) + +#define RlimitOffsets(field) \ + OffsetOf(sigar_resource_limit_t, field##_cur), \ + OffsetOf(sigar_resource_limit_t, field##_max) + +#define RlimitSet(structure, ptr, val) \ + *(sigar_uint64_t *)((char *)structure + (int)(long)ptr) = val + +typedef struct { + int resource; + int factor; + size_t cur; + size_t max; +} rlimit_field_t; + +#ifndef RLIMIT_RSS +#define RLIMIT_RSS (RLIM_NLIMITS+1) +#endif + +#ifndef RLIMIT_NPROC +#define RLIMIT_NPROC (RLIM_NLIMITS+2) +#endif + +#define RLIMIT_PSIZE (RLIM_NLIMITS+3) + +#ifndef RLIMIT_AS +# if defined(RLIMIT_VMEM) +# define RLIMIT_AS RLIMIT_VMEM +# elif defined(RLIMIT_RSS) +# define RLIMIT_AS RLIMIT_RSS +# endif +#endif + +static rlimit_field_t sigar_rlimits[] = { + { RLIMIT_CPU, 1, RlimitOffsets(cpu) }, + { RLIMIT_FSIZE, 1024, RlimitOffsets(file_size) }, + { RLIMIT_DATA, 1024, RlimitOffsets(data) }, + { RLIMIT_STACK, 1024, RlimitOffsets(stack) }, + { RLIMIT_PSIZE, 512, RlimitOffsets(pipe_size) }, + { RLIMIT_CORE, 1024, RlimitOffsets(core) }, + { RLIMIT_RSS, 1024, RlimitOffsets(memory) }, + { RLIMIT_NPROC, 1, RlimitOffsets(processes) }, + { RLIMIT_NOFILE, 1, RlimitOffsets(open_files) }, + { RLIMIT_AS, 1024, RlimitOffsets(virtual_memory) }, + { -1 } +}; + +#define RlimitScale(val) \ + if (val != RLIM_INFINITY) val /= r->factor + +#define RlimitHS(val) \ + rl.rlim_cur = rl.rlim_max = (val) + +int sigar_resource_limit_get(sigar_t *sigar, + sigar_resource_limit_t *rlimit) +{ + int i; + + for (i=0; sigar_rlimits[i].resource != -1; i++) { + struct rlimit rl; + rlimit_field_t *r = &sigar_rlimits[i]; + + if (r->resource > RLIM_NLIMITS) { + switch (r->resource) { + case RLIMIT_NPROC: + RlimitHS(sysconf(_SC_CHILD_MAX)); + break; + case RLIMIT_PSIZE: + RlimitHS(PIPE_BUF/512); + break; + default: + RlimitHS(RLIM_INFINITY); + break; + } + } + else if (getrlimit(r->resource, &rl) != 0) { + RlimitHS(RLIM_INFINITY); + } + else { + RlimitScale(rl.rlim_cur); + RlimitScale(rl.rlim_max); + } + + RlimitSet(rlimit, r->cur, rl.rlim_cur); + RlimitSet(rlimit, r->max, rl.rlim_max); + } + + return SIGAR_OK; +} +#endif + +#if !defined(WIN32) && !defined(NETWARE) && !defined(DARWIN) && \ + !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) + +/* XXX: prolly will be moving these stuffs into os_net.c */ +#include +#include + +#ifndef SIOCGIFCONF +#include +#endif + +#if defined(_AIX) || defined(__osf__) /* good buddies */ + +#include + +static void hwaddr_aix_lookup(sigar_t *sigar, sigar_net_interface_config_t *ifconfig) +{ + char *ent, *end; + struct ifreq *ifr; + + /* XXX: assumes sigar_net_interface_list_get has been called */ + end = sigar->ifconf_buf + sigar->ifconf_len; + + for (ent = sigar->ifconf_buf; + ent < end; + ent += sizeof(*ifr)) + { + ifr = (struct ifreq *)ent; + + if (ifr->ifr_addr.sa_family != AF_LINK) { + continue; + } + + if (strEQ(ifr->ifr_name, ifconfig->name)) { + struct sockaddr_dl *sdl = (struct sockaddr_dl *)&ifr->ifr_addr; + + sigar_net_address_mac_set(ifconfig->hwaddr, + LLADDR(sdl), + sdl->sdl_alen); + return; + } + } + + sigar_hwaddr_set_null(ifconfig); +} + +#elif !defined(SIOCGIFHWADDR) + +#include + +static void hwaddr_arp_lookup(sigar_net_interface_config_t *ifconfig, int sock) +{ + struct arpreq areq; + struct sockaddr_in *sa; + + memset(&areq, 0, sizeof(areq)); + sa = (struct sockaddr_in *)&areq.arp_pa; + sa->sin_family = AF_INET; + sa->sin_addr.s_addr = ifconfig->address.addr.in; + + if (ioctl(sock, SIOCGARP, &areq) < 0) { + /* ho-hum */ + sigar_hwaddr_set_null(ifconfig); + } + else { + sigar_net_address_mac_set(ifconfig->hwaddr, + areq.arp_ha.sa_data, + SIGAR_IFHWADDRLEN); + } +} + +#endif + +#ifdef __linux__ + +#include + +#ifndef ARPHRD_CISCO /* not in 2.2 kernel headers */ +#define ARPHRD_CISCO 513 /* Cisco HDLC. */ +#endif + +static void get_interface_type(sigar_net_interface_config_t *ifconfig, + int family) +{ + char *type; + + switch (family) { + case ARPHRD_SLIP: + type = SIGAR_NIC_SLIP; + break; + case ARPHRD_CSLIP: + type = SIGAR_NIC_CSLIP; + break; + case ARPHRD_SLIP6: + type = SIGAR_NIC_SLIP6; + break; + case ARPHRD_CSLIP6: + type = SIGAR_NIC_CSLIP6; + break; + case ARPHRD_ADAPT: + type = SIGAR_NIC_ADAPTIVE; + break; + case ARPHRD_ETHER: + type = SIGAR_NIC_ETHERNET; + break; + case ARPHRD_ASH: + type = SIGAR_NIC_ASH; + break; + case ARPHRD_FDDI: + type = SIGAR_NIC_FDDI; + break; + case ARPHRD_HIPPI: + type = SIGAR_NIC_HIPPI; + break; + case ARPHRD_AX25: + type = SIGAR_NIC_AX25; + break; + case ARPHRD_ROSE: + type = SIGAR_NIC_ROSE; + break; + case ARPHRD_NETROM: + type = SIGAR_NIC_NETROM; + break; + case ARPHRD_X25: + type = SIGAR_NIC_X25; + break; + case ARPHRD_TUNNEL: + type = SIGAR_NIC_TUNNEL; + break; + case ARPHRD_PPP: + type = SIGAR_NIC_PPP; + break; + case ARPHRD_CISCO: + type = SIGAR_NIC_HDLC; + break; + case ARPHRD_LAPB: + type = SIGAR_NIC_LAPB; + break; + case ARPHRD_ARCNET: + type = SIGAR_NIC_ARCNET; + break; + case ARPHRD_DLCI: + type = SIGAR_NIC_DLCI; + break; + case ARPHRD_FRAD: + type = SIGAR_NIC_FRAD; + break; + case ARPHRD_SIT: + type = SIGAR_NIC_SIT; + break; + case ARPHRD_IRDA: + type = SIGAR_NIC_IRDA; + break; + case ARPHRD_ECONET: + type = SIGAR_NIC_EC; + break; + default: + type = SIGAR_NIC_UNSPEC; + break; + } + + SIGAR_SSTRCPY(ifconfig->type, type); +} + +#endif + +int sigar_net_interface_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig) +{ + int sock; + struct ifreq ifr; + + if (!name) { + return sigar_net_interface_config_primary_get(sigar, ifconfig); + } + + SIGAR_ZERO(ifconfig); + + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + return errno; + } + + SIGAR_SSTRCPY(ifconfig->name, name); + SIGAR_SSTRCPY(ifr.ifr_name, name); + +#define ifr_s_addr(ifr) \ + ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr + + if (!ioctl(sock, SIOCGIFADDR, &ifr)) { + sigar_net_address_set(ifconfig->address, + ifr_s_addr(ifr)); + } + + if (!ioctl(sock, SIOCGIFNETMASK, &ifr)) { + sigar_net_address_set(ifconfig->netmask, + ifr_s_addr(ifr)); + } + + if (!ioctl(sock, SIOCGIFFLAGS, &ifr)) { + sigar_uint64_t flags = ifr.ifr_flags; +#ifdef __linux__ +# ifndef IFF_DYNAMIC +# define IFF_DYNAMIC 0x8000 /* not in 2.2 kernel */ +# endif /* IFF_DYNAMIC */ + int is_mcast = flags & IFF_MULTICAST; + int is_slave = flags & IFF_SLAVE; + int is_master = flags & IFF_MASTER; + int is_dynamic = flags & IFF_DYNAMIC; + /* + * XXX: should just define SIGAR_IFF_* + * and test IFF_* bits on given platform. + * this is the only diff between solaris/hpux/linux + * for the flags we care about. + * + */ + flags &= ~(IFF_MULTICAST|IFF_SLAVE|IFF_MASTER); + if (is_mcast) { + flags |= SIGAR_IFF_MULTICAST; + } + if (is_slave) { + flags |= SIGAR_IFF_SLAVE; + } + if (is_master) { + flags |= SIGAR_IFF_MASTER; + } + if (is_dynamic) { + flags |= SIGAR_IFF_DYNAMIC; + } +#endif + ifconfig->flags = flags; + } + else { + /* should always be able to get flags for existing device */ + /* other ioctls may fail if device is not enabled: ok */ + close(sock); + return errno; + } + + if (ifconfig->flags & IFF_LOOPBACK) { + sigar_net_address_set(ifconfig->destination, + ifconfig->address.addr.in); + sigar_net_address_set(ifconfig->broadcast, 0); + sigar_hwaddr_set_null(ifconfig); + SIGAR_SSTRCPY(ifconfig->type, + SIGAR_NIC_LOOPBACK); + } + else { + if (!ioctl(sock, SIOCGIFDSTADDR, &ifr)) { + sigar_net_address_set(ifconfig->destination, + ifr_s_addr(ifr)); + } + + if (!ioctl(sock, SIOCGIFBRDADDR, &ifr)) { + sigar_net_address_set(ifconfig->broadcast, + ifr_s_addr(ifr)); + } + +#if defined(SIOCGIFHWADDR) + if (!ioctl(sock, SIOCGIFHWADDR, &ifr)) { + get_interface_type(ifconfig, + ifr.ifr_hwaddr.sa_family); + sigar_net_address_mac_set(ifconfig->hwaddr, + ifr.ifr_hwaddr.sa_data, + IFHWADDRLEN); + } +#elif defined(_AIX) || defined(__osf__) + hwaddr_aix_lookup(sigar, ifconfig); + SIGAR_SSTRCPY(ifconfig->type, + SIGAR_NIC_ETHERNET); +#else + hwaddr_arp_lookup(ifconfig, sock); + SIGAR_SSTRCPY(ifconfig->type, + SIGAR_NIC_ETHERNET); +#endif + } + +#if defined(SIOCGLIFMTU) && !defined(__hpux) + { + struct lifreq lifr; + SIGAR_SSTRCPY(lifr.lifr_name, name); + if(!ioctl(sock, SIOCGLIFMTU, &lifr)) { + ifconfig->mtu = lifr.lifr_mtu; + } + } +#elif defined(SIOCGIFMTU) + if (!ioctl(sock, SIOCGIFMTU, &ifr)) { +# if defined(__hpux) + ifconfig->mtu = ifr.ifr_metric; +# else + ifconfig->mtu = ifr.ifr_mtu; +#endif + } +#else + ifconfig->mtu = 0; /*XXX*/ +#endif + + if (!ioctl(sock, SIOCGIFMETRIC, &ifr)) { + ifconfig->metric = ifr.ifr_metric ? ifr.ifr_metric : 1; + } + +#if defined(SIOCGIFTXQLEN) + if (!ioctl(sock, SIOCGIFTXQLEN, &ifr)) { + ifconfig->tx_queue_len = ifr.ifr_qlen; + } + else { + ifconfig->tx_queue_len = -1; /* net-tools behaviour */ + } +#else + ifconfig->tx_queue_len = -1; +#endif + + close(sock); + + /* XXX can we get a better description like win32? */ + SIGAR_SSTRCPY(ifconfig->description, + ifconfig->name); + + sigar_net_interface_ipv6_config_init(ifconfig); + sigar_net_interface_ipv6_config_get(sigar, name, ifconfig); + + return SIGAR_OK; +} + +#ifdef _AIX +# define MY_SIOCGIFCONF CSIOCGIFCONF +#else +# define MY_SIOCGIFCONF SIOCGIFCONF +#endif + +#ifdef __osf__ +static int sigar_netif_configured(sigar_t *sigar, char *name) +{ + int status; + sigar_net_interface_config_t ifconfig; + + status = sigar_net_interface_config_get(sigar, name, &ifconfig); + + return status == SIGAR_OK; +} +#endif + +#ifdef __linux__ +static SIGAR_INLINE int has_interface(sigar_net_interface_list_t *iflist, + char *name) +{ + register int i; + register int num = iflist->number; + register char **data = iflist->data; + for (i=0; idata[iflist->number++] = + sigar_strdup(dev); + } + + fclose(fp); + + return SIGAR_OK; +} +#endif + +int sigar_net_interface_list_get(sigar_t *sigar, + sigar_net_interface_list_t *iflist) +{ + int n, lastlen=0; + struct ifreq *ifr; + struct ifconf ifc; + int sock = socket(AF_INET, SOCK_DGRAM, 0); + + if (sock < 0) { + return errno; + } + + for (;;) { + if (!sigar->ifconf_buf || lastlen) { + sigar->ifconf_len += sizeof(struct ifreq) * SIGAR_NET_IFLIST_MAX; + sigar->ifconf_buf = realloc(sigar->ifconf_buf, sigar->ifconf_len); + } + + ifc.ifc_len = sigar->ifconf_len; + ifc.ifc_buf = sigar->ifconf_buf; + + if (ioctl(sock, MY_SIOCGIFCONF, &ifc) < 0) { + /* EINVAL should mean num_interfaces > ifc.ifc_len */ + if ((errno != EINVAL) || + (lastlen == ifc.ifc_len)) + { + free(ifc.ifc_buf); + return errno; + } + } + + if (ifc.ifc_len < sigar->ifconf_len) { + break; /* got em all */ + } + + if (ifc.ifc_len != lastlen) { + /* might be more */ + lastlen = ifc.ifc_len; + continue; + } + + break; + } + + close(sock); + + iflist->number = 0; + iflist->size = ifc.ifc_len; + iflist->data = malloc(sizeof(*(iflist->data)) * + iflist->size); + + ifr = ifc.ifc_req; + for (n = 0; n < ifc.ifc_len; n += sizeof(struct ifreq), ifr++) { +#if defined(_AIX) || defined(__osf__) /* pass the bourbon */ + if (ifr->ifr_addr.sa_family != AF_LINK) { + /* XXX: dunno if this is right. + * otherwise end up with two 'en0' and three 'lo0' + * with the same ip address. + */ + continue; + } +# ifdef __osf__ + /* weed out "sl0", "tun0" and the like */ + /* XXX must be a better way to check this */ + if (!sigar_netif_configured(sigar, ifr->ifr_name)) { + continue; + } +# endif +#endif + iflist->data[iflist->number++] = + sigar_strdup(ifr->ifr_name); + } + +#ifdef __linux__ + proc_net_interface_list_get(sigar, iflist); +#endif + + return SIGAR_OK; +} + +#endif /* WIN32 */ + +SIGAR_DECLARE(int) +sigar_net_interface_config_primary_get(sigar_t *sigar, + sigar_net_interface_config_t *ifconfig) +{ + int i, status, found=0; + sigar_net_interface_list_t iflist; + sigar_net_interface_config_t possible_config; + + possible_config.flags = 0; + + if ((status = sigar_net_interface_list_get(sigar, &iflist)) != SIGAR_OK) { + return status; + } + + for (i=0; iflags & SIGAR_IFF_LOOPBACK) || + !ifconfig->hwaddr.addr.in) /* no mac address */ + { + continue; + } + + if (!possible_config.flags) { + /* save for later for use if we're not connected to the net + * or all interfaces are aliases (e.g. solaris zone) + */ + memcpy(&possible_config, ifconfig, sizeof(*ifconfig)); + } + if (!ifconfig->address.addr.in) { + continue; /* no ip address */ + } + if (strchr(iflist.data[i], ':')) { + continue; /* alias */ + } + + found = 1; + break; + } + + sigar_net_interface_list_destroy(sigar, &iflist); + + if (found) { + return SIGAR_OK; + } + else if (possible_config.flags) { + memcpy(ifconfig, &possible_config, sizeof(*ifconfig)); + return SIGAR_OK; + } + else { + return SIGAR_ENXIO; + } +} + +static int fqdn_ip_get(sigar_t *sigar, char *name) +{ + sigar_net_interface_config_t ifconfig; + int status; + + status = sigar_net_interface_config_primary_get(sigar, &ifconfig); + + if (status != SIGAR_OK) { + return status; + } + if (!ifconfig.address.addr.in) { + return SIGAR_ENXIO; + } + + sigar_net_address_to_string(sigar, &ifconfig.address, name); + + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[fqdn] using ip address '%s' for fqdn", + name); + + return SIGAR_OK; +} + +struct hostent *sigar_gethostbyname(const char *name, + sigar_hostent_t *data) +{ + struct hostent *hp = NULL; + +#if defined(__linux__) + gethostbyname_r(name, &data->hs, + data->buffer, sizeof(data->buffer), + &hp, &data->error); +#elif defined(__sun) + hp = gethostbyname_r(name, &data->hs, + data->buffer, sizeof(data->buffer), + &data->error); +#elif defined(SIGAR_HAS_HOSTENT_DATA) + if (gethostbyname_r(name, &data->hs, &data->hd) == 0) { + hp = &data->hs; + } + else { + data->error = h_errno; + } +#else + hp = gethostbyname(name); +#endif + + return hp; +} + +static struct hostent *sigar_gethostbyaddr(const char *addr, + int len, int type, + sigar_hostent_t *data) +{ + struct hostent *hp = NULL; + +#if defined(__linux__) + gethostbyaddr_r(addr, len, type, + &data->hs, + data->buffer, sizeof(data->buffer), + &hp, &data->error); +#elif defined(__sun) + hp = gethostbyaddr_r(addr, len, type, + &data->hs, + data->buffer, sizeof(data->buffer), + &data->error); +#elif defined(SIGAR_HAS_HOSTENT_DATA) + if (gethostbyaddr_r((char *)addr, len, type, + &data->hs, &data->hd) == 0) + { + hp = &data->hs; + } + else { + data->error = h_errno; + } +#else + if (!(hp = gethostbyaddr(addr, len, type))) { + data->error = h_errno; + } +#endif + + return hp; +} +#define IS_FQDN(name) \ + (name && strchr(name, '.')) + +#define IS_FQDN_MATCH(lookup, name) \ + (IS_FQDN(lookup) && strnEQ(lookup, name, strlen(name))) + +#define FQDN_SET(fqdn) \ + SIGAR_STRNCPY(name, fqdn, namelen) + +SIGAR_DECLARE(int) sigar_fqdn_get(sigar_t *sigar, char *name, int namelen) +{ + register int is_debug = SIGAR_LOG_IS_DEBUG(sigar); + sigar_hostent_t data; + struct hostent *p; + char domain[SIGAR_FQDN_LEN + 1]; +#ifdef WIN32 + int status = sigar_wsa_init(sigar); + + if (status != SIGAR_OK) { + return status; + } +#endif + + if (gethostname(name, namelen - 1) != 0) { + sigar_log_printf(sigar, SIGAR_LOG_ERROR, + "[fqdn] gethostname failed: %s", + sigar_strerror(sigar, errno)); + return errno; + } + else { + if (is_debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[fqdn] gethostname()=='%s'", + name); + } + } + + if (!(p = sigar_gethostbyname(name, &data))) { + if (is_debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[fqdn] gethostbyname(%s) failed: %s", + name, sigar_strerror(sigar, errno)); + } + + if (!IS_FQDN(name)) { + fqdn_ip_get(sigar, name); + } + + return SIGAR_OK; + } + + if (IS_FQDN_MATCH(p->h_name, name)) { + FQDN_SET(p->h_name); + + sigar_log(sigar, SIGAR_LOG_DEBUG, + "[fqdn] resolved using gethostbyname.h_name"); + + return SIGAR_OK; + } + else { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[fqdn] unresolved using gethostbyname.h_name"); + } + + if (p->h_aliases) { + int i; + + for (i=0; p->h_aliases[i]; i++) { + if (IS_FQDN_MATCH(p->h_aliases[i], name)) { + FQDN_SET(p->h_aliases[i]); + + sigar_log(sigar, SIGAR_LOG_DEBUG, + "[fqdn] resolved using gethostbyname.h_aliases"); + + return SIGAR_OK; + } + else if (is_debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[fqdn] gethostbyname(%s).alias[%d]=='%s'", + name, i, p->h_aliases[i]); + } + } + } + + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[fqdn] unresolved using gethostbyname.h_aliases"); + + if (p->h_addr_list) { + int i,j; + + for (i=0; p->h_addr_list[i]; i++) { + char addr[SIGAR_INET6_ADDRSTRLEN]; + struct in_addr *in = + (struct in_addr *)p->h_addr_list[i]; + + struct hostent *q = + sigar_gethostbyaddr(p->h_addr_list[i], + p->h_length, + p->h_addrtype, + &data); + + if (is_debug) { + sigar_inet_ntoa(sigar, in->s_addr, addr); + } + + if (!q) { + if (is_debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[fqdn] gethostbyaddr(%s) failed: %s", + addr, + sigar_strerror(sigar, errno)); + } + continue; + } + + if (IS_FQDN_MATCH(q->h_name, name)) { + FQDN_SET(q->h_name); + + sigar_log(sigar, SIGAR_LOG_DEBUG, + "[fqdn] resolved using gethostbyaddr.h_name"); + + return SIGAR_OK; + } + else { + if (is_debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[fqdn] gethostbyaddr(%s)=='%s'", + addr, q->h_name); + } + + for (j=0; q->h_aliases[j]; j++) { + if (IS_FQDN_MATCH(q->h_aliases[j], name)) { + FQDN_SET(q->h_aliases[j]); + + sigar_log(sigar, SIGAR_LOG_DEBUG, + "[fqdn] resolved using " + "gethostbyaddr.h_aliases"); + + return SIGAR_OK; + } + else if (is_debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[fqdn] gethostbyaddr(%s).alias[%d]=='%s'", + addr, j, q->h_aliases[j]); + } + } + } + } + } + + sigar_log(sigar, SIGAR_LOG_DEBUG, + "[fqdn] unresolved using gethostbyname.h_addr_list"); + +#if !defined(WIN32) && !defined(NETWARE) + if (!IS_FQDN(name) && /* e.g. aix gethostname is already fqdn */ + (getdomainname(domain, sizeof(domain) - 1) == 0) && + (domain[0] != '\0') && + (domain[0] != '(')) /* linux default is "(none)" */ + { + /* sprintf(name, "%s.%s", name, domain); */ + char *ptr = name; + int len = strlen(name); + ptr += len; + *ptr++ = '.'; + namelen -= (len+1); + SIGAR_STRNCPY(ptr, domain, namelen); + + sigar_log(sigar, SIGAR_LOG_DEBUG, + "[fqdn] resolved using getdomainname"); + } + else { + sigar_log(sigar, SIGAR_LOG_DEBUG, + "[fqdn] getdomainname failed"); + } +#endif + + if (!IS_FQDN(name)) { + fqdn_ip_get(sigar, name); + } + + return SIGAR_OK; +} + +#ifndef MAX_STRING_LEN +#define MAX_STRING_LEN 8192 +#endif + +#ifdef WIN32 +/* The windows version of getPasswordNative was lifted from apr */ +SIGAR_DECLARE(char *) sigar_password_get(const char *prompt) +{ + static char password[MAX_STRING_LEN]; + int n = 0; + int ch; + + fputs(prompt, stderr); + fflush(stderr); + + while ((ch = _getch()) != '\r') { + if (ch == EOF) /* EOF */ { + return NULL; + } + else if (ch == 0 || ch == 0xE0) { + /* FN Keys (0 or E0) are a sentinal for a FN code */ + ch = (ch << 4) | _getch(); + /* Catch {DELETE}, {<--}, Num{DEL} and Num{<--} */ + if ((ch == 0xE53 || ch == 0xE4B || ch == 0x053 || ch == 0x04b) && n) { + password[--n] = '\0'; + fputs("\b \b", stderr); + fflush(stderr); + } + else { + fputc('\a', stderr); + fflush(stderr); + } + } + else if ((ch == '\b' || ch == 127) && n) /* BS/DEL */ { + password[--n] = '\0'; + fputs("\b \b", stderr); + fflush(stderr); + } + else if (ch == 3) /* CTRL+C */ { + /* _getch() bypasses Ctrl+C but not Ctrl+Break detection! */ + fputs("^C\n", stderr); + fflush(stderr); + exit(-1); + } + else if (ch == 26) /* CTRL+Z */ { + fputs("^Z\n", stderr); + fflush(stderr); + return NULL; + } + else if (ch == 27) /* ESC */ { + fputc('\n', stderr); + fputs(prompt, stderr); + fflush(stderr); + n = 0; + } + else if ((n < sizeof(password) - 1) && !iscntrl(ch)) { + password[n++] = ch; + fputc(' ', stderr); + fflush(stderr); + } + else { + fputc('\a', stderr); + fflush(stderr); + } + } + + fputc('\n', stderr); + fflush(stderr); + password[n] = '\0'; + + return password; +} + +#else + +/* linux/hpux/solaris getpass() prototype lives here */ +#include + +#include + +/* from apr_getpass.c */ + +#if defined(SIGAR_HPUX) +# define getpass termios_getpass +#elif defined(SIGAR_SOLARIS) +# define getpass getpassphrase +#endif + +#ifdef SIGAR_HPUX +static char *termios_getpass(const char *prompt) +{ + struct termios attr; + static char password[MAX_STRING_LEN]; + unsigned int n=0; + + fputs(prompt, stderr); + fflush(stderr); + + if (tcgetattr(STDIN_FILENO, &attr) != 0) { + return NULL; + } + + attr.c_lflag &= ~(ECHO); + + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &attr) != 0) { + return NULL; + } + + while ((password[n] = getchar()) != '\n') { + if (n < (sizeof(password) - 1) && + (password[n] >= ' ') && + (password[n] <= '~')) + { + n++; + } + else { + fprintf(stderr, "\n"); + fputs(prompt, stderr); + fflush(stderr); + n = 0; + } + } + + password[n] = '\0'; + printf("\n"); + + if (n > (MAX_STRING_LEN - 1)) { + password[MAX_STRING_LEN - 1] = '\0'; + } + + attr.c_lflag |= ECHO; + tcsetattr(STDIN_FILENO, TCSANOW, &attr); + + return (char *)&password; +} +#endif + +SIGAR_DECLARE(char *) sigar_password_get(const char *prompt) +{ + char *buf = NULL; + + /* the linux version of getpass prints the prompt to the tty; ok. + * the solaris version prints the prompt to stderr; not ok. + * so print the prompt to /dev/tty ourselves if possible (always should be) + */ + + FILE *tty = NULL; + + if ((tty = fopen("/dev/tty", "w"))) { + fprintf(tty, "%s", prompt); + fflush(tty); + + buf = getpass(tty ? "" : prompt); + fclose(tty); + } + + return buf; +} + +#endif /* WIN32 */ diff --git a/vendor/sigar/src/sigar_cache.c b/vendor/sigar/src/sigar_cache.c new file mode 100644 index 0000000..8d64016 --- /dev/null +++ b/vendor/sigar/src/sigar_cache.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2004-2006 Hyperic, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_util.h" +#include +/* + * hash table to cache values where key is a unique number + * such as: + * pid -> some process data + * uid -> user name + * gid -> group name + */ + +#define ENTRIES_SIZE(n) \ + (sizeof(sigar_cache_entry_t *) * (n)) + +/* wrap free() for use w/ dmalloc */ +static void free_value(void *ptr) +{ + free(ptr); +} + +sigar_cache_t *sigar_cache_new(int size) +{ + sigar_cache_t *table = malloc(sizeof(*table)); + table->count = 0; + table->size = size; + table->entries = malloc(ENTRIES_SIZE(size)); + memset(table->entries, '\0', ENTRIES_SIZE(size)); + table->free_value = free_value; + return table; +} + +#ifdef DEBUG_CACHE +/* see how well entries are distributed */ +static void sigar_cache_dump(sigar_cache_t *table) +{ + int i; + sigar_cache_entry_t **entries = table->entries; + + for (i=0; isize; i++) { + sigar_cache_entry_t *entry = *entries++; + + printf("|"); + while (entry) { + printf("%lld", entry->id); + if (entry->next) { + printf(","); + } + entry = entry->next; + } + } + printf("\n"); + fflush(stdout); +} +#endif + +static void sigar_cache_rehash(sigar_cache_t *table) +{ + int i; + unsigned int new_size = table->size * 2 + 1; + sigar_cache_entry_t **entries = table->entries; + sigar_cache_entry_t **new_entries = + malloc(ENTRIES_SIZE(new_size)); + + memset(new_entries, '\0', ENTRIES_SIZE(new_size)); + + for (i=0; isize; i++) { + sigar_cache_entry_t *entry = *entries++; + + while (entry) { + sigar_cache_entry_t *next = entry->next; + sigar_uint64_t hash = entry->id % new_size; + + entry->next = new_entries[hash]; + new_entries[hash] = entry; + entry = next; + } + } + + free(table->entries); + table->entries = new_entries; + table->size = new_size; +} + +#define SIGAR_CACHE_IX(t, k) \ + t->entries + (k % t->size) + +sigar_cache_entry_t *sigar_cache_find(sigar_cache_t *table, + sigar_uint64_t key) +{ + sigar_cache_entry_t *entry, **ptr; + + for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr; + entry; + ptr = &entry->next, entry = *ptr) + { + if (entry->id == key) { + return entry; + } + } + + return NULL; +} + +/* create entry if it does not exist */ +sigar_cache_entry_t *sigar_cache_get(sigar_cache_t *table, + sigar_uint64_t key) +{ + sigar_cache_entry_t *entry, **ptr; + + for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr; + entry; + ptr = &entry->next, entry = *ptr) + { + if (entry->id == key) { + return entry; + } + } + + if (table->count++ > table->size) { + sigar_cache_rehash(table); + + for (ptr = SIGAR_CACHE_IX(table, key), entry = *ptr; + entry; + ptr = &entry->next, entry = *ptr) + { + } + } + + *ptr = entry = malloc(sizeof(*entry)); + entry->id = key; + entry->value = NULL; + entry->next = NULL; + + return entry; +} + +void sigar_cache_destroy(sigar_cache_t *table) +{ + int i; + sigar_cache_entry_t **entries = table->entries; + +#ifdef DEBUG_CACHE + sigar_cache_dump(table); +#endif + + for (i=0; isize; i++) { + sigar_cache_entry_t *entry, *ptr; + entry = *entries++; + + while (entry) { + if (entry->value) { + table->free_value(entry->value); + } + ptr = entry->next; + free(entry); + entry = ptr; + } + } + + free(table->entries); + free(table); +} diff --git a/vendor/sigar/src/sigar_fileinfo.c b/vendor/sigar/src/sigar_fileinfo.c new file mode 100644 index 0000000..adde8c0 --- /dev/null +++ b/vendor/sigar/src/sigar_fileinfo.c @@ -0,0 +1,815 @@ +/* + * Copyright (c) 2004-2005, 2007-2008 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2010 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* ==================================================================== + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000-2003 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The names "Apache" and "Apache Software Foundation" must + * not be used to endorse or promote products derived from this + * software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache", + * nor may "Apache" appear in their name, without prior written + * permission of the Apache Software Foundation. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + */ + +#ifndef WIN32 +# ifdef _AIX +# define _LARGE_FILES +# else +# define _FILE_OFFSET_BITS 64 +# define _LARGEFILE64_SOURCE +# endif +#endif + +#include "sigar.h" + +#ifndef WIN32 +#if defined(__FreeBSD__) || defined(__OpenBSD__) +# include +# include +#else +# include +# define HAVE_STATVFS +#endif +#include + +#define SIGAR_FS_BLOCKS_TO_BYTES(val, bsize) ((val * bsize) >> 1) + +int sigar_statvfs(sigar_t *sigar, + const char *dirname, + sigar_file_system_usage_t *fsusage) +{ + sigar_uint64_t val, bsize; +#ifdef HAVE_STATVFS + struct statvfs buf; + int status = +# if defined(__sun) && !defined(_LP64) + /* http://bugs.opensolaris.org/view_bug.do?bug_id=4462986 */ + statvfs(dirname, (void *)&buf); +# else + statvfs(dirname, &buf); +# endif +#else + struct statfs buf; + int status = statfs(dirname, &buf); +#endif + + if (status != 0) { + return errno; + } + +#ifdef HAVE_STATVFS + bsize = buf.f_frsize / 512; +#else + bsize = buf.f_bsize / 512; +#endif + val = buf.f_blocks; + fsusage->total = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize); + val = buf.f_bfree; + fsusage->free = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize); + val = buf.f_bavail; + fsusage->avail = SIGAR_FS_BLOCKS_TO_BYTES(val, bsize); + fsusage->used = fsusage->total - fsusage->free; + fsusage->files = buf.f_files; + fsusage->free_files = buf.f_ffree; + + return SIGAR_OK; +} +#endif + +/* + * whittled down version of apr/file_info/{unix,win32}/filestat.c + * to fillin sigar_fileattrs_t + */ +#include "sigar_fileinfo.h" +#include "sigar_log.h" + +#ifndef SIGAR_ZERO +#define SIGAR_ZERO(s) \ + memset(s, '\0', sizeof(*(s))) +#endif + +#ifdef WIN32 +#include +sigar_uint64_t sigar_FileTimeToTime(FILETIME *ft); +#else +#include +#endif + +static const char* types[] = { + "none", + "regular", + "directory", + "character device", + "block device", + "pipe", + "symbolic link", + "socket", + "unknown" +}; + +SIGAR_DECLARE(const char *) +sigar_file_attrs_type_string_get(sigar_file_type_e type) +{ + if ((type < SIGAR_FILETYPE_NOFILE) || + (type > SIGAR_FILETYPE_UNKFILE)) + { + type = SIGAR_FILETYPE_UNKFILE; + } + + return types[type]; +} + +static const sigar_uint64_t perm_modes[] = { + SIGAR_UREAD, SIGAR_UWRITE, SIGAR_UEXECUTE, + SIGAR_GREAD, SIGAR_GWRITE, SIGAR_GEXECUTE, + SIGAR_WREAD, SIGAR_WWRITE, SIGAR_WEXECUTE +}; + +static const char perm_chars[] = "rwx"; + +SIGAR_DECLARE(char *) +sigar_file_attrs_permissions_string_get(sigar_uint64_t permissions, + char *str) +{ + char *ptr = str; + int i=0, j=0; + + for (i=0; i<9; i+=3) { + for (j=0; j<3; j++) { + if (permissions & perm_modes[i+j]) { + *ptr = perm_chars[j]; + } + else { + *ptr = '-'; + } + ptr++; + } + } + + *ptr = '\0'; + return str; +} + +static const int perm_int[] = { + 400, 200, 100, + 40, 20, 10, + 4, 2, 1 +}; + +SIGAR_DECLARE(int)sigar_file_attrs_mode_get(sigar_uint64_t permissions) +{ + int i=0; + int perms = 0; + + /* no doubt there is some fancy bitshifting + * to convert, but this works fine. + */ + for (i=0; i<9; i++) { + if (permissions & perm_modes[i]) { + perms += perm_int[i]; + } + } + + return perms; +} + +#define IS_DOTDIR(dir) \ + ((dir[0] == '.') && (!dir[1] || ((dir[1] == '.') && !dir[2]))) + +#define DIR_STAT_WARN() \ + sigar_log_printf(sigar, SIGAR_LOG_WARN, \ + "dir_stat: cannot stat `%s': %s", \ + name, \ + sigar_strerror(sigar, status)) + +#if defined(NETWARE) + +int sigar_dir_stat_get(sigar_t *sigar, + const char *dir, + sigar_dir_stat_t *dirstats) +{ + return SIGAR_ENOTIMPL; +} + +int sigar_file_attrs_get(sigar_t *sigar, + const char *file, + sigar_file_attrs_t *fileattrs) +{ + return SIGAR_ENOTIMPL; +} + +int sigar_link_attrs_get(sigar_t *sigar, + const char *file, + sigar_file_attrs_t *fileattrs) +{ + return SIGAR_ENOTIMPL; +} + +#elif defined(WIN32) + +#include +#include + +static void fillin_fileattrs(sigar_file_attrs_t *finfo, + WIN32_FILE_ATTRIBUTE_DATA *wininfo, + int linkinfo) +{ + DWORD *sizes = &wininfo->nFileSizeHigh; + + finfo->atime = sigar_FileTimeToTime(&wininfo->ftLastAccessTime) / 1000; + finfo->ctime = sigar_FileTimeToTime(&wininfo->ftCreationTime) / 1000; + finfo->mtime = sigar_FileTimeToTime(&wininfo->ftLastWriteTime) / 1000; + + finfo->size = + (sigar_uint64_t)sizes[1] | ((sigar_uint64_t)sizes[0] << 32); + + if (linkinfo && + (wininfo->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { + finfo->type = SIGAR_FILETYPE_LNK; + } + else if (wininfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + finfo->type = SIGAR_FILETYPE_DIR; + } + else { + finfo->type = SIGAR_FILETYPE_REG; + } +} + +static sigar_uint64_t convert_perms(ACCESS_MASK acc, sigar_uint64_t scope) +{ + sigar_uint64_t perms = 0; + if (acc & FILE_EXECUTE) { + perms |= SIGAR_WEXECUTE; + } + if (acc & FILE_WRITE_DATA) { + perms |= SIGAR_WWRITE; + } + if (acc & FILE_READ_DATA) { + perms |= SIGAR_WREAD; + } + + return (perms << scope); +} + +static int get_security_info(sigar_t *sigar, + const char *file, + sigar_file_attrs_t *fileattrs) +{ + DWORD retval; + PSID user = NULL, group = NULL, world = NULL; + PACL dacl = NULL; + PSECURITY_DESCRIPTOR pdesc = NULL; + SECURITY_INFORMATION sinfo = + OWNER_SECURITY_INFORMATION | + GROUP_SECURITY_INFORMATION | + DACL_SECURITY_INFORMATION; + TRUSTEE ident = {NULL, NO_MULTIPLE_TRUSTEE, TRUSTEE_IS_SID}; + ACCESS_MASK acc; + SID_IDENTIFIER_AUTHORITY auth = SECURITY_WORLD_SID_AUTHORITY; + + retval = GetNamedSecurityInfo((char *)file, + SE_FILE_OBJECT, + sinfo, + &user, + &group, + &dacl, + NULL, + &pdesc); + + if (retval != ERROR_SUCCESS) { + return retval; + } + + if (!AllocateAndInitializeSid(&auth, 1, SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, &world)) + { + world = NULL; + } + + ident.TrusteeType = TRUSTEE_IS_USER; + ident.ptstrName = user; + if (GetEffectiveRightsFromAcl(dacl, &ident, &acc) == ERROR_SUCCESS) { + fileattrs->permissions |= convert_perms(acc, 8); + } + + ident.TrusteeType = TRUSTEE_IS_GROUP; + ident.ptstrName = group; + if (GetEffectiveRightsFromAcl(dacl, &ident, &acc) == ERROR_SUCCESS) { + fileattrs->permissions |= convert_perms(acc, 4); + } + + if (world) { + ident.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; + ident.ptstrName = world; + if (GetEffectiveRightsFromAcl(dacl, &ident, &acc) == ERROR_SUCCESS) { + fileattrs->permissions |= convert_perms(acc, 0); + } + } + + if (world) { + FreeSid(world); + } + + LocalFree(pdesc); + + return SIGAR_OK; +} + +static int fileattrs_get(sigar_t *sigar, + const char *file, + sigar_file_attrs_t *fileattrs, + int linkinfo) +{ + BY_HANDLE_FILE_INFORMATION info; + WIN32_FILE_ATTRIBUTE_DATA attrs; + HANDLE handle; + DWORD flags; + + SIGAR_ZERO(fileattrs); + + if (!GetFileAttributesExA(file, + GetFileExInfoStandard, + &attrs)) + { + return GetLastError(); + } + + fillin_fileattrs(fileattrs, &attrs, linkinfo); + + flags = fileattrs->type == SIGAR_FILETYPE_DIR ? + FILE_FLAG_BACKUP_SEMANTICS : + FILE_ATTRIBUTE_NORMAL; + + /** + * We need to set dwDesiredAccess to 0 to work in cases where GENERIC_READ can fail. + * + * see: http://msdn.microsoft.com/en-us/library/aa363858(VS.85).aspx + */ + handle = CreateFile(file, + 0, + 0, + NULL, + OPEN_EXISTING, + flags, + NULL); + + if (handle != INVALID_HANDLE_VALUE) { + if (GetFileInformationByHandle(handle, &info)) { + fileattrs->inode = + info.nFileIndexLow | + (info.nFileIndexHigh << 32); + fileattrs->device = info.dwVolumeSerialNumber; + fileattrs->nlink = info.nNumberOfLinks; + } + CloseHandle(handle); + } + + get_security_info(sigar, file, fileattrs); + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_file_attrs_get(sigar_t *sigar, + const char *file, + sigar_file_attrs_t *fileattrs) +{ + return fileattrs_get(sigar, file, fileattrs, 0); +} + +SIGAR_DECLARE(int) sigar_link_attrs_get(sigar_t *sigar, + const char *file, + sigar_file_attrs_t *fileattrs) +{ + return fileattrs_get(sigar, file, fileattrs, 1); +} + +static __inline int file_type(char *file) +{ + WIN32_FILE_ATTRIBUTE_DATA attrs; + + if (!GetFileAttributesExA(file, + GetFileExInfoStandard, + &attrs)) + { + return -1; + } + + if (attrs.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + return SIGAR_FILETYPE_LNK; + } + else if (attrs.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + return SIGAR_FILETYPE_DIR; + } + else { + return SIGAR_FILETYPE_REG; + } +} + +static int dir_stat_get(sigar_t *sigar, + const char *dir, + sigar_dir_stat_t *dirstats, + int recurse) +{ + int status; + char name[SIGAR_PATH_MAX+1]; + int len = strlen(dir); + int max = sizeof(name)-len-1; + char *ptr = name; + WIN32_FIND_DATA data; + HANDLE handle; + DWORD error; + char delim; + + if (file_type((char *)dir) != SIGAR_FILETYPE_DIR) { + return ERROR_NO_MORE_FILES; + } + + strncpy(name, dir, sizeof(name)); + ptr += len; + if (strchr(dir, '/')) { + delim = '/'; + } + else { + delim = '\\'; + } + if (name[len] != delim) { + *ptr++ = delim; + len++; + max--; + } + + /* e.g. "C:\sigar\*" */ + name[len] = '*'; + name[len+1] = '\0'; + + handle = FindFirstFile(name, &data); + if (handle == INVALID_HANDLE_VALUE) { + return GetLastError(); + } + + do { + /* skip '.' and '..' */ + if (IS_DOTDIR(data.cFileName)) { + continue; + } + + dirstats->disk_usage += + (data.nFileSizeHigh * (MAXDWORD+1)) + + data.nFileSizeLow; + + /* e.g. "C:\sigar\lib" */ + strncpy(ptr, data.cFileName, max); + ptr[max] = '\0'; + + switch (file_type(name)) { + case -1: + break; + case SIGAR_FILETYPE_REG: + ++dirstats->files; + break; + case SIGAR_FILETYPE_DIR: + ++dirstats->subdirs; + if (recurse) { + status = + dir_stat_get(sigar, name, + dirstats, recurse); + if (status != SIGAR_OK) { + DIR_STAT_WARN(); + } + } + break; + case SIGAR_FILETYPE_LNK: + ++dirstats->symlinks; + break; + case SIGAR_FILETYPE_CHR: + ++dirstats->chrdevs; + break; + case SIGAR_FILETYPE_BLK: + ++dirstats->blkdevs; + break; + case SIGAR_FILETYPE_SOCK: + ++dirstats->sockets; + break; + default: + ++dirstats->total; + } + } while (FindNextFile(handle, &data)); + + error = GetLastError(); + + FindClose(handle); + + if (error != ERROR_NO_MORE_FILES) { + return error; + } + + dirstats->total = + dirstats->files + + dirstats->subdirs + + dirstats->symlinks + + dirstats->chrdevs + + dirstats->blkdevs + + dirstats->sockets; + + return SIGAR_OK; +} + +#else + +#include +#include +#include +#include + +static sigar_file_type_e filetype_from_mode(mode_t mode) +{ + sigar_file_type_e type; + + switch (mode & S_IFMT) { + case S_IFREG: + type = SIGAR_FILETYPE_REG; break; + case S_IFDIR: + type = SIGAR_FILETYPE_DIR; break; + case S_IFLNK: + type = SIGAR_FILETYPE_LNK; break; + case S_IFCHR: + type = SIGAR_FILETYPE_CHR; break; + case S_IFBLK: + type = SIGAR_FILETYPE_BLK; break; +#if defined(S_IFFIFO) + case S_IFFIFO: + type = SIGAR_FILETYPE_PIPE; break; +#endif +#if !defined(BEOS) && defined(S_IFSOCK) + case S_IFSOCK: + type = SIGAR_FILETYPE_SOCK; break; +#endif + + default: + /* Work around missing S_IFxxx values above + * for Linux et al. + */ +#if !defined(S_IFFIFO) && defined(S_ISFIFO) + if (S_ISFIFO(mode)) { + type = SIGAR_FILETYPE_PIPE; + } else +#endif +#if !defined(BEOS) && !defined(S_IFSOCK) && defined(S_ISSOCK) + if (S_ISSOCK(mode)) { + type = SIGAR_FILETYPE_SOCK; + } else +#endif + type = SIGAR_FILETYPE_UNKFILE; + } + return type; +} + +static sigar_uint64_t sigar_unix_mode2perms(mode_t mode) +{ + sigar_uint64_t perms = 0; + + if (mode & S_IRUSR) + perms |= SIGAR_UREAD; + if (mode & S_IWUSR) + perms |= SIGAR_UWRITE; + if (mode & S_IXUSR) + perms |= SIGAR_UEXECUTE; + + if (mode & S_IRGRP) + perms |= SIGAR_GREAD; + if (mode & S_IWGRP) + perms |= SIGAR_GWRITE; + if (mode & S_IXGRP) + perms |= SIGAR_GEXECUTE; + + if (mode & S_IROTH) + perms |= SIGAR_WREAD; + if (mode & S_IWOTH) + perms |= SIGAR_WWRITE; + if (mode & S_IXOTH) + perms |= SIGAR_WEXECUTE; + + return perms; +} + +static void copy_stat_info(sigar_file_attrs_t *fileattrs, + struct stat *info) +{ + fileattrs->permissions = sigar_unix_mode2perms(info->st_mode); + fileattrs->type = filetype_from_mode(info->st_mode); + fileattrs->uid = info->st_uid; + fileattrs->gid = info->st_gid; + fileattrs->size = info->st_size; + fileattrs->inode = info->st_ino; + fileattrs->device = info->st_dev; + fileattrs->nlink = info->st_nlink; + fileattrs->atime = info->st_atime; + fileattrs->mtime = info->st_mtime; + fileattrs->ctime = info->st_ctime; + fileattrs->atime *= 1000; + fileattrs->mtime *= 1000; + fileattrs->ctime *= 1000; +} + +int sigar_file_attrs_get(sigar_t *sigar, + const char *file, + sigar_file_attrs_t *fileattrs) +{ + struct stat info; + + if (stat(file, &info) == 0) { + copy_stat_info(fileattrs, &info); + return SIGAR_OK; + } + else { + return errno; + } +} + +int sigar_link_attrs_get(sigar_t *sigar, + const char *file, + sigar_file_attrs_t *fileattrs) +{ + struct stat info; + + if (lstat(file, &info) == 0) { + copy_stat_info(fileattrs, &info); + return SIGAR_OK; + } + else { + return errno; + } +} + +static int dir_stat_get(sigar_t *sigar, + const char *dir, + sigar_dir_stat_t *dirstats, + int recurse) +{ + int status; + char name[SIGAR_PATH_MAX+1]; + int len = strlen(dir); + int max = sizeof(name)-len-1; + char *ptr = name; + DIR *dirp = opendir(dir); + struct dirent *ent; + struct stat info; +#ifdef HAVE_READDIR_R + struct dirent dbuf; +#endif + + if (!dirp) { + return errno; + } + + strncpy(name, dir, sizeof(name)); + ptr += len; + if (name[len] != '/') { + *ptr++ = '/'; + len++; + max--; + } + +#ifdef HAVE_READDIR_R + while (readdir_r(dirp, &dbuf, &ent) == 0) { + if (ent == NULL) { + break; + } +#else + while ((ent = readdir(dirp))) { +#endif + /* skip '.' and '..' */ + if (IS_DOTDIR(ent->d_name)) { + continue; + } + + strncpy(ptr, ent->d_name, max); + ptr[max] = '\0'; + + if (lstat(name, &info) != 0) { + continue; + } + + dirstats->disk_usage += info.st_size; + + switch (filetype_from_mode(info.st_mode)) { + case SIGAR_FILETYPE_REG: + ++dirstats->files; + break; + case SIGAR_FILETYPE_DIR: + ++dirstats->subdirs; + if (recurse) { + status = + dir_stat_get(sigar, name, + dirstats, recurse); + if (status != SIGAR_OK) { + DIR_STAT_WARN(); + } + } + break; + case SIGAR_FILETYPE_LNK: + ++dirstats->symlinks; + break; + case SIGAR_FILETYPE_CHR: + ++dirstats->chrdevs; + break; + case SIGAR_FILETYPE_BLK: + ++dirstats->blkdevs; + break; + case SIGAR_FILETYPE_SOCK: + ++dirstats->sockets; + break; + default: + ++dirstats->total; + } + } + + dirstats->total = + dirstats->files + + dirstats->subdirs + + dirstats->symlinks + + dirstats->chrdevs + + dirstats->blkdevs + + dirstats->sockets; + + closedir(dirp); + + return SIGAR_OK; +} + +#endif + +SIGAR_DECLARE(int) sigar_dir_stat_get(sigar_t *sigar, + const char *dir, + sigar_dir_stat_t *dirstats) +{ + SIGAR_ZERO(dirstats); + return dir_stat_get(sigar, dir, dirstats, 0); +} + +SIGAR_DECLARE(int) sigar_dir_usage_get(sigar_t *sigar, + const char *dir, + sigar_dir_usage_t *dirusage) +{ + SIGAR_ZERO(dirusage); + return dir_stat_get(sigar, dir, dirusage, 1); +} diff --git a/vendor/sigar/src/sigar_format.c b/vendor/sigar/src/sigar_format.c new file mode 100644 index 0000000..8062ddd --- /dev/null +++ b/vendor/sigar/src/sigar_format.c @@ -0,0 +1,696 @@ +/* + * Copyright (c) 2007-2008 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * Copyright (c) 2010 VMware, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Utility functions to provide string formatting of SIGAR data */ + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_util.h" +#include "sigar_os.h" +#include "sigar_format.h" + +#include +#include + +#ifndef WIN32 +#include +#include +#if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(_AIX) +#include +#endif +#include +#include + +/* sysconf(_SC_GET{PW,GR}_R_SIZE_MAX) */ +#define R_SIZE_MAX 2048 + +int sigar_user_name_get(sigar_t *sigar, int uid, char *buf, int buflen) +{ + struct passwd *pw = NULL; + /* XXX cache lookup */ + +# ifdef HAVE_GETPWUID_R + struct passwd pwbuf; + char buffer[R_SIZE_MAX]; + + if (getpwuid_r(uid, &pwbuf, buffer, sizeof(buffer), &pw) != 0) { + return errno; + } + if (!pw) { + return ENOENT; + } +# else + if ((pw = getpwuid(uid)) == NULL) { + return errno; + } +# endif + + strncpy(buf, pw->pw_name, buflen); + buf[buflen-1] = '\0'; + + return SIGAR_OK; +} + +int sigar_group_name_get(sigar_t *sigar, int gid, char *buf, int buflen) +{ + struct group *gr; + /* XXX cache lookup */ + +# ifdef HAVE_GETGRGID_R + struct group grbuf; + char buffer[R_SIZE_MAX]; + + if (getgrgid_r(gid, &grbuf, buffer, sizeof(buffer), &gr) != 0) { + return errno; + } +# else + if ((gr = getgrgid(gid)) == NULL) { + return errno; + } +# endif + + if (gr && gr->gr_name) { + strncpy(buf, gr->gr_name, buflen); + } + else { + /* seen on linux.. apache httpd.conf has: + * Group #-1 + * results in uid == -1 and gr == NULL. + * wtf getgrgid_r doesnt fail instead? + */ + sprintf(buf, "%d", gid); + } + buf[buflen-1] = '\0'; + + return SIGAR_OK; +} + +int sigar_user_id_get(sigar_t *sigar, const char *name, int *uid) +{ + /* XXX cache lookup */ + struct passwd *pw; + +# ifdef HAVE_GETPWNAM_R + struct passwd pwbuf; + char buf[R_SIZE_MAX]; + + if (getpwnam_r(name, &pwbuf, buf, sizeof(buf), &pw) != 0) { + return errno; + } +# else + if (!(pw = getpwnam(name))) { + return errno; + } +# endif + + *uid = (int)pw->pw_uid; + return SIGAR_OK; +} + +#endif /* WIN32 */ + +static char *sigar_error_string(int err) +{ + switch (err) { + case SIGAR_ENOTIMPL: + return "This function has not been implemented on this platform"; + default: + return "Error string not specified yet"; + } +} + +SIGAR_DECLARE(char *) sigar_strerror(sigar_t *sigar, int err) +{ + char *buf; + + if (err < 0) { + return sigar->errbuf; + } + + if (err > SIGAR_OS_START_ERROR) { + if ((buf = sigar_os_error_string(sigar, err)) != NULL) { + return buf; + } + return "Unknown OS Error"; /* should never happen */ + } + + if (err > SIGAR_START_ERROR) { + return sigar_error_string(err); + } + + return sigar_strerror_get(err, sigar->errbuf, sizeof(sigar->errbuf)); +} + +char *sigar_strerror_get(int err, char *errbuf, int buflen) +{ + char *buf = NULL; +#ifdef WIN32 + DWORD len; + + len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + err, + MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT), /* force english */ + (LPTSTR)errbuf, + (DWORD)buflen, + NULL); +#else + +#if defined(HAVE_STRERROR_R) && defined(HAVE_STRERROR_R_GLIBC) + /* + * strerror_r man page says: + * "The GNU version may, but need not, use the user supplied buffer" + */ + buf = strerror_r(err, errbuf, buflen); +#elif defined(HAVE_STRERROR_R) + if (strerror_r(err, errbuf, buflen) < 0) { + buf = "Unknown Error"; + } +#else + /* strerror() is thread safe on solaris and hpux */ + buf = strerror(err); +#endif + + if (buf != NULL) { + SIGAR_STRNCPY(errbuf, buf, buflen); + } + +#endif + return errbuf; +} + +void sigar_strerror_set(sigar_t *sigar, char *msg) +{ + SIGAR_SSTRCPY(sigar->errbuf, msg); +} + +#ifdef WIN32 +#define vsnprintf _vsnprintf +#endif + +void sigar_strerror_printf(sigar_t *sigar, const char *format, ...) +{ + va_list args; + + va_start(args, format); + vsnprintf(sigar->errbuf, sizeof(sigar->errbuf), format, args); + va_end(args); +} + +/* copy apr_strfsize */ +SIGAR_DECLARE(char *) sigar_format_size(sigar_uint64_t size, char *buf) +{ + const char ord[] = "KMGTPE"; + const char *o = ord; + int remain; + + if (size == SIGAR_FIELD_NOTIMPL) { + buf[0] = '-'; + buf[1] = '\0'; + return buf; + } + + if (size < 973) { + sprintf(buf, "%3d ", (int) size); + return buf; + } + + do { + remain = (int)(size & 1023); + size >>= 10; + + if (size >= 973) { + ++o; + continue; + } + + if (size < 9 || (size == 9 && remain < 973)) { + if ((remain = ((remain * 5) + 256) / 512) >= 10) { + ++size; + remain = 0; + } + sprintf(buf, "%d.%d%c", (int) size, remain, *o); + return buf; + } + + if (remain >= 512) { + ++size; + } + + sprintf(buf, "%3d%c", (int) size, *o); + + return buf; + } while (1); +} + + +SIGAR_DECLARE(int) sigar_uptime_string(sigar_t *sigar, + sigar_uptime_t *uptime, + char *buffer, + int buflen) +{ + char *ptr = buffer; + int time = (int)uptime->uptime; + int minutes, hours, days, offset = 0; + + /* XXX: get rid of sprintf and/or check for overflow */ + days = time / (60*60*24); + + if (days) { + offset += sprintf(ptr + offset, "%d day%s, ", + days, (days > 1) ? "s" : ""); + } + + minutes = time / 60; + hours = minutes / 60; + hours = hours % 24; + minutes = minutes % 60; + + if (hours) { + offset += sprintf(ptr + offset, "%2d:%02d", + hours, minutes); + } + else { + offset += sprintf(ptr + offset, "%d min", minutes); + } + + return SIGAR_OK; +} + +/* threadsafe alternative to inet_ntoa (inet_ntop4 from apr) */ +int sigar_inet_ntoa(sigar_t *sigar, + sigar_uint32_t address, + char *addr_str) +{ + char *next=addr_str; + int n=0; + const unsigned char *src = + (const unsigned char *)&address; + + do { + unsigned char u = *src++; + if (u > 99) { + *next++ = '0' + u/100; + u %= 100; + *next++ = '0' + u/10; + u %= 10; + } + else if (u > 9) { + *next++ = '0' + u/10; + u %= 10; + } + *next++ = '0' + u; + *next++ = '.'; + n++; + } while (n < 4); + + *--next = 0; + + return SIGAR_OK; +} + +static int sigar_ether_ntoa(char *buff, unsigned char *ptr) +{ + sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X", + (ptr[0] & 0xff), (ptr[1] & 0xff), (ptr[2] & 0xff), + (ptr[3] & 0xff), (ptr[4] & 0xff), (ptr[5] & 0xff)); + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_net_address_equals(sigar_net_address_t *addr1, + sigar_net_address_t *addr2) + +{ + if (addr1->family != addr2->family) { + return EINVAL; + } + + switch (addr1->family) { + case SIGAR_AF_INET: + return memcmp(&addr1->addr.in, &addr2->addr.in, sizeof(addr1->addr.in)); + case SIGAR_AF_INET6: + return memcmp(&addr1->addr.in6, &addr2->addr.in6, sizeof(addr1->addr.in6)); + case SIGAR_AF_LINK: + return memcmp(&addr1->addr.mac, &addr2->addr.mac, sizeof(addr1->addr.mac)); + default: + return EINVAL; + } +} + +#if defined(SIGAR_USING_MSC6) +#define sigar_inet_ntop(af, src, dst, size) NULL +#define sigar_inet_ntop_errno SIGAR_ENOTIMPL +#elif defined(WIN32) +static char *sigar_inet_ntop(int af, const void *src, char *dst, int cnt) +{ + struct sockaddr_in6 sa; /* note only using this for AF_INET6 */ + + memset(&sa, '\0', sizeof(sa)); + sa.sin6_family = af; + memcpy(&sa.sin6_addr, src, sizeof(sa.sin6_addr)); + + if (getnameinfo((struct sockaddr *)&sa, sizeof(sa), + dst, cnt, NULL, 0, NI_NUMERICHOST)) + { + return NULL; + } + else { + return dst; + } +} +#define sigar_inet_ntop_errno GetLastError() +#else +#define sigar_inet_ntop inet_ntop +#define sigar_inet_ntop_errno errno +#endif + +SIGAR_DECLARE(int) sigar_net_address_to_string(sigar_t *sigar, + sigar_net_address_t *address, + char *addr_str) +{ + *addr_str = '\0'; + switch (address->family) { + case SIGAR_AF_INET6: + if (sigar_inet_ntop(AF_INET6, (const void *)&address->addr.in6, + addr_str, SIGAR_INET6_ADDRSTRLEN)) + { + return SIGAR_OK; + } + else { + return sigar_inet_ntop_errno; + } + case SIGAR_AF_INET: + return sigar_inet_ntoa(sigar, address->addr.in, addr_str); + case SIGAR_AF_UNSPEC: + return sigar_inet_ntoa(sigar, 0, addr_str); /*XXX*/ + case SIGAR_AF_LINK: + return sigar_ether_ntoa(addr_str, &address->addr.mac[0]); + default: + return EINVAL; + } +} + +SIGAR_DECLARE(const char *)sigar_net_scope_to_string(int type) +{ + switch (type) { + case SIGAR_IPV6_ADDR_ANY: + return "Global"; + case SIGAR_IPV6_ADDR_LOOPBACK: + return "Host"; + case SIGAR_IPV6_ADDR_LINKLOCAL: + return "Link"; + case SIGAR_IPV6_ADDR_SITELOCAL: + return "Site"; + case SIGAR_IPV6_ADDR_COMPATv4: + return "Compat"; + default: + return "Unknown"; + } +} + +SIGAR_DECLARE(sigar_uint32_t) sigar_net_address_hash(sigar_net_address_t *address) +{ + sigar_uint32_t hash = 0; + unsigned char *data; + int i=0, size, elts; + + switch (address->family) { + case SIGAR_AF_UNSPEC: + case SIGAR_AF_INET: + return address->addr.in; + case SIGAR_AF_INET6: + data = (unsigned char *)&address->addr.in6; + size = sizeof(address->addr.in6); + elts = 4; + break; + case SIGAR_AF_LINK: + data = (unsigned char *)&address->addr.mac; + size = sizeof(address->addr.mac); + elts = 2; + break; + default: + return -1; + } + + while (ivalue) { + entry->value = strdup(name); + } + } + + fclose(fp); + return SIGAR_OK; +} + +SIGAR_DECLARE(char *)sigar_net_services_name_get(sigar_t *sigar, + int protocol, unsigned long port) +{ + sigar_cache_entry_t *entry; + sigar_cache_t **names; + char *pname; + + switch (protocol) { + case SIGAR_NETCONN_TCP: + names = &sigar->net_services_tcp; + pname = "tcp"; + break; + case SIGAR_NETCONN_UDP: + names = &sigar->net_services_udp; + pname = "udp"; + break; + default: + return NULL; + } + + if (*names == NULL) { + *names = sigar_cache_new(1024); + net_services_parse(*names, pname); + } + + if ((entry = sigar_cache_find(*names, port))) { + return (char *)entry->value; + } + else { + return NULL; + } +} + +SIGAR_DECLARE(int) sigar_cpu_perc_calculate(sigar_cpu_t *prev, + sigar_cpu_t *curr, + sigar_cpu_perc_t *perc) +{ + double diff_user, diff_sys, diff_nice, diff_idle; + double diff_wait, diff_irq, diff_soft_irq, diff_stolen; + double diff_total; + + diff_user = curr->user - prev->user; + diff_sys = curr->sys - prev->sys; + diff_nice = curr->nice - prev->nice; + diff_idle = curr->idle - prev->idle; + diff_wait = curr->wait - prev->wait; + diff_irq = curr->irq - prev->irq; + diff_soft_irq = curr->soft_irq - prev->soft_irq; + diff_stolen = curr->stolen - prev->stolen; + + diff_user = diff_user < 0 ? 0 : diff_user; + diff_sys = diff_sys < 0 ? 0 : diff_sys; + diff_nice = diff_nice < 0 ? 0 : diff_nice; + diff_idle = diff_idle < 0 ? 0 : diff_idle; + diff_wait = diff_wait < 0 ? 0 : diff_wait; + diff_irq = diff_irq < 0 ? 0 : diff_irq; + diff_soft_irq = diff_soft_irq < 0 ? 0 : diff_soft_irq; + diff_stolen = diff_stolen < 0 ? 0 : diff_stolen; + + diff_total = + diff_user + diff_sys + diff_nice + diff_idle + + diff_wait + diff_irq + diff_soft_irq + + diff_stolen; + + perc->user = diff_user / diff_total; + perc->sys = diff_sys / diff_total; + perc->nice = diff_nice / diff_total; + perc->idle = diff_idle / diff_total; + perc->wait = diff_wait / diff_total; + perc->irq = diff_irq / diff_total; + perc->soft_irq = diff_soft_irq / diff_total; + perc->stolen = diff_stolen / diff_total; + + perc->combined = + perc->user + perc->sys + perc->nice + perc->wait; + + return SIGAR_OK; +} diff --git a/vendor/sigar/src/sigar_getline.c b/vendor/sigar/src/sigar_getline.c new file mode 100644 index 0000000..0a8946b --- /dev/null +++ b/vendor/sigar/src/sigar_getline.c @@ -0,0 +1,1849 @@ +/* + * Copyright (C) 1991, 1992 by Chris Thewalt (thewalt@ce.berkeley.edu) + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted, provided + * that the above copyright notices appear in all copies and that both the + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + */ +/* +*************************** Motivation ********************************** + +Many interactive programs read input line by line, but would like to +provide line editing and history functionality to the end-user that +runs the program. + +The input-edit package provides that functionality. As far as the +programmer is concerned, the program only asks for the next line +of input. However, until the user presses the RETURN key they can use +emacs-style line editing commands and can traverse the history of lines +previously typed. + +Other packages, such as GNU's readline, have greater capability but are +also substantially larger. Input-edit is small, since it uses neither +stdio nor any termcap features, and is also quite portable. It only uses +\b to backspace and \007 to ring the bell on errors. Since it cannot +edit multiple lines it scrolls long lines left and right on the same line. + +Input edit uses classic (not ANSI) C, and should run on any Unix +system (BSD or SYSV), PC's with the MSC compiler, or Vax/VMS (untested by me). +Porting the package to new systems basicaly requires code to read a +character when it is typed without echoing it, everything else should be OK. + +I have run the package on: + + DECstation 5000, Ultrix 4.2 with cc and gcc + Sun Sparc 2, SunOS 4.1.1, with cc + SGI Iris, IRIX System V.3, with cc + PC, DRDOS 5.0, with MSC 6.0 + +The description below is broken into two parts, the end-user (editing) +interface and the programmer interface. Send bug reports, fixes and +enhancements to: + +Chris Thewalt (thewalt@ce.berkeley.edu) +2/4/92 + +PS: I don't have, and don't want to add, a vi mode, sorry. + +************************** End-User Interface *************************** + +Entering printable keys generally inserts new text into the buffer (unless +in overwrite mode, see below). Other special keys can be used to modify +the text in the buffer. In the description of the keys below, ^n means +Control-n, or holding the CONTROL key down while pressing "n". M-B means +Meta-B (or Alt-B). Errors will ring the terminal bell. + +^A/^E : Move cursor to beginning/end of the line. +^F/^B : Move cursor forward/backward one character. +^D : Delete the character under the cursor. +^H, DEL : Delete the character to the left of the cursor. +^K : Kill from the cursor to the end of line. +^L : Redraw current line. +^O : Toggle overwrite/insert mode. Initially in insert mode. Text + added in overwrite mode (including yanks) overwrite + existing text, while insert mode does not overwrite. +^P/^N : Move to previous/next item on history list. +^R/^S : Perform incremental reverse/forward search for string on + the history list. Typing normal characters adds to the current + search string and searches for a match. Typing ^R/^S marks + the start of a new search, and moves on to the next match. + Typing ^H or DEL deletes the last character from the search + string, and searches from the starting location of the last search. + Therefore, repeated DEL's appear to unwind to the match nearest + the point at which the last ^R or ^S was typed. If DEL is + repeated until the search string is empty the search location + begins from the start of the history list. Typing ESC or + any other editing character accepts the current match and + loads it into the buffer, terminating the search. +^T : Toggle the characters under and to the left of the cursor. +^U : Kill from beginning to the end of the line. +^Y : Yank previously killed text back at current location. Note that + this will overwrite or insert, depending on the current mode. +M-F/M-B : Move cursor forward/backward one word. +M-D : Delete the word under the cursor. +^SPC : Set mark. +^W : Kill from mark to point. +^X : Exchange mark and point. +TAB : By default adds spaces to buffer to get to next TAB stop + (just after every 8th column), although this may be rebound by the + programmer, as described below. +NL, CR : returns current buffer to the program. + +DOS and ANSI terminal arrow key sequences are recognized, and act like: + + up : same as ^P + down : same as ^N + left : same as ^B + right : same as ^F + +************************** Programmer Interface *************************** + +The programmer accesses input-edit through five functions, and optionally +through three additional function pointer hooks. The five functions are: + +char *Getline(char *prompt) + + Prints the prompt and allows the user to edit the current line. A + pointer to the line is returned when the user finishes by + typing a newline or a return. Unlike GNU readline, the returned + pointer points to a static buffer, so it should not be free'd, and + the buffer contains the newline character. The user enters an + end-of-file by typing ^D on an empty line, in which case the + first character of the returned buffer is '\0'. Getline never + returns a NULL pointer. The getline function sets terminal modes + needed to make it work, and resets them before returning to the + caller. The getline function also looks for characters that would + generate a signal, and resets the terminal modes before raising the + signal condition. If the signal handler returns to getline, + the screen is automatically redrawn and editing can continue. + Getline now requires both the input and output stream be connected + to the terminal (not redirected) so the main program should check + to make sure this is true. If input or output have been redirected + the main program should use buffered IO (stdio) rather than + the slow 1 character read()s that getline uses (note: this limitation + has been removed). + +char *Getlinem(int mode, char *prompt) + + mode: -1 = init, 0 = line mode, 1 = one char at a time mode, 2 = cleanup + + More specialized version of the previous function. Depending on + the mode, it behaves differently. Its main use is to allow + character by character input from the input stream (useful when + in an X eventloop). It will return NULL as long as no newline + has been received. Its use is typically as follows: + 1) In the program initialization part one calls: Getlinem(-1,"prompt>") + 2) In the X inputhandler: if ((line = Getlinem(1,NULL))) { + 3) In the termination routine: Getlinem(2,NULL) + With mode=0 the function behaves exactly like the previous function. + +void Gl_config(const char *which, int value) + + Set some config options. Which can be: + "noecho": do not echo characters (used for passwd input) + "erase": do erase line after return (used for text scrollers) + +void Gl_setwidth(int width) + + Set the width of the terminal to the specified width. The default + width is 80 characters, so this function need only be called if the + width of the terminal is not 80. Since horizontal scrolling is + controlled by this parameter it is important to get it right. + +void Gl_histinit(char *file) + + This function reads a history list from file. So lines from a + previous session can be used again. + +void Gl_histadd(char *buf) + + The Gl_histadd function checks to see if the buf is not empty or + whitespace, and also checks to make sure it is different than + the last saved buffer to avoid repeats on the history list. + If the buf is a new non-blank string a copy is made and saved on + the history list, so the caller can re-use the specified buf. + +The main loop in testgl.c, included in this directory, shows how the +input-edit package can be used: + +extern char *Getline(); +extern void Gl_histadd(); +main() +{ + char *p; + Gl_histinit(".hist"); + do { + p = Getline("PROMPT>>>> "); + Gl_histadd(p); + fputs(p, stdout); + } while (*p != 0); +} + +In order to allow the main program to have additional access to the buffer, +to implement things such as completion or auto-indent modes, three +function pointers can be bound to user functions to modify the buffer as +described below. By default gl_in_hook and gl_out_hook are set to NULL, +and gl_tab_hook is bound to a function that inserts spaces until the next +logical tab stop is reached. The user can reassign any of these pointers +to other functions. Each of the functions bound to these hooks receives +the current buffer as the first argument, and must return the location of +the leftmost change made in the buffer. If the buffer isn't modified the +functions should return -1. When the hook function returns the screen is +updated to reflect any changes made by the user function. + +int (*gl_in_hook)(char *buf) + + If gl_in_hook is non-NULL the function is called each time a new + buffer is loaded. It is called when getline is entered, with an + empty buffer, it is called each time a new buffer is loaded from + the history with ^P or ^N, and it is called when an incremental + search string is accepted (when the search is terminated). The + buffer can be modified and will be redrawn upon return to Getline(). + +int (*gl_out_hook)(char *buf) + + If gl_out_hook is non-NULL it is called when a line has been + completed by the user entering a newline or return. The buffer + handed to the hook does not yet have the newline appended. If the + buffer is modified the screen is redrawn before getline returns the + buffer to the caller. + +int (*gl_tab_hook)(char *buf, int prompt_width, int *cursor_loc) + + If gl_tab_hook is non-NULL, it is called whenever a tab is typed. + In addition to receiving the buffer, the current prompt width is + given (needed to do tabbing right) and a pointer to the cursor + offset is given, where a 0 offset means the first character in the + line. Not only does the cursor_loc tell the programmer where the + TAB was received, but it can be reset so that the cursor will end + up at the specified location after the screen is redrawn. +*/ + +/* forward reference needed for gl_tab_hook */ +static int gl_tab(char *buf, int offset, int *loc); + +/********************* exported interface ********************************/ + +static int (*gl_in_hook)(char *buf) = 0; +static int (*gl_out_hook)(char *buf) = 0; +static int (*gl_tab_hook)(char *buf, int prompt_width, int *loc) = gl_tab; + +/******************** imported interface *********************************/ +#ifdef DMALLOC +/* reports leaks, which is the history buffer. dont care */ +#undef DMALLOC +#endif +#include "sigar_getline.h" +#include "sigar_private.h" +#include "sigar_util.h" +#include +#include +#include +#include +#include +#include + +/******************** internal interface *********************************/ + +static char *sigar_getlinem(int mode, char *prompt); /* allows reading char by char */ + +static void sigar_getline_config(const char *which, int value); /* set some options */ + +static void sigar_getline_clear_screen(void); + +#define BUF_SIZE 8096 + +static int gl_init_done = -1; /* terminal mode flag */ +static int gl_notty = 0; /* 1 when not a tty */ +static int gl_eof = 0; /* 1 when not a tty and read() == -1 */ +static int gl_termw = 80; /* actual terminal width */ +static int gl_scroll = 27; /* width of EOL scrolling region */ +static int gl_width = 0; /* net size available for input */ +static int gl_extent = 0; /* how far to redraw, 0 means all */ +static int gl_overwrite = 0; /* overwrite mode */ +static int gl_no_echo = 0; /* do not echo input characters */ +static int gl_passwd = 0; /* do not echo input characters */ +static int gl_erase_line = 0; /* erase line before returning */ +static int gl_pos, gl_cnt = 0; /* position and size of input */ +static char gl_buf[BUF_SIZE]; /* input buffer */ +static char gl_killbuf[BUF_SIZE]=""; /* killed text */ +static char *gl_prompt; /* to save the prompt string */ +static char gl_intrc = 0; /* keyboard SIGINT char */ +static char gl_quitc = 0; /* keyboard SIGQUIT char */ +static char gl_suspc = 0; /* keyboard SIGTSTP char */ +static char gl_dsuspc = 0; /* delayed SIGTSTP char */ +static int gl_search_mode = 0; /* search mode flag */ +static int gl_bell_enabled = 0; /* bell mode */ +static int gl_savehist = 0; /* # of lines to save in hist file */ +static char gl_histfile[256]; /* name of history file */ + +static void gl_init(); /* prepare to edit a line */ +static void gl_bell(); /* ring bell */ +static void gl_cleanup(); /* to undo gl_init */ +static void gl_char_init(); /* get ready for no echo input */ +static void gl_char_cleanup(); /* undo gl_char_init */ + +static void gl_addchar(int c); /* install specified char */ +static void gl_del(int loc); /* del, either left (-1) or cur (0) */ +static void gl_error(char *buf); /* write error msg and die */ +static void gl_fixup(char *p, int c, int cur); /* fixup state variables and screen */ +static int gl_getc(); /* read one char from terminal */ +static void gl_kill(); /* delete to EOL */ +static void gl_newline(); /* handle \n or \r */ +static void gl_putc(int c); /* write one char to terminal */ +static void gl_puts(char *buf); /* write a line to terminal */ +static void gl_transpose(); /* transpose two chars */ +static void gl_yank(); /* yank killed text */ + +static int is_whitespace(char c); /* "whitespace" very loosely interpreted */ +static void gl_back_1_word(); /* move cursor back one word */ +static void gl_kill_1_word(); /* kill to end of word */ +static void gl_kill_region(int i, int j); /* kills from i to j */ +static void gl_fwd_1_word(); /* move cursor forward one word */ +static void gl_set_mark(); /* sets mark to be at point */ +static void gl_exch(); /* exchanges point and mark */ +static void gl_wipe(); /* kills from mark to point */ +static int gl_mark = -1; /* position of mark. gl_mark<0 if not set */ + +static void hist_init(); /* initializes hist pointers */ +static char *hist_next(); /* return ptr to next item */ +static char *hist_prev(); /* return ptr to prev item */ +static char *hist_save(char *p); /* makes copy of a string, without NL */ + +static void search_addchar(int c); /* increment search string */ +static void search_term(); /* reset with current contents */ +static void search_back(int s); /* look back for current string */ +static void search_forw(int s); /* look forw for current string */ + +/************************ nonportable part *********************************/ + +#ifdef MSDOS +#include +#endif + +#ifdef WIN32 +# define MSDOS +# include +# include +#endif /* WIN32 */ + +#ifdef __MWERKS__ +#define R__MWERKS +#endif + +#ifdef R__MWERKS +# include +#endif + +#if defined(_AIX) || defined(__Lynx__) || defined(__APPLE__) +#define unix +#endif + +#if defined(__hpux) || defined(__osf__) /* W.Karig@gsi.de */ +#ifndef unix +#define unix +#endif +#endif + +#ifdef unix +#include +#if !defined(__osf__) && !defined(_AIX) /* W.Karig@gsi.de */ +#include +#endif + +#if defined(__linux__) && defined(__powerpc__) +# define R__MKLINUX // = linux on PowerMac +#endif +#if defined(__linux__) && defined(__alpha__) +# define R__ALPHALINUX // = linux on Alpha +#endif + +#if defined(TIOCGETP) && !defined(__sgi) && !defined(R__MKLINUX) && \ + !defined(R__ALPHALINUX) /* use BSD interface if possible */ +#include +static struct sgttyb new_tty, old_tty; +static struct tchars tch; +static struct ltchars ltch; +#else +#ifdef SIGTSTP /* need POSIX interface to handle SUSP */ +#include +#if defined(__sun) || defined(__sgi) || defined(R__MKLINUX) || \ + defined(R__ALPHALINUX) +#undef TIOCGETP /* Solaris and SGI define TIOCGETP in */ +#undef TIOCSETP +#endif +static struct termios new_termios, old_termios; +#else /* use SYSV interface */ +#include +static struct termio new_termio, old_termio; +#endif +#endif +#endif /* unix */ + +#ifdef VMS +#include +#include +#include +#include +#include +#include unixio + +static int setbuff[2]; /* buffer to set terminal attributes */ +static short chan = -1; /* channel to terminal */ +struct dsc$descriptor_s descrip; /* VMS descriptor */ +#endif + +static void +sigar_getline_config(const char *which, int value) +{ + if (strcmp(which, "noecho") == 0) + gl_no_echo = value; + else if (strcmp(which, "erase") == 0) + gl_erase_line = value; + else + printf("gl_config: %s ?\n", which); +} + +static void +gl_char_init() /* turn off input echo */ +{ + if (gl_notty) return; +#ifdef unix +#ifdef TIOCGETP /* BSD */ + ioctl(0, TIOCGETC, &tch); + ioctl(0, TIOCGLTC, <ch); + gl_intrc = tch.t_intrc; + gl_quitc = tch.t_quitc; + gl_suspc = ltch.t_suspc; + gl_dsuspc = ltch.t_dsuspc; + ioctl(0, TIOCGETP, &old_tty); + new_tty = old_tty; + new_tty.sg_flags |= RAW; + new_tty.sg_flags &= ~ECHO; + ioctl(0, TIOCSETP, &new_tty); +#else +#ifdef SIGTSTP /* POSIX */ + tcgetattr(0, &old_termios); + gl_intrc = old_termios.c_cc[VINTR]; + gl_quitc = old_termios.c_cc[VQUIT]; +#ifdef VSUSP + gl_suspc = old_termios.c_cc[VSUSP]; +#endif +#ifdef VDSUSP + gl_dsuspc = old_termios.c_cc[VDSUSP]; +#endif + new_termios = old_termios; + new_termios.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF); + new_termios.c_iflag |= (IGNBRK|IGNPAR); + new_termios.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO); + new_termios.c_cc[VMIN] = 1; + new_termios.c_cc[VTIME] = 0; + tcsetattr(0, TCSANOW, &new_termios); +#else /* SYSV */ + ioctl(0, TCGETA, &old_termio); + gl_intrc = old_termio.c_cc[VINTR]; + gl_quitc = old_termio.c_cc[VQUIT]; + new_termio = old_termio; + new_termio.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF); + new_termio.c_iflag |= (IGNBRK|IGNPAR); + new_termio.c_lflag &= ~(ICANON|ISIG|ECHO); + new_termio.c_cc[VMIN] = 1; + new_termio.c_cc[VTIME] = 0; + ioctl(0, TCSETA, &new_termio); +#endif +#endif +#endif /* unix */ + +#ifdef MSDOS + gl_intrc = 'C' - '@'; + gl_quitc = 'Q' - '@'; +// gl_suspc = ltch.t_suspc; +#endif /* MSDOS */ + +#ifdef R__MWERKS + gl_intrc = 'C' - '@'; + gl_quitc = 'Q' - '@'; +#endif + +#ifdef vms + descrip.dsc$w_length = strlen("tt:"); + descrip.dsc$b_dtype = DSC$K_DTYPE_T; + descrip.dsc$b_class = DSC$K_CLASS_S; + descrip.dsc$a_pointer = "tt:"; + (void)sys$assign(&descrip,&chan,0,0); + (void)sys$qiow(0,chan,IO$_SENSEMODE,0,0,0,setbuff,8,0,0,0,0); + setbuff[1] |= TT$M_NOECHO; + (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0); +#endif /* vms */ +} + +static void +gl_char_cleanup() /* undo effects of gl_char_init */ +{ + if (gl_notty) return; +#ifdef unix +#ifdef TIOCSETP /* BSD */ + ioctl(0, TIOCSETP, &old_tty); +#else +#ifdef SIGTSTP /* POSIX */ + tcsetattr(0, TCSANOW, &old_termios); +#else /* SYSV */ + ioctl(0, TCSETA, &old_termio); +#endif +#endif +#endif /* unix */ + +#ifdef vms + setbuff[1] &= ~TT$M_NOECHO; + (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0); + sys$dassgn(chan); + chan = -1; +#endif +} + +#if defined(MSDOS) && !defined(WIN32) +// +DECK, PAUSE, T=XCC, IF=WINNT. (from KERNDOS.CAR ) +# include + int pause_() + { + int first_char; + first_char = _getch(); + if (first_char == 0 || first_char == 0xE0) first_char = -_getch(); + return first_char; + } +#endif + +#if defined(MSDOS) && defined(WIN32) +//______________________________________________________________________________ +int pause_() +{ + static HANDLE hConsoleInput = NULL; + static iCharCount = 0; + static int chLastChar = 0; + + DWORD cRead; + + INPUT_RECORD pirBuffer; + KEY_EVENT_RECORD *KeyEvent= (KEY_EVENT_RECORD *)&(pirBuffer.Event); + + if (!hConsoleInput) hConsoleInput = GetStdHandle(STD_INPUT_HANDLE); + + if (iCharCount) iCharCount--; // Whether several symbols had been read + else { + chLastChar = 0; + while (chLastChar == 0) { + if (!ReadConsoleInput(hConsoleInput, // handle of a console input buffer + &pirBuffer, // address of the buffer for read data + 1, // number of records to read + &cRead // address of number of records read + )) return 0; + + if (pirBuffer.EventType == KEY_EVENT && KeyEvent->bKeyDown == TRUE){ + iCharCount = KeyEvent->wRepeatCount - 1; + chLastChar = ((int) (KeyEvent->uChar).AsciiChar & 0xffff); + if (chLastChar) + OemToCharBuff((char const *)&chLastChar,(char *)&chLastChar,1); + else + chLastChar = - (KeyEvent->wVirtualScanCode); +// chLastChar = - (KeyEvent->wVirtualKeyCode); + } + } + } + return chLastChar; + +} +#endif + +static int +gl_getc() +/* get a character without echoing it to screen */ +{ +#ifdef MSDOS +# define k_ctrl_C 3 +# define k_ctrl_Z 26 +# define k_ctrl_Q 17 +# define k_ctrl_K 11 +# define k_rt_arr -77 +# define k_lt_arr -75 +# define k_up_arr -72 +# define k_dn_arr -80 +# define k_PGUP -73 +# define k_PGDW -81 +# define k_HOME -71 +# define k_END -79 +# define k_INS -82 +# define k_DEL -83 +# define k_ENTER 13 +# define k_CR 13 +# define k_BS 8 +# define k_ESC 27 +# define k_alt_H -35 +# define k_beep 7 +# ifndef WIN32 + int get_cursor__(int *,int *); + int display_off__(int *); + int display_on__(); + int locate_(int *,int *); + int ixc, iyc; +# endif + int pause_(); +#endif + + int c; + +#if defined(unix) + unsigned char ch; + while ((c = (read(0, &ch, 1) > 0) ? ch : -1) == -1 && errno == EINTR) + errno = 0; +#endif + +#if defined(R__MWERKS) + c = getchar(); +#endif + +#ifdef MSDOS + c = pause_(); + if (c < 0) { + switch (c) { + case k_up_arr: c = 'P' - '@'; /* up -> ^P = 16 */ + break; + case k_dn_arr: c = 'N' - '@'; /* down -> ^N = 14 */ + break; + case k_lt_arr: c = 'B' - '@'; /* left -> ^B =2 */ + break; + case k_rt_arr: c = 'F' - '@'; /* right -> ^F = 6*/ + break; + case k_INS: c = 'O' - '@'; /* right -> ^O = 15*/ + break; + case k_DEL: c = 'D' - '@'; /* Delete character under cursor = 4*/ + break; + case k_END: c = 'E' - '@'; /* Moves cursor to end of line * = 5 */ + break; + case k_HOME: c = 'A' - '@'; /* Moves cursor to beginning of line = 1*/ + break; + default: c = 0; /* make it garbage */ + } + } + else { + switch(c) { + case k_ESC: c = 'U' - '@'; /* Clear full line -> ^U */ + break; + default: + break; + } + } +#endif + +#ifdef vms + if(chan < 0) { + c='\0'; + } + (void)sys$qiow(0,chan,IO$_TTYREADALL,0,0,0,&c,1,0,0,0,0); + c &= 0177; /* get a char */ +#endif + return c; +} + +static void +gl_putc(int c) +{ + char ch = c; + + if (gl_notty) return; + + if ( !gl_passwd || !isgraph(c)) + { +#ifdef WIN32 + CharToOemBuff((char const *)&c,&ch,1); +#endif + + sigar_write(1, &ch, 1); + } +#if defined(unix) || defined(MSDOS) || defined(WIN32) || defined(R__MWERKS) +#ifdef TIOCSETP /* BSD in RAW mode, map NL to NL,CR */ + if (ch == '\n') { + ch = '\r'; + sigar_write(1, &ch, 1); + } +#endif +#endif +} + +/******************** fairly portable part *********************************/ + +static void +gl_puts(char *buf) +{ + int len = strlen(buf); + + if (gl_notty) return; +#ifdef WIN32 + { + char *OemBuf = (char *)malloc(2*len); + CharToOemBuff(buf,OemBuf,len); + sigar_write(1, OemBuf, len); + free(OemBuf); + } +#else + sigar_write(1, buf, len); +#endif +} + +static void +gl_error(char *buf) +{ + int len = strlen(buf); + + gl_cleanup(); +#ifdef WIN32 + { + char *OemBuf = (char *)malloc(2*len); + CharToOemBuff(buf,OemBuf,len); + sigar_write(2, OemBuf, len); + free(OemBuf); + } +#else + sigar_write(2, buf, len); +#endif + exit(1); +} + +static void +gl_init() +/* set up variables and terminal */ +{ + if (gl_init_done < 0) { /* -1 only on startup */ + hist_init(); + } + if (sigar_isatty(0) == 0 || sigar_isatty(1) == 0) + gl_notty = 1; + gl_char_init(); + gl_init_done = 1; +} + +static void +gl_bell() +{ + if (gl_bell_enabled) { + gl_putc('\007'); + } +} + +static void +gl_cleanup() +/* undo effects of gl_init, as necessary */ +{ + if (gl_init_done > 0) + gl_char_cleanup(); + gl_init_done = 0; +} + +SIGAR_DECLARE(void) +sigar_getline_setwidth(int w) +{ + if (w > 20) { + gl_termw = w; + gl_scroll = w / 3; + } else { + gl_error("\n*** Error: minimum screen width is 21\n"); + } +} + +SIGAR_DECLARE(void) +sigar_getline_windowchanged() +{ +#ifdef TIOCGWINSZ + if (sigar_isatty(0)) { + static char lenv[32], cenv[32]; + struct winsize wins; + ioctl(0, TIOCGWINSZ, &wins); + + if (wins.ws_col == 0) wins.ws_col = 80; + if (wins.ws_row == 0) wins.ws_row = 24; + + sigar_getline_setwidth(wins.ws_col); + + sprintf(lenv, "LINES=%d", wins.ws_row); + putenv(lenv); + sprintf(cenv, "COLUMNS=%d", wins.ws_col); + putenv(cenv); + } +#endif +} + +/* -1 = init, 0 = line mode, 1 = one char at a time mode, 2 = cleanup */ + +static char * +sigar_getlinem(int mode, char *prompt) +{ + int c, loc, tmp; + int sig; + + if (mode == 2) { + gl_cleanup(); + return NULL; + } + + if (mode < 1) { + if (mode == -1) { + sigar_getline_config("noecho", 0); + sigar_getline_config("erase", 0); + } + gl_init(); + gl_prompt = (prompt)? prompt : (char*)""; + gl_buf[0] = 0; + if (gl_in_hook) + gl_in_hook(gl_buf); + gl_fixup(gl_prompt, -2, BUF_SIZE); + if (mode == -1) return NULL; + } + while ((c = gl_getc()) >= 0) { + gl_extent = 0; /* reset to full extent */ +#ifndef WIN32 + if (isprint(c)) { +#else + if (c >= ' ') { +#endif + if (gl_search_mode) + search_addchar(c); + else + gl_addchar(c); + } else { + if (gl_search_mode) { + if (c == '\033' || c == '\016' || c == '\020') { + search_term(); + c = 0; /* ignore the character */ + } else if (c == '\010' || c == '\177') { + search_addchar(-1); /* unwind search string */ + c = 0; + } else if (c != '\022' && c != '\023') { + search_term(); /* terminate and handle char */ + } + } + /* NOTE: + * sometimes M-x turns on bit 8 ( M-x --> 'x' + 128 ) + * sometimes M-x prepends an escape character ( M-x --> '\033','x' ) + * both cases are handled ... + */ + switch (c) + { + case 'b'+128: /* M-b */ + case 'B'+128: /* M-B */ + gl_back_1_word(); + break; + case 'd'+128: /* M-d */ + case 'D'+128: /* M-D */ + gl_kill_1_word(); + break; + case 'f'+128: /* M-f */ + case 'F'+128: /* M-F */ + gl_fwd_1_word(); + break; + case '\000': /* ^SPC */ + gl_set_mark(); + break; + case '\027': /* ^W */ + gl_wipe(); + break; + case '\030': /* ^X */ + gl_exch(); + break; + case '\n': /* newline */ + case '\r': + gl_newline(); + gl_cleanup(); + return gl_buf; + /*NOTREACHED*/ + break; + case '\001': gl_fixup(gl_prompt, -1, 0); /* ^A */ + break; + case '\002': gl_fixup(gl_prompt, -1, gl_pos-1); /* ^B */ + break; + case '\004': /* ^D */ + if (gl_cnt == 0) { + gl_buf[0] = 0; + gl_cleanup(); + gl_putc('\n'); + return gl_buf; + } else { + gl_del(0); + } + break; + case '\005': gl_fixup(gl_prompt, -1, gl_cnt); /* ^E */ + break; + case '\006': gl_fixup(gl_prompt, -1, gl_pos+1); /* ^F */ + break; + case '\010': case '\177': gl_del(-1); /* ^H and DEL */ + break; + case '\t': /* TAB */ + if (gl_tab_hook) { + tmp = gl_pos; + loc = gl_tab_hook(gl_buf, strlen(gl_prompt), &tmp); + if (loc >= 0 || tmp != gl_pos || loc == -2) + gl_fixup(gl_prompt, loc, tmp); + } + break; + case '\013': gl_kill(); /* ^K */ + break; + case '\014': sigar_getline_clear_screen(); /* ^L */ + break; + case '\016': /* ^N */ + strcpy(gl_buf, hist_next()); + if (gl_in_hook) + gl_in_hook(gl_buf); + gl_fixup(gl_prompt, 0, BUF_SIZE); + break; + case '\017': gl_overwrite = !gl_overwrite; /* ^O */ + break; + case '\020': /* ^P */ + strcpy(gl_buf, hist_prev()); + if (gl_in_hook) + gl_in_hook(gl_buf); + gl_fixup(gl_prompt, 0, BUF_SIZE); + break; + case '\022': search_back(1); /* ^R */ + break; + case '\023': search_forw(1); /* ^S */ + break; + case '\024': gl_transpose(); /* ^T */ + break; + case '\025': gl_fixup(gl_prompt,-1,0); gl_kill(); /* ^U */ + break; + case '\031': gl_yank(); /* ^Y */ + break; + case '\033': + switch(c = gl_getc()) + { + case 'b': /* M-b */ + case 'B': /* M-B */ + gl_back_1_word(); + break; + case 'd': /* M-d */ + case 'D': /* M-D */ + gl_kill_1_word(); + break; + case 'f': /* M-f */ + case 'F': /* M-F */ + gl_fwd_1_word(); + break; + case '[': /* ansi arrow keys */ + case 'O': /* xterm arrow keys */ + switch(c = gl_getc()) + { + case 'A': /* up */ + strcpy(gl_buf, hist_prev()); + if (gl_in_hook) + gl_in_hook(gl_buf); + gl_fixup(gl_prompt, 0, BUF_SIZE); + break; + case 'B': /* down */ + strcpy(gl_buf, hist_next()); + if (gl_in_hook) + gl_in_hook(gl_buf); + gl_fixup(gl_prompt, 0, BUF_SIZE); + break; + case 'C': gl_fixup(gl_prompt, -1, gl_pos+1); /* right */ + break; + case 'D': gl_fixup(gl_prompt, -1, gl_pos-1); /* left */ + break; + default: /* who knows */ + gl_bell(); + break; + } + break; + default: + gl_bell(); + } + break; + default: /* check for a terminal signal */ + +#if defined(unix) || defined(WIN32) || defined(R__MWERKS) + if (c > 0) { /* ignore 0 (reset above) */ + sig = 0; +#ifdef SIGINT + if (c == gl_intrc) + sig = SIGINT; +#endif +#ifdef SIGQUIT + if (c == gl_quitc) + sig = SIGQUIT; +#endif +#ifdef SIGTSTP + if (c == gl_suspc || c == gl_dsuspc) + sig = SIGTSTP; +#endif + if (sig != 0) { + gl_cleanup(); +#if !defined(WIN32) + raise(sig); +#endif +#ifdef WIN32 + if (sig == SIGINT) GenerateConsoleCtrlEvent(CTRL_C_EVENT,0); + else raise(sig); +#endif + gl_init(); + sigar_getline_redraw(); + c = 0; + } + } +#endif /* unix */ + if (c > 0) + gl_bell(); + break; + } + } + if (mode == 1) return NULL; + } + if (c == -1 && gl_notty) + gl_eof = 1; + else + gl_eof = 0; + + gl_cleanup(); + gl_buf[0] = 0; + return gl_buf; +} + +SIGAR_DECLARE(int) +sigar_getline_eof() +{ + return gl_eof; +} + +SIGAR_DECLARE(char *) +sigar_getline(char *prompt) +{ + return sigar_getlinem(0, prompt); +} + +static void +gl_addchar(int c) +/* adds the character c to the input buffer at current location */ +{ + int i; + + if (gl_cnt >= BUF_SIZE - 1) + gl_error("\n*** Error: sigar_getline(): input buffer overflow\n"); + if (gl_overwrite == 0 || gl_pos == gl_cnt) { + for (i=gl_cnt; i >= gl_pos; i--) + gl_buf[i+1] = gl_buf[i]; + gl_buf[gl_pos] = c; + gl_fixup(gl_prompt, gl_pos, gl_pos+1); + } else { + gl_buf[gl_pos] = c; + gl_extent = 1; + gl_fixup(gl_prompt, gl_pos, gl_pos+1); + } +} + +static void +gl_yank() +/* adds the kill buffer to the input buffer at current location */ +{ + int i, len; + + len = strlen(gl_killbuf); + if (len > 0) { + gl_mark = gl_pos; + if (gl_overwrite == 0) { + if (gl_cnt + len >= BUF_SIZE - 1) + gl_error("\n*** Error: sigar_getline(): input buffer overflow\n"); + for (i=gl_cnt; i >= gl_pos; i--) + gl_buf[i+len] = gl_buf[i]; + for (i=0; i < len; i++) + gl_buf[gl_pos+i] = gl_killbuf[i]; + gl_fixup(gl_prompt, gl_pos, gl_pos+len); + } else { + if (gl_pos + len > gl_cnt) { + if (gl_pos + len >= BUF_SIZE - 1) + gl_error("\n*** Error: sigar_getline(): input buffer overflow\n"); + gl_buf[gl_pos + len] = 0; + } + for (i=0; i < len; i++) + gl_buf[gl_pos+i] = gl_killbuf[i]; + gl_extent = len; + gl_fixup(gl_prompt, gl_pos, gl_pos+len); + } + } else + gl_bell(); +} + +static void +gl_transpose() +/* switch character under cursor and to left of cursor */ +{ + int c; + + if (gl_pos > 0 && gl_cnt > gl_pos) { + c = gl_buf[gl_pos-1]; + gl_buf[gl_pos-1] = gl_buf[gl_pos]; + gl_buf[gl_pos] = c; + gl_extent = 2; + gl_fixup(gl_prompt, gl_pos-1, gl_pos); + } else + gl_bell(); +} + +static void +gl_newline() +/* + * Cleans up entire line before returning to caller. A \n is appended. + * If line longer than screen, we redraw starting at beginning + */ +{ + int change = gl_cnt; + int len = gl_cnt; + int loc = gl_width - 5; /* shifts line back to start position */ + + if (gl_cnt >= BUF_SIZE - 1) + gl_error("\n*** Error: sigar_getline(): input buffer overflow\n"); + if (gl_out_hook) { + change = gl_out_hook(gl_buf); + len = strlen(gl_buf); + } + if (gl_erase_line) { + char gl_buf0 = gl_buf[0]; + gl_buf[0] = '\0'; + gl_fixup("", 0, 0); + gl_buf[0] = gl_buf0; + } + else { + if (loc > len) + loc = len; + gl_fixup(gl_prompt, change, loc); /* must do this before appending \n */ + gl_putc('\n'); + } +#if 0 + gl_buf[len] = '\n'; + gl_buf[len+1] = '\0'; +#endif + gl_mark = -1; +} + +static void +gl_del(int loc) +/* + * Delete a character. The loc variable can be: + * -1 : delete character to left of cursor + * 0 : delete character under cursor + */ +{ + int i; + + if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) { + for (i=gl_pos+loc; i < gl_cnt; i++) + gl_buf[i] = gl_buf[i+1]; + gl_fixup(gl_prompt, gl_pos+loc, gl_pos+loc); + } else + gl_bell(); +} + +static void +gl_kill() +/* delete from current position to the end of line */ +{ + if (gl_pos < gl_cnt) { + strcpy(gl_killbuf, gl_buf + gl_pos); + gl_buf[gl_pos] = '\0'; + gl_fixup(gl_prompt, gl_pos, gl_pos); + } else + gl_bell(); +} + +SIGAR_DECLARE(void) sigar_getline_redraw(void) +/* emit a newline, reset and redraw prompt and current input line */ +{ + if (gl_init_done > 0) { + gl_putc('\n'); + gl_fixup(gl_prompt, -2, gl_pos); + } +} + +#define CLEAR_SCREEN "\033[2J" + +static void sigar_getline_clear_screen(void) +{ + if (gl_init_done > 0) { + gl_putc('\n'); + /* XXX what to do for non-ansi term? */ + gl_puts(CLEAR_SCREEN); + gl_fixup(gl_prompt, -2, gl_pos); + } +} + +SIGAR_DECLARE(void) sigar_getline_reset(void) +{ + gl_fixup(gl_prompt,-1,0); + gl_kill(); +} + +static void +gl_fixup(char *prompt, int change, int cursor) +/* + * This function is used both for redrawing when input changes or for + * moving within the input line. The parameters are: + * prompt: compared to last_prompt[] for changes; + * change : the index of the start of changes in the input buffer, + * with -1 indicating no changes, -2 indicating we're on + * a new line, redraw everything. + * cursor : the desired location of the cursor after the call. + * A value of BUF_SIZE can be used to indicate the cursor should + * move just past the end of the input line. + */ +{ + static int gl_shift; /* index of first on screen character */ + static int off_right; /* true if more text right of screen */ + static int off_left; /* true if more text left of screen */ + static char last_prompt[BUF_SIZE] = ""; + int left = 0, right = -1; /* bounds for redraw */ + int padl; /* how much to erase at end of line */ + int backup; /* how far to backup before fixing */ + int new_shift; /* value of shift based on cursor */ + int extra; /* adjusts when shift (scroll) happens */ + int i; + int new_right = -1; /* alternate right bound, using gl_extent */ + int l1, l2; + + if (change == -2) { /* reset */ + gl_pos = gl_cnt = gl_shift = off_right = off_left = 0; + gl_passwd = 0; + gl_puts(prompt); + gl_passwd = gl_no_echo; + strcpy(last_prompt, prompt); + change = 0; + gl_width = gl_termw - strlen(prompt); + } else if (strcmp(prompt, last_prompt) != 0) { + l1 = strlen(last_prompt); + l2 = strlen(prompt); + gl_cnt = gl_cnt + l1 - l2; + strcpy(last_prompt, prompt); + backup = gl_pos - gl_shift + l1; + for (i=0; i < backup; i++) + gl_putc('\b'); + gl_passwd = 0; + gl_puts(prompt); + gl_passwd = gl_no_echo; + gl_pos = gl_shift; + gl_width = gl_termw - l2; + change = 0; + } + padl = (off_right)? gl_width - 1 : gl_cnt - gl_shift; /* old length */ + backup = gl_pos - gl_shift; + if (change >= 0) { + gl_cnt = strlen(gl_buf); + if (change > gl_cnt) + change = gl_cnt; + } + if (cursor > gl_cnt) { + if (cursor != BUF_SIZE) /* BUF_SIZE means end of line */ + gl_bell(); + cursor = gl_cnt; + } + if (cursor < 0) { + gl_bell(); + cursor = 0; + } + if (off_right || (off_left && cursor < gl_shift + gl_width - gl_scroll / 2)) + extra = 2; /* shift the scrolling boundary */ + else + extra = 0; + new_shift = cursor + extra + gl_scroll - gl_width; + if (new_shift > 0) { + new_shift /= gl_scroll; + new_shift *= gl_scroll; + } else + new_shift = 0; + if (new_shift != gl_shift) { /* scroll occurs */ + gl_shift = new_shift; + off_left = (gl_shift)? 1 : 0; + off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0; + left = gl_shift; + new_right = right = (off_right)? gl_shift + gl_width - 2 : gl_cnt; + } else if (change >= 0) { /* no scroll, but text changed */ + if (change < gl_shift + off_left) { + left = gl_shift; + } else { + left = change; + backup = gl_pos - change; + } + off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0; + right = (off_right)? gl_shift + gl_width - 2 : gl_cnt; + new_right = (gl_extent && (right > left + gl_extent))? + left + gl_extent : right; + } + padl -= (off_right)? gl_width - 1 : gl_cnt - gl_shift; + padl = (padl < 0)? 0 : padl; + if (left <= right) { /* clean up screen */ + for (i=0; i < backup; i++) + gl_putc('\b'); + if (left == gl_shift && off_left) { + gl_putc('$'); + left++; + } + for (i=left; i < new_right; i++) + gl_putc(gl_buf[i]); + gl_pos = new_right; + if (off_right && new_right == right) { + gl_putc('$'); + gl_pos++; + } else { + for (i=0; i < padl; i++) /* erase remains of prev line */ + gl_putc(' '); + gl_pos += padl; + } + } + i = gl_pos - cursor; /* move to final cursor location */ + if (i > 0) { + while (i--) + gl_putc('\b'); + } else { + for (i=gl_pos; i < cursor; i++) + gl_putc(gl_buf[i]); + } + gl_pos = cursor; +} + +static int +gl_tab(char *buf, int offset, int *loc) +/* default tab handler, acts like tabstops every 8 cols */ +{ + int i, count, len; + + len = strlen(buf); + count = 8 - (offset + *loc) % 8; + for (i=len; i >= *loc; i--) + buf[i+count] = buf[i]; + for (i=0; i < count; i++) + buf[*loc+i] = ' '; + i = *loc; + *loc = i + count; + return i; +} + +/******************* History stuff **************************************/ + +#ifndef HIST_SIZE +#define HIST_SIZE 100 +#endif + +static int hist_pos = 0, hist_last = 0; +static char *hist_buf[HIST_SIZE]; + +static void +hist_init() +{ + int i; + + if (gl_savehist) return; + + hist_buf[0] = ""; + for (i=1; i < HIST_SIZE; i++) + hist_buf[i] = (char *)0; +} + +SIGAR_DECLARE(void) sigar_getline_completer_set(sigar_getline_completer_t func) +{ + if (func) { + gl_tab_hook = func; + } + else { + gl_tab_hook = gl_tab; + } +} + +SIGAR_DECLARE(void) +sigar_getline_histinit(char *file) +{ + char line[256]; + FILE *fp; + int nline = 1; /* prevent from becoming 0 */ + + gl_savehist = 0; + + hist_init(); + + if (!strcmp(file, "-")) return; + + sprintf(gl_histfile, "%s", file); + + fp = fopen(gl_histfile, "r"); + if (fp) + while (fgets(line, 256, fp)) { + nline++; + sigar_getline_histadd(line); + } + else + fp = fopen(gl_histfile, "w"); + + if (fp) fclose(fp); + + gl_savehist = nline; +} + +SIGAR_DECLARE(void) +sigar_getline_histadd(char *buf) +{ + static char *prev = 0; + char *p = buf; + int len; + + while (*p == ' ' || *p == '\t' || *p == '\n') + p++; + if (*p) { + len = strlen(buf); + if (strchr(p, '\n')) /* previously line already has NL stripped */ + len--; + if (prev == 0 || strlen(prev) != len || + strncmp(prev, buf, len) != 0) { + hist_buf[hist_last] = hist_save(buf); + prev = hist_buf[hist_last]; + hist_last = (hist_last + 1) % HIST_SIZE; + if (hist_buf[hist_last] && *hist_buf[hist_last]) { + free(hist_buf[hist_last]); + } + hist_buf[hist_last] = ""; + + /* append command to history file */ + if (gl_savehist) { + FILE *fp; + fp = fopen(gl_histfile, "a+"); + if (fp) { + fprintf(fp, "%s\n", prev); + gl_savehist++; + fclose(fp); + } + + /* if more than HIST_SIZE lines, safe last 60 command and delete rest */ + if (gl_savehist > HIST_SIZE) { + FILE *ftmp; + char tname[L_tmpnam]; + char line[BUFSIZ]; + + fp = fopen(gl_histfile, "r"); + tmpnam(tname); + ftmp = fopen(tname, "w"); + if (fp && ftmp) { + int nline = 0; + while (fgets(line, BUFSIZ, fp)) { + nline++; + gl_savehist = 1; /* prevent from becoming 0 */ + if (nline > HIST_SIZE-60) { + gl_savehist++; + fprintf(ftmp, "%s", line); + } + } + } + if (fp) fclose(fp); + if (ftmp) fclose(ftmp); + + /* copy back to history file */ + fp = fopen(gl_histfile, "w"); + ftmp = fopen(tname, "r"); + if (fp && ftmp) + while (fgets(line, BUFSIZ, ftmp)) + fprintf(fp, "%s", line); + + if (fp) fclose(fp); + if (ftmp) fclose(ftmp); + remove(tname); + } + } + } + } + hist_pos = hist_last; +} + +static char * +hist_prev() +/* loads previous hist entry into input buffer, sticks on first */ +{ + char *p = 0; + int next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE; + + if (hist_buf[hist_pos] != 0 && next != hist_last) { + hist_pos = next; + p = hist_buf[hist_pos]; + } + if (p == 0) { + p = ""; + gl_bell(); + } + return p; +} + +static char * +hist_next() +/* loads next hist entry into input buffer, clears on last */ +{ + char *p = 0; + + if (hist_pos != hist_last) { + hist_pos = (hist_pos+1) % HIST_SIZE; + p = hist_buf[hist_pos]; + } + if (p == 0) { + p = ""; + gl_bell(); + } + return p; +} + +static char * +hist_save(char *p) +/* makes a copy of the string */ +{ + char *s = 0; + int len = strlen(p); + char *nl = strchr(p, '\n'); + + if (nl) { + if ((s = (char *)malloc(len)) != 0) { + strncpy(s, p, len-1); + s[len-1] = 0; + } + } else { + if ((s = (char *)malloc(len+1)) != 0) { + strcpy(s, p); + } + } + if (s == 0) + gl_error("\n*** Error: hist_save() failed on malloc\n"); + return s; +} + +/******************* Search stuff **************************************/ + +static char search_prompt[101]; /* prompt includes search string */ +static char search_string[100]; +static int search_pos = 0; /* current location in search_string */ +static int search_forw_flg = 0; /* search direction flag */ +static int search_last = 0; /* last match found */ + +static void +search_update(int c) +{ + if (c == 0) { + search_pos = 0; + search_string[0] = 0; + search_prompt[0] = '?'; + search_prompt[1] = ' '; + search_prompt[2] = 0; + } else if (c > 0) { + search_string[search_pos] = c; + search_string[search_pos+1] = 0; + search_prompt[search_pos] = c; + search_prompt[search_pos+1] = '?'; + search_prompt[search_pos+2] = ' '; + search_prompt[search_pos+3] = 0; + search_pos++; + } else { + if (search_pos > 0) { + search_pos--; + search_string[search_pos] = 0; + search_prompt[search_pos] = '?'; + search_prompt[search_pos+1] = ' '; + search_prompt[search_pos+2] = 0; + } else { + gl_bell(); + hist_pos = hist_last; + } + } +} + +static void +search_addchar(int c) +{ + char *loc; + + search_update(c); + if (c < 0) { + if (search_pos > 0) { + hist_pos = search_last; + } else { + gl_buf[0] = 0; + hist_pos = hist_last; + } + strcpy(gl_buf, hist_buf[hist_pos]); + } + if ((loc = strstr(gl_buf, search_string)) != 0) { + gl_fixup(search_prompt, 0, loc - gl_buf); + } else if (search_pos > 0) { + if (search_forw_flg) { + search_forw(0); + } else { + search_back(0); + } + } else { + gl_fixup(search_prompt, 0, 0); + } +} + +static void +search_term() +{ + gl_search_mode = 0; + if (gl_buf[0] == 0) /* not found, reset hist list */ + hist_pos = hist_last; + if (gl_in_hook) + gl_in_hook(gl_buf); + gl_fixup(gl_prompt, 0, gl_pos); +} + +static void +search_back(int new_search) +{ + int found = 0; + char *p, *loc; + + search_forw_flg = 0; + if (gl_search_mode == 0) { + search_last = hist_pos = hist_last; + search_update(0); + gl_search_mode = 1; + gl_buf[0] = 0; + gl_fixup(search_prompt, 0, 0); + } else if (search_pos > 0) { + while (!found) { + p = hist_prev(); + if (*p == 0) { /* not found, done looking */ + gl_buf[0] = 0; + gl_fixup(search_prompt, 0, 0); + found = 1; + } else if ((loc = strstr(p, search_string)) != 0) { + strcpy(gl_buf, p); + gl_fixup(search_prompt, 0, loc - p); + if (new_search) + search_last = hist_pos; + found = 1; + } + } + } else { + gl_bell(); + } +} + +static void +search_forw(int new_search) +{ + int found = 0; + char *p, *loc; + + search_forw_flg = 1; + if (gl_search_mode == 0) { + search_last = hist_pos = hist_last; + search_update(0); + gl_search_mode = 1; + gl_buf[0] = 0; + gl_fixup(search_prompt, 0, 0); + } else if (search_pos > 0) { + while (!found) { + p = hist_next(); + if (*p == 0) { /* not found, done looking */ + gl_buf[0] = 0; + gl_fixup(search_prompt, 0, 0); + found = 1; + } else if ((loc = strstr(p, search_string)) != 0) { + strcpy(gl_buf, p); + gl_fixup(search_prompt, 0, loc - p); + if (new_search) + search_last = hist_pos; + found = 1; + } + } + } else { + gl_bell(); + } +} +#if 0 +/*********************************************************************** + * * + * Strip blanks from both sides of a string. Space for the new * + * string is allocated and a pointer to it is returned. * + * * + ***********************************************************************/ +char *strip(char *s) +{ + char *r, *t1, *t2; + int l; + + l = strlen(s); + r = (char *)calloc(l+1, 1); + + if (l == 0) { + *r = '\0'; + return r; + } + + /* get rid of leading blanks */ + t1 = s; + while (*t1 == ' ') + t1++; + + t2 = s + l - 1; + while (*t2 == ' ' && t2 > s) + t2--; + + if (t1 > t2) { + *r = '\0'; + return r; + } + strncpy(r, t1, (size_t) (t2-t1+1)); + + return r; +} +#endif +/*****************************************************************************/ +/* Extra routine provided by Christian Lacunza */ +/*****************************************************************************/ + +/* move cursor back to beginning of _current_ word */ +/* unless it's already at the beginning, */ +/* in which case it moves back to the beginning */ +/* of the _previous_ word. */ +static void gl_back_1_word( void ) +{ + int i = gl_pos; + + /* if we're at the beginning of a word, */ + /* slip back into the preceeding whitespace */ + if( i>0 && is_whitespace(gl_buf[i-1]) ) { + i-=1; + } + + /* now move back over all consecutive whitespace */ + while( i>0 && is_whitespace(gl_buf[i]) ) { + i-=1; + } + + /* now keep moving back over all consecutive non-whitespace */ + /* until we find the beginning of this word. */ + /* ie. stop just before more whitespace shows up. */ + while( i>0 && !is_whitespace(gl_buf[i-1]) ) { + i-=1; + } + + /* move the cursor here */ + gl_fixup(gl_prompt, -1, i); +} + +/* kills from current position to end of word */ +static void gl_kill_1_word( void ) +{ + int i = gl_pos; + int j = gl_pos; + +/* delete this: */ +#if 0 + /* not sure what to do with "punctuation" */ + if( is_whitespace(gl_buf[j]) && gl_buf[j]!=' ' ) { + return; + } + /* first find a word */ + while( j + +#ifdef SIGAR_HAS_PCRE +#include "pcre.h" +#endif + +/* See http://gcc.gnu.org/ml/libstdc++/2002-03/msg00164.html */ +#if defined(WIN32) || (defined(__hpux) && defined(SIGAR_64BIT)) +#define strtoull strtoul +#elif (defined(__hpux) && !defined(SIGAR_64BIT)) +#define strtoull __strtoull +#else +#include +#endif + +#define SIGAR_CLEAR_ERRNO() errno = 0 + +#define strtonum_failed(src, ptr) \ + ((src == ptr) || (errno == ERANGE) || (*ptr != '\0')) + +typedef struct ptql_parse_branch_t ptql_parse_branch_t; +typedef struct ptql_branch_t ptql_branch_t; + +/* adhere to calling convention, else risk stack corruption */ +#ifdef WIN32 +#define SIGAPI WINAPI +#else +#define SIGAPI +#endif + +typedef int (SIGAPI *ptql_get_t)(sigar_t *sigar, sigar_pid_t pid, void *data); +typedef int (*ptql_branch_init_t)(ptql_parse_branch_t *parsed, ptql_branch_t *branch, + sigar_ptql_error_t *error); + +typedef int (*ptql_op_ui64_t)(ptql_branch_t *branch, + sigar_uint64_t haystack, + sigar_uint64_t needle); + +typedef int (*ptql_op_ui32_t)(ptql_branch_t *branch, + sigar_uint32_t haystack, + sigar_uint32_t needle); + +typedef int (*ptql_op_dbl_t)(ptql_branch_t *branch, + double haystack, + double needle); + +typedef int (*ptql_op_str_t)(ptql_branch_t *branch, + char *haystack, + char *needle); + +typedef int (*ptql_op_chr_t)(ptql_branch_t *branch, + char haystack, + char needle); + +typedef enum { + PTQL_VALUE_TYPE_UI64, + PTQL_VALUE_TYPE_UI32, + PTQL_VALUE_TYPE_DBL, + PTQL_VALUE_TYPE_CHR, + PTQL_VALUE_TYPE_STR, + PTQL_VALUE_TYPE_ANY +} ptql_value_type_t; + +typedef enum { + PTQL_OP_EQ, + PTQL_OP_NE, + PTQL_OP_GT, + PTQL_OP_GE, + PTQL_OP_LT, + PTQL_OP_LE, +#define PTQL_OP_MAX_NSTR PTQL_OP_LE + PTQL_OP_EW, /* rest are string only */ + PTQL_OP_SW, + PTQL_OP_RE, + PTQL_OP_CT, + PTQL_OP_MAX +} ptql_op_name_t; + +#define PTQL_OP_FLAG_PARENT 1 +#define PTQL_OP_FLAG_REF 2 +#define PTQL_OP_FLAG_GLOB 4 +#define PTQL_OP_FLAG_PID 8 +#define PTQL_OP_FLAG_ICASE 16 + +struct ptql_parse_branch_t { + char *name; + char *attr; + char *op; + char *value; + unsigned int op_flags; +}; + +typedef struct { + char *name; + ptql_get_t get; + size_t offset; + unsigned int data_size; + ptql_value_type_t type; + ptql_branch_init_t init; +} ptql_lookup_t; + +#define DATA_PTR(branch) \ + ((char *)branch->data.ptr + branch->lookup->offset) + +#define IS_ICASE(branch) \ + (branch->op_flags & PTQL_OP_FLAG_ICASE) + +#define branch_strcmp(branch, s1, s2) \ + (IS_ICASE(branch) ? strcasecmp(s1, s2) : strcmp(s1, s2)) + +#define branch_strncmp(branch, s1, s2, n) \ + (IS_ICASE(branch) ? strncasecmp(s1, s2, n) : strncmp(s1, s2, n)) + +#define branch_strEQ(branch, s1, s2) \ + (branch_strcmp(branch, s1, s2) == 0) + +#define branch_strnEQ(branch, s1, s2, n) \ + (branch_strncmp(branch, s1, s2, n) == 0) + +#define branch_strstr(branch, s1, s2) \ + (IS_ICASE(branch) ? sigar_strcasestr(s1, s2) : strstr(s1, s2)) + +#define IS_PID_SERVICE_QUERY(branch) \ + (branch->flags >= PTQL_PID_SERVICE_NAME) + +static void data_free(void *data) +{ + free(data); +} + +typedef union { + sigar_pid_t pid; + sigar_uint64_t ui64; + sigar_uint32_t ui32; + double dbl; + char chr[4]; + char *str; + void *ptr; +} any_value_t; + +struct ptql_branch_t { + ptql_lookup_t *lookup; + any_value_t data; + unsigned int data_size; + void (*data_free)(void *); + unsigned int flags; + unsigned int op_flags; + ptql_op_name_t op_name; + union { + ptql_op_ui64_t ui64; + ptql_op_ui32_t ui32; + ptql_op_dbl_t dbl; + ptql_op_chr_t chr; + ptql_op_str_t str; + } match; + any_value_t value; + void (*value_free)(void *); +}; + +typedef struct { + char *name; + ptql_lookup_t *members; +} ptql_entry_t; + +typedef struct { + unsigned long number; + unsigned long size; + ptql_branch_t *data; +} ptql_branch_list_t; + +struct sigar_ptql_query_t { + ptql_branch_list_t branches; +#ifdef PTQL_DEBUG + char *ptql; +#endif +}; + +/* XXX optimize */ +static ptql_op_name_t ptql_op_code_get(char *op) +{ + if (strEQ(op, "eq")) { + return PTQL_OP_EQ; + } + else if (strEQ(op, "ne")) { + return PTQL_OP_NE; + } + else if (strEQ(op, "gt")) { + return PTQL_OP_GT; + } + else if (strEQ(op, "ge")) { + return PTQL_OP_GE; + } + else if (strEQ(op, "lt")) { + return PTQL_OP_LT; + } + else if (strEQ(op, "le")) { + return PTQL_OP_LE; + } + else if (strEQ(op, "ew")) { + return PTQL_OP_EW; + } + else if (strEQ(op, "sw")) { + return PTQL_OP_SW; + } + else if (strEQ(op, "re")) { + return PTQL_OP_RE; + } + else if (strEQ(op, "ct")) { + return PTQL_OP_CT; + } + else { + return PTQL_OP_MAX; + } +} + +static int ptql_op_ui64_eq(ptql_branch_t *branch, + sigar_uint64_t haystack, sigar_uint64_t needle) +{ + return haystack == needle; +} + +static int ptql_op_ui64_ne(ptql_branch_t *branch, + sigar_uint64_t haystack, sigar_uint64_t needle) +{ + return haystack != needle; +} + +static int ptql_op_ui64_gt(ptql_branch_t *branch, + sigar_uint64_t haystack, sigar_uint64_t needle) +{ + return haystack > needle; +} + +static int ptql_op_ui64_ge(ptql_branch_t *branch, + sigar_uint64_t haystack, sigar_uint64_t needle) +{ + return haystack >= needle; +} + +static int ptql_op_ui64_lt(ptql_branch_t *branch, + sigar_uint64_t haystack, sigar_uint64_t needle) +{ + return haystack < needle; +} + +static int ptql_op_ui64_le(ptql_branch_t *branch, + sigar_uint64_t haystack, sigar_uint64_t needle) +{ + return haystack <= needle; +} + +static ptql_op_ui64_t ptql_op_ui64[] = { + ptql_op_ui64_eq, + ptql_op_ui64_ne, + ptql_op_ui64_gt, + ptql_op_ui64_ge, + ptql_op_ui64_lt, + ptql_op_ui64_le +}; + +static int ptql_op_ui32_eq(ptql_branch_t *branch, + sigar_uint32_t haystack, sigar_uint32_t needle) +{ + return haystack == needle; +} + +static int ptql_op_ui32_ne(ptql_branch_t *branch, + sigar_uint32_t haystack, sigar_uint32_t needle) +{ + return haystack != needle; +} + +static int ptql_op_ui32_gt(ptql_branch_t *branch, + sigar_uint32_t haystack, sigar_uint32_t needle) +{ + return haystack > needle; +} + +static int ptql_op_ui32_ge(ptql_branch_t *branch, + sigar_uint32_t haystack, sigar_uint32_t needle) +{ + return haystack >= needle; +} + +static int ptql_op_ui32_lt(ptql_branch_t *branch, + sigar_uint32_t haystack, sigar_uint32_t needle) +{ + return haystack < needle; +} + +static int ptql_op_ui32_le(ptql_branch_t *branch, + sigar_uint32_t haystack, sigar_uint32_t needle) +{ + return haystack <= needle; +} + +static ptql_op_ui32_t ptql_op_ui32[] = { + ptql_op_ui32_eq, + ptql_op_ui32_ne, + ptql_op_ui32_gt, + ptql_op_ui32_ge, + ptql_op_ui32_lt, + ptql_op_ui32_le +}; + +static int ptql_op_dbl_eq(ptql_branch_t *branch, + double haystack, double needle) +{ + return haystack == needle; +} + +static int ptql_op_dbl_ne(ptql_branch_t *branch, + double haystack, double needle) +{ + return haystack != needle; +} + +static int ptql_op_dbl_gt(ptql_branch_t *branch, + double haystack, double needle) +{ + return haystack > needle; +} + +static int ptql_op_dbl_ge(ptql_branch_t *branch, + double haystack, double needle) +{ + return haystack >= needle; +} + +static int ptql_op_dbl_lt(ptql_branch_t *branch, + double haystack, double needle) +{ + return haystack < needle; +} + +static int ptql_op_dbl_le(ptql_branch_t *branch, + double haystack, double needle) +{ + return haystack <= needle; +} + +static ptql_op_dbl_t ptql_op_dbl[] = { + ptql_op_dbl_eq, + ptql_op_dbl_ne, + ptql_op_dbl_gt, + ptql_op_dbl_ge, + ptql_op_dbl_lt, + ptql_op_dbl_le +}; + +static int ptql_op_str_eq(ptql_branch_t *branch, + char *haystack, char *needle) +{ + return branch_strEQ(branch, haystack, needle); +} + +static int ptql_op_str_ne(ptql_branch_t *branch, + char *haystack, char *needle) +{ + return !branch_strEQ(branch, haystack, needle); +} + +static int ptql_op_str_gt(ptql_branch_t *branch, + char *haystack, char *needle) +{ + return branch_strcmp(branch, haystack, needle) > 0; +} + +static int ptql_op_str_ge(ptql_branch_t *branch, + char *haystack, char *needle) +{ + return branch_strcmp(branch, haystack, needle) >= 0; +} + +static int ptql_op_str_lt(ptql_branch_t *branch, + char *haystack, char *needle) +{ + return branch_strcmp(branch, haystack, needle) < 0; +} + +static int ptql_op_str_le(ptql_branch_t *branch, + char *haystack, char *needle) +{ + return branch_strcmp(branch, haystack, needle) <= 0; +} + +static int ptql_op_str_ew(ptql_branch_t *branch, + char *haystack, char *needle) +{ + int nlen = strlen(needle); + int hlen = strlen(haystack); + int diff = hlen - nlen; + if (diff < 0) { + return 0; + } + return branch_strnEQ(branch, haystack + diff, needle, nlen); +} + +static int ptql_op_str_sw(ptql_branch_t *branch, + char *haystack, char *needle) +{ + return branch_strnEQ(branch, haystack, needle, strlen(needle)); +} + +static int ptql_op_str_re(ptql_branch_t *branch, + char *haystack, char *needle) +{ +#ifdef SIGAR_HAS_PCRE + pcre *re = (pcre *)branch->value.ptr; + int len = strlen(haystack); + int rc = + pcre_exec(re, NULL, haystack, len, 0, 0, NULL, 0); + return rc >= 0; +#else + return 0; +#endif +} + +static int ptql_op_str_ct(ptql_branch_t *branch, + char *haystack, char *needle) +{ + return branch_strstr(branch, haystack, needle) != NULL; +} + +static ptql_op_str_t ptql_op_str[] = { + ptql_op_str_eq, + ptql_op_str_ne, + ptql_op_str_gt, + ptql_op_str_ge, + ptql_op_str_lt, + ptql_op_str_le, + ptql_op_str_ew, + ptql_op_str_sw, + ptql_op_str_re, + ptql_op_str_ct +}; + +static int ptql_op_chr_eq(ptql_branch_t *branch, + char haystack, char needle) +{ + return haystack == needle; +} + +static int ptql_op_chr_ne(ptql_branch_t *branch, + char haystack, char needle) +{ + return haystack != needle; +} + +static int ptql_op_chr_gt(ptql_branch_t *branch, + char haystack, char needle) +{ + return haystack > needle; +} + +static int ptql_op_chr_ge(ptql_branch_t *branch, + char haystack, char needle) +{ + return haystack >= needle; +} + +static int ptql_op_chr_lt(ptql_branch_t *branch, + char haystack, char needle) +{ + return haystack < needle; +} + +static int ptql_op_chr_le(ptql_branch_t *branch, + char haystack, char needle) +{ + return haystack <= needle; +} + +static ptql_op_chr_t ptql_op_chr[] = { + ptql_op_chr_eq, + ptql_op_chr_ne, + ptql_op_chr_gt, + ptql_op_chr_ge, + ptql_op_chr_lt, + ptql_op_chr_le +}; + +#define PTQL_BRANCH_LIST_MAX 3 + +#define PTQL_BRANCH_LIST_GROW(branches) \ + if ((branches)->number >= (branches)->size) { \ + ptql_branch_list_grow(branches); \ + } + +static int ptql_branch_list_create(ptql_branch_list_t *branches) +{ + branches->number = 0; + branches->size = PTQL_BRANCH_LIST_MAX; + branches->data = malloc(sizeof(*(branches->data)) * + branches->size); + + return SIGAR_OK; +} + +static int ptql_branch_list_grow(ptql_branch_list_t *branches) +{ + branches->data = + realloc(branches->data, + sizeof(*(branches->data)) * + (branches->size + PTQL_BRANCH_LIST_MAX)); + branches->size += PTQL_BRANCH_LIST_MAX; + + return SIGAR_OK; +} + +static int ptql_branch_list_destroy(ptql_branch_list_t *branches) +{ + if (branches->size) { + int i; + + for (i=0; inumber; i++) { + ptql_branch_t *branch = + &branches->data[i]; + + if (branch->data_size && branch->data.ptr) { + branch->data_free(branch->data.ptr); + } + + if (branch->lookup && + ((branch->lookup->type == PTQL_VALUE_TYPE_STR) || + (branch->lookup->type == PTQL_VALUE_TYPE_ANY)) && + !(branch->op_flags & PTQL_OP_FLAG_REF)) + { + if (branch->value.str) { + branch->value_free(branch->value.str); + } + } + } + + free(branches->data); + branches->number = branches->size = 0; + } + + return SIGAR_OK; +} + +#ifdef WIN32 +#define vsnprintf _vsnprintf +#endif + +#define PTQL_ERRNAN \ + ptql_error(error, "Query value '%s' is not a number", parsed->value) + +static int ptql_error(sigar_ptql_error_t *error, const char *format, ...) +{ + va_list args; + + if (error != NULL) { + va_start(args, format); + vsnprintf(error->message, sizeof(error->message), format, args); + va_end(args); + } + + return SIGAR_PTQL_MALFORMED_QUERY; +} + +static int ptql_branch_init_any(ptql_parse_branch_t *parsed, + ptql_branch_t *branch, + sigar_ptql_error_t *error) +{ + branch->data.str = sigar_strdup(parsed->attr); + branch->data_size = strlen(parsed->attr); + return SIGAR_OK; +} + +static int ptql_str_match(sigar_t *sigar, ptql_branch_t *branch, char *value) +{ + if (!branch->value.str) { + return 0; + } +#ifndef SIGAR_HAS_PCRE + if (branch->op_name == PTQL_OP_RE) { + if (sigar->ptql_re_impl) { + return sigar->ptql_re_impl(sigar->ptql_re_data, + value, + branch->value.str); + } + else { + return 0; + } + } +#endif + return branch->match.str(branch, + value, + branch->value.str); +} + +static int ptql_branch_match(ptql_branch_t *branch) +{ + switch (branch->lookup->type) { + case PTQL_VALUE_TYPE_UI64: + return branch->match.ui64(branch, + *(sigar_uint64_t *)DATA_PTR(branch), + branch->value.ui64); + case PTQL_VALUE_TYPE_UI32: + return branch->match.ui32(branch, + *(sigar_uint32_t *)DATA_PTR(branch), + branch->value.ui32); + case PTQL_VALUE_TYPE_DBL: + return branch->match.dbl(branch, + *(double *)DATA_PTR(branch), + branch->value.dbl); + case PTQL_VALUE_TYPE_CHR: + return branch->match.chr(branch, + *(char *)DATA_PTR(branch), + branch->value.chr[0]); + case PTQL_VALUE_TYPE_STR: + case PTQL_VALUE_TYPE_ANY: + if (!branch->value.str) { + return 0; + } + return branch->match.str(branch, + (char *)DATA_PTR(branch), + branch->value.str); + default: + return 0; + } +} + +static int ptql_branch_match_ref(ptql_branch_t *branch, ptql_branch_t *ref) +{ + switch (branch->lookup->type) { + case PTQL_VALUE_TYPE_UI64: + return branch->match.ui64(branch, + *(sigar_uint64_t *)DATA_PTR(branch), + *(sigar_uint64_t *)DATA_PTR(ref)); + case PTQL_VALUE_TYPE_UI32: + return branch->match.ui32(branch, + *(sigar_uint32_t *)DATA_PTR(branch), + *(sigar_uint32_t *)DATA_PTR(ref)); + case PTQL_VALUE_TYPE_DBL: + return branch->match.dbl(branch, + *(double *)DATA_PTR(branch), + *(double *)DATA_PTR(ref)); + case PTQL_VALUE_TYPE_CHR: + return branch->match.chr(branch, + *(char *)DATA_PTR(branch), + *(char *)DATA_PTR(ref)); + case PTQL_VALUE_TYPE_STR: + case PTQL_VALUE_TYPE_ANY: + return branch->match.str(branch, + (char *)DATA_PTR(branch), + (char *)DATA_PTR(ref)); + default: + return 0; + } +} + +enum { + PTQL_PID_PID, + PTQL_PID_FILE, + PTQL_PID_SUDO_FILE, + PTQL_PID_TCP_PORT, + PTQL_PID_UDP_PORT, + PTQL_PID_SERVICE_NAME, + PTQL_PID_SERVICE_DISPLAY, + PTQL_PID_SERVICE_PATH, + PTQL_PID_SERVICE_EXE, + PTQL_PID_SERVICE_PID +}; + +#ifdef SIGAR_64BIT + +#define str2pid(value, ptr) strtoull(value, &ptr, 10) + +#define pid_branch_match(branch, pid, match_pid) \ + ptql_op_ui64[branch->op_name](branch, pid, match_pid) + +#else + +#define str2pid(value, ptr) strtoul(value, &ptr, 10) + +#define pid_branch_match(branch, pid, match_pid) \ + ptql_op_ui32[branch->op_name](branch, pid, match_pid) + +#endif + +#ifndef WIN32 +#include +int sigar_sudo_file2str(const char *fname, char *buffer, int buflen) +{ + FILE *fp; + struct stat sb; + + if (stat(fname, &sb) < 0) { + return errno; + } + if (sb.st_size > buflen) { + return ENOMEM; + } + snprintf(buffer, buflen, "sudo cat %s", fname); + if (!(fp = popen(buffer, "r"))) { + return errno; + } + (void)fgets(buffer, buflen, fp); + pclose(fp); + + return SIGAR_OK; +} +#endif + +static int ptql_branch_init_service(ptql_parse_branch_t *parsed, + ptql_branch_t *branch, + sigar_ptql_error_t *error) +{ + branch->op_flags |= PTQL_OP_FLAG_PID; + + if (strEQ(parsed->attr, "Name")) { + branch->flags = PTQL_PID_SERVICE_NAME; + } + else if (strEQ(parsed->attr, "DisplayName")) { + branch->flags = PTQL_PID_SERVICE_DISPLAY; + } + else if (strEQ(parsed->attr, "Path")) { + branch->flags = PTQL_PID_SERVICE_PATH; + } + else if (strEQ(parsed->attr, "Exe")) { + /* basename of Path */ + branch->flags = PTQL_PID_SERVICE_EXE; + } + else if (strEQ(parsed->attr, "Pid")) { + branch->flags = PTQL_PID_SERVICE_PID; + } + else { + return ptql_error(error, "Unsupported %s attribute: %s", + parsed->name, parsed->attr); + } + +#ifdef WIN32 + branch->data.str = sigar_strdup(parsed->value); + branch->data_size = strlen(parsed->value); +#endif + return SIGAR_OK; +} + +static int ptql_branch_init_pid(ptql_parse_branch_t *parsed, + ptql_branch_t *branch, + sigar_ptql_error_t *error) +{ + int use_sudo = 0; + branch->op_flags |= PTQL_OP_FLAG_PID; + + if (strEQ(parsed->attr, "Pid")) { + branch->flags = PTQL_PID_PID; + if (strEQ(parsed->value, "$$")) { + branch->data.pid = getpid(); + } + else { + char *ptr; + SIGAR_CLEAR_ERRNO(); + branch->data.pid = str2pid(parsed->value, ptr); + if (strtonum_failed(parsed->value, ptr)) { + return PTQL_ERRNAN; + } + } + return SIGAR_OK; + } + else if (strEQ(parsed->attr, "PidFile") || + (use_sudo = strEQ(parsed->attr, "SudoPidFile"))) + { + branch->flags = use_sudo ? PTQL_PID_SUDO_FILE : PTQL_PID_FILE; + branch->data.str = sigar_strdup(parsed->value); + branch->data_size = strlen(parsed->value); + return SIGAR_OK; + } + + return ptql_error(error, "Unsupported %s attribute: %s", + parsed->name, parsed->attr); +} + +#ifdef WIN32 +#define QUERY_SC_SIZE 8192 + +static int ptql_service_query_config(SC_HANDLE scm_handle, + char *name, + LPQUERY_SERVICE_CONFIG config) +{ + int status; + DWORD bytes; + SC_HANDLE handle = + OpenService(scm_handle, name, SERVICE_QUERY_CONFIG); + + if (!handle) { + return GetLastError(); + } + + if (QueryServiceConfig(handle, config, QUERY_SC_SIZE, &bytes)) { + status = SIGAR_OK; + } + else { + status = GetLastError(); + } + + CloseServiceHandle(handle); + return status; +} + +static int sigar_services_walk(sigar_services_walker_t *walker, + ptql_branch_t *branch) +{ + sigar_services_status_t ss; + char buffer[QUERY_SC_SIZE]; + char exe[SIGAR_CMDLINE_MAX]; + LPQUERY_SERVICE_CONFIG config = (LPQUERY_SERVICE_CONFIG)buffer; + DWORD i, status; + + SIGAR_ZERO(&ss); + status = sigar_services_status_get(&ss, walker->flags); + if (status != SIGAR_OK) { + return status; + } + for (i=0; iadd_service(walker, name) != SIGAR_OK) { + break; + } + continue; + } + + switch (branch->flags) { + case PTQL_PID_SERVICE_DISPLAY: + value = ss.services[i].lpDisplayName; + break; + case PTQL_PID_SERVICE_PATH: + case PTQL_PID_SERVICE_EXE: + status = ptql_service_query_config(ss.handle, name, config); + if (status == SIGAR_OK) { + if (branch->flags == PTQL_PID_SERVICE_EXE) { + value = + sigar_service_exe_get(config->lpBinaryPathName, + exe, 1); + } + else { + value = config->lpBinaryPathName; + } + } + else { + continue; + } + break; + case PTQL_PID_SERVICE_PID: + sigar_service_pid_get(walker->sigar, + name, + &service_pid); + break; + case PTQL_PID_SERVICE_NAME: + default: + value = name; + break; + } + + if ((value && ptql_str_match(walker->sigar, branch, value)) || + (service_pid && + pid_branch_match(branch, service_pid, atoi(branch->data.str)))) + { + if (walker->add_service(walker, name) != SIGAR_OK) { + break; + } + } + } + + sigar_services_status_close(&ss); + + return SIGAR_OK; +} + +static int ptql_pid_service_add(sigar_services_walker_t *walker, + char *name) +{ + sigar_pid_t service_pid; + sigar_proc_list_t *proclist = + (sigar_proc_list_t *)walker->data; + int status = + sigar_service_pid_get(walker->sigar, + name, + &service_pid); + + if (status == SIGAR_OK) { + SIGAR_PROC_LIST_GROW(proclist); + proclist->data[proclist->number++] = service_pid; + } + + return SIGAR_OK; +} + +static int ptql_pid_service_list_get(sigar_t *sigar, + ptql_branch_t *branch, + sigar_proc_list_t *proclist) +{ + sigar_services_walker_t walker; + walker.sigar = sigar; + walker.flags = SERVICE_ACTIVE; + walker.data = proclist; + walker.add_service = ptql_pid_service_add; + + return sigar_services_walk(&walker, branch); +} + +int sigar_services_query(char *ptql, + sigar_ptql_error_t *error, + sigar_services_walker_t *walker) +{ + int status; + sigar_ptql_query_t *query; + + if (ptql == NULL) { + return sigar_services_walk(walker, NULL); + } + + status = sigar_ptql_query_create(&query, (char *)ptql, error); + if (status != SIGAR_OK) { + return status; + } + + if (query->branches.number == 1) { + ptql_branch_t *branch = &query->branches.data[0]; + + if (IS_PID_SERVICE_QUERY(branch)) { + status = sigar_services_walk(walker, branch); + } + else { + ptql_error(error, "Invalid Service query: %s", ptql); + status = SIGAR_PTQL_MALFORMED_QUERY; + } + } + else { + ptql_error(error, "Too many queries (%d), must be (1)", + query->branches.number); + status = SIGAR_PTQL_MALFORMED_QUERY; + } + + sigar_ptql_query_destroy(query); + + return status; +} +#endif + +static int ptql_pid_port_get(sigar_t *sigar, + ptql_branch_t *branch, + sigar_pid_t *pid) +{ + unsigned long port = + branch->data.ui32; + int status; + int proto = + branch->flags == PTQL_PID_UDP_PORT ? + SIGAR_NETCONN_UDP : SIGAR_NETCONN_TCP; + + status = + sigar_proc_port_get(sigar, proto, port, pid); + + return status; +} + +static int ptql_pid_get(sigar_t *sigar, + ptql_branch_t *branch, + sigar_pid_t *pid) +{ + if ((branch->flags == PTQL_PID_FILE) || + (branch->flags == PTQL_PID_SUDO_FILE)) + { + char *ptr, buffer[SIGAR_PATH_MAX+1]; + const char *fname = (const char *)branch->data.str; + int status, len = sizeof(buffer)-1; + + if (branch->flags == PTQL_PID_FILE) { + status = sigar_file2str(fname, buffer, len); + } + else { +#ifdef WIN32 + return SIGAR_ENOTIMPL; +#else + status = sigar_sudo_file2str(fname, buffer, len); +#endif + } + if (status != SIGAR_OK) { + return status; + } + SIGAR_CLEAR_ERRNO(); + *pid = str2pid(buffer, ptr); + if ((buffer == ptr) || (errno == ERANGE)) { + return errno; + } + } + else if (branch->flags == PTQL_PID_SERVICE_NAME) { +#ifdef WIN32 + int status = + sigar_service_pid_get(sigar, + branch->data.str, pid); + if (status != SIGAR_OK) { + return status; + } +#else + return SIGAR_ENOTIMPL; +#endif + } + else if ((branch->flags == PTQL_PID_UDP_PORT) || + (branch->flags == PTQL_PID_TCP_PORT)) + { + int status = ptql_pid_port_get(sigar, branch, pid); + if (status != SIGAR_OK) { + return status; + } + } + else { + *pid = branch->data.pid; + } + + return SIGAR_OK; +} + +static int ptql_pid_list_get(sigar_t *sigar, + ptql_branch_t *branch, + sigar_proc_list_t *proclist) +{ + int status, i; + sigar_pid_t match_pid; + + if (IS_PID_SERVICE_QUERY(branch)) { + if ((branch->flags > PTQL_PID_SERVICE_NAME) || + (branch->op_name != PTQL_OP_EQ)) + { +#ifdef WIN32 + return ptql_pid_service_list_get(sigar, branch, proclist); +#else + return SIGAR_OK; /* no matches */ +#endif + } + } + + status = ptql_pid_get(sigar, branch, &match_pid); + + if (status != SIGAR_OK) { + /* XXX treated as non-match but would be nice to propagate */ + return SIGAR_OK; + } + + status = sigar_proc_list_get(sigar, NULL); + if (status != SIGAR_OK) { + return status; + } + for (i=0; ipids->number; i++) { + sigar_pid_t pid = sigar->pids->data[i]; + if (pid_branch_match(branch, pid, match_pid)) { + SIGAR_PROC_LIST_GROW(proclist); + proclist->data[proclist->number++] = pid; + } + } + + return SIGAR_OK; +} + +static int SIGAPI ptql_pid_match(sigar_t *sigar, + sigar_pid_t pid, + void *data) +{ + /* query already used to filter proc_list */ + return SIGAR_OK; +} + +static int ptql_args_branch_init(ptql_parse_branch_t *parsed, + ptql_branch_t *branch, + sigar_ptql_error_t *error) +{ + if (strEQ(parsed->attr, "*")) { + branch->op_flags |= PTQL_OP_FLAG_GLOB; + } + else { + char *end; + + SIGAR_CLEAR_ERRNO(); + branch->data.ui32 = + strtol(parsed->attr, &end, 10); + + if (strtonum_failed(parsed->attr, end)) { + /* conversion failed */ + return ptql_error(error, "%s is not a number", parsed->attr); + } + } + return SIGAR_OK; +} + +static int SIGAPI ptql_args_match(sigar_t *sigar, + sigar_pid_t pid, + void *data) +{ + ptql_branch_t *branch = + (ptql_branch_t *)data; + int status, matched=0; + sigar_proc_args_t args; + + status = sigar_proc_args_get(sigar, pid, &args); + if (status != SIGAR_OK) { + return status; + } + + if (branch->op_flags & PTQL_OP_FLAG_GLOB) { + int i; + for (i=0; idata.ui32; + + /* e.g. find last element of args: Args.-1.eq=weblogic.Server */ + if (num < 0) { + num += args.number; + } + if ((num >= 0) && (num < args.number)) { + matched = + ptql_str_match(sigar, branch, args.data[num]); + } + } + + sigar_proc_args_destroy(sigar, &args); + + return matched ? SIGAR_OK : !SIGAR_OK; +} + +typedef struct { + sigar_t *sigar; + ptql_branch_t *branch; + sigar_uint32_t ix; + int matched; +} proc_modules_match_t; + +static int proc_modules_match(void *data, char *name, int len) +{ + proc_modules_match_t *matcher = + (proc_modules_match_t *)data; + ptql_branch_t *branch = matcher->branch; + + if (branch->op_flags & PTQL_OP_FLAG_GLOB) { /* Modules.*.ct=libc */ + matcher->matched = + ptql_str_match(matcher->sigar, branch, name); + + if (matcher->matched) { + return !SIGAR_OK; /* stop iterating */ + } + } + else { + if (matcher->ix++ == branch->data.ui32) { /* Modules.3.ct=libc */ + matcher->matched = + ptql_str_match(matcher->sigar, branch, name); + return !SIGAR_OK; /* stop iterating */ + } + } + + return SIGAR_OK; +} + +static int SIGAPI ptql_modules_match(sigar_t *sigar, + sigar_pid_t pid, + void *data) +{ + ptql_branch_t *branch = + (ptql_branch_t *)data; + int status; + sigar_proc_modules_t procmods; + proc_modules_match_t matcher; + + matcher.sigar = sigar; + matcher.branch = branch; + matcher.ix = 0; + matcher.matched = 0; + + procmods.module_getter = proc_modules_match; + procmods.data = &matcher; + + status = sigar_proc_modules_get(sigar, pid, &procmods); + + if (status != SIGAR_OK) { + return status; + } + + return matcher.matched ? SIGAR_OK : !SIGAR_OK; +} + +typedef struct { + const char *key; + int klen; + char *val; + int vlen; +} sigar_proc_env_entry_t; + +static int sigar_proc_env_get_key(void *data, + const char *key, int klen, + char *val, int vlen) +{ + sigar_proc_env_entry_t *entry = + (sigar_proc_env_entry_t *)data; + + if ((entry->klen == klen) && + (strcmp(entry->key, key) == 0)) + { + entry->val = val; + entry->vlen = vlen; + return !SIGAR_OK; /* foundit; stop iterating */ + } + + return SIGAR_OK; +} + +static int SIGAPI ptql_env_match(sigar_t *sigar, + sigar_pid_t pid, + void *data) +{ + ptql_branch_t *branch = + (ptql_branch_t *)data; + int status, matched=0; + sigar_proc_env_t procenv; + sigar_proc_env_entry_t entry; + + /* XXX ugh this is klunky */ + entry.key = branch->data.str; + entry.klen = branch->data_size; + entry.val = NULL; + + procenv.type = SIGAR_PROC_ENV_KEY; + procenv.key = branch->data.str; + procenv.klen = branch->data_size; + procenv.env_getter = sigar_proc_env_get_key; + procenv.data = &entry; + + status = sigar_proc_env_get(sigar, pid, &procenv); + if (status != SIGAR_OK) { + return status; + } + else { + if (entry.val) { + matched = + ptql_str_match(sigar, branch, entry.val); + } + } + + return matched ? SIGAR_OK : !SIGAR_OK; +} + +static int ptql_branch_init_port(ptql_parse_branch_t *parsed, + ptql_branch_t *branch, + sigar_ptql_error_t *error) +{ + char *ptr; + + /* only 'eq' is supported here */ + if (branch->op_name != PTQL_OP_EQ) { + return ptql_error(error, "%s requires 'eq' operator", + parsed->name); + } + + if (strEQ(parsed->attr, "tcp")) { + branch->flags = PTQL_PID_TCP_PORT; + } + else if (strEQ(parsed->attr, "udp")) { + branch->flags = PTQL_PID_TCP_PORT; + } + else { + return ptql_error(error, "Unsupported %s protocol: %s", + parsed->name, parsed->attr); + } + + branch->op_flags |= PTQL_OP_FLAG_PID; + SIGAR_CLEAR_ERRNO(); + branch->data.ui32 = strtoul(parsed->value, &ptr, 10); + if (strtonum_failed(parsed->value, ptr)) { + return PTQL_ERRNAN; + } + + return SIGAR_OK; +} + +#define PTQL_LOOKUP_ENTRY(cname, member, type) \ + (ptql_get_t)sigar_##cname##_get, \ + sigar_offsetof(sigar_##cname##_t, member), \ + sizeof(sigar_##cname##_t), \ + PTQL_VALUE_TYPE_##type, \ + NULL + +/* XXX uid/pid can be larger w/ 64bit mode */ +#define PTQL_VALUE_TYPE_PID PTQL_VALUE_TYPE_UI32 +#define PTQL_VALUE_TYPE_UID PTQL_VALUE_TYPE_UI32 + +static ptql_lookup_t PTQL_Time[] = { + { "StartTime", PTQL_LOOKUP_ENTRY(proc_time, start_time, UI64) }, + { "User", PTQL_LOOKUP_ENTRY(proc_time, user, UI64) }, + { "Sys", PTQL_LOOKUP_ENTRY(proc_time, sys, UI64) }, + { "Total", PTQL_LOOKUP_ENTRY(proc_time, total, UI64) }, + { NULL } +}; + +static ptql_lookup_t PTQL_Cpu[] = { + { "StartTime", PTQL_LOOKUP_ENTRY(proc_cpu, start_time, UI64) }, + { "User", PTQL_LOOKUP_ENTRY(proc_cpu, user, UI64) }, + { "Sys", PTQL_LOOKUP_ENTRY(proc_cpu, sys, UI64) }, + { "Total", PTQL_LOOKUP_ENTRY(proc_cpu, total, UI64) }, + { "Percent", PTQL_LOOKUP_ENTRY(proc_cpu, percent, DBL) }, + { NULL } +}; + +static ptql_lookup_t PTQL_CredName[] = { + { "User", PTQL_LOOKUP_ENTRY(proc_cred_name, user, STR) }, + { "Group", PTQL_LOOKUP_ENTRY(proc_cred_name, group, STR) }, + { NULL } +}; + +static ptql_lookup_t PTQL_Mem[] = { + { "Size", PTQL_LOOKUP_ENTRY(proc_mem, size, UI64) }, + { "Resident", PTQL_LOOKUP_ENTRY(proc_mem, resident, UI64) }, + { "Share", PTQL_LOOKUP_ENTRY(proc_mem, share, UI64) }, + { "MinorFaults", PTQL_LOOKUP_ENTRY(proc_mem, minor_faults, UI64) }, + { "MajorFaults", PTQL_LOOKUP_ENTRY(proc_mem, major_faults, UI64) }, + { "PageFaults", PTQL_LOOKUP_ENTRY(proc_mem, page_faults, UI64) }, + { NULL } +}; + +static ptql_lookup_t PTQL_Exe[] = { + { "Name", PTQL_LOOKUP_ENTRY(proc_exe, name, STR) }, + { "Cwd", PTQL_LOOKUP_ENTRY(proc_exe, cwd, STR) }, + { NULL } +}; + +static ptql_lookup_t PTQL_Cred[] = { + { "Uid", PTQL_LOOKUP_ENTRY(proc_cred, uid, UID) }, + { "Gid", PTQL_LOOKUP_ENTRY(proc_cred, gid, UID) }, + { "Euid", PTQL_LOOKUP_ENTRY(proc_cred, euid, UID) }, + { "Egid", PTQL_LOOKUP_ENTRY(proc_cred, egid, UID) }, + { NULL } +}; + +static ptql_lookup_t PTQL_State[] = { + { "State", PTQL_LOOKUP_ENTRY(proc_state, state, CHR) }, + { "Name", PTQL_LOOKUP_ENTRY(proc_state, name, STR) }, + { "Ppid", PTQL_LOOKUP_ENTRY(proc_state, ppid, PID) }, + { "Tty", PTQL_LOOKUP_ENTRY(proc_state, tty, UI32) }, + { "Nice", PTQL_LOOKUP_ENTRY(proc_state, nice, UI32) }, + { "Priority", PTQL_LOOKUP_ENTRY(proc_state, priority, UI32) }, + { "Threads", PTQL_LOOKUP_ENTRY(proc_state, threads, UI64) }, + { "Processor", PTQL_LOOKUP_ENTRY(proc_state, processor, UI32) }, + { NULL } +}; + +static ptql_lookup_t PTQL_Fd[] = { + { "Total", PTQL_LOOKUP_ENTRY(proc_fd, total, UI64) }, + { NULL } +}; + +static ptql_lookup_t PTQL_Args[] = { + { NULL, ptql_args_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_args_branch_init } +}; + +static ptql_lookup_t PTQL_Modules[] = { + { NULL, ptql_modules_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_args_branch_init } +}; + +static ptql_lookup_t PTQL_Env[] = { + { NULL, ptql_env_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_any } +}; + +static ptql_lookup_t PTQL_Port[] = { + { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_port } +}; + +static ptql_lookup_t PTQL_Pid[] = { + { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_pid } +}; + +static ptql_lookup_t PTQL_Service[] = { + { NULL, ptql_pid_match, 0, 0, PTQL_VALUE_TYPE_ANY, ptql_branch_init_service } +}; + +static ptql_entry_t ptql_map[] = { + { "Time", PTQL_Time }, + { "Cpu", PTQL_Cpu }, + { "CredName", PTQL_CredName }, + { "Mem", PTQL_Mem }, + { "Exe", PTQL_Exe }, + { "Cred", PTQL_Cred }, + { "State", PTQL_State }, + { "Fd", PTQL_Fd }, + { "Args", PTQL_Args }, + { "Modules", PTQL_Modules }, + { "Env", PTQL_Env }, + { "Port", PTQL_Port }, + { "Pid", PTQL_Pid }, + { "Service", PTQL_Service }, + { NULL } +}; + +static int ptql_branch_parse(char *query, ptql_parse_branch_t *branch, + sigar_ptql_error_t *error) +{ + char *ptr = strchr(query, '='); + if (!ptr) { + return ptql_error(error, "Missing '='"); + } + + branch->op_flags = 0; + + *ptr = '\0'; + branch->value = ++ptr; + + if ((ptr = strchr(query, '.'))) { + *ptr = '\0'; + branch->name = query; + query = ++ptr; + } + else { + return ptql_error(error, "Missing '.'"); + } + + if ((ptr = strchr(query, '.'))) { + *ptr = '\0'; + branch->attr = query; + query = ++ptr; + } + else { + return ptql_error(error, "Missing '.'"); + } + + if (*query) { + char flag; + + while (sigar_isupper((flag = *query))) { + switch (flag) { + case 'P': + branch->op_flags |= PTQL_OP_FLAG_PARENT; + break; + case 'I': + branch->op_flags |= PTQL_OP_FLAG_ICASE; + break; + default: + return ptql_error(error, "Unsupported modifier: %c", flag); + } + + ++query; + } + + branch->op = query; + } + else { + return ptql_error(error, "Missing query"); + } + + /* Pid.Service -> Service.Name */ + if (strEQ(branch->attr, "Service")) { + branch->name = branch->attr; + branch->attr = "Name"; + } + + return SIGAR_OK; +} + +static int ptql_branch_add(ptql_parse_branch_t *parsed, + ptql_branch_list_t *branches, + sigar_ptql_error_t *error) +{ + ptql_branch_t *branch; + ptql_entry_t *entry = NULL; + ptql_lookup_t *lookup = NULL; + int i, is_set=0; + char *ptr; + + PTQL_BRANCH_LIST_GROW(branches); + + branch = &branches->data[branches->number++]; + SIGAR_ZERO(branch); + branch->data_free = data_free; + branch->value_free = data_free; + branch->op_flags = parsed->op_flags; + + branch->op_name = ptql_op_code_get(parsed->op); + if (branch->op_name == PTQL_OP_MAX) { + return ptql_error(error, "Unsupported operator: %s", parsed->op); + } + + for (i=0; ptql_map[i].name; i++) { + if (strEQ(ptql_map[i].name, parsed->name)) { + entry = &ptql_map[i]; + break; + } + } + + if (!entry) { + return ptql_error(error, "Unsupported method: %s", parsed->name); + } + + for (i=0; entry->members[i].name; i++) { + if (strEQ(entry->members[i].name, parsed->attr)) { + lookup = &entry->members[i]; + break; + } + } + + if (!lookup) { + if (entry->members[0].type == PTQL_VALUE_TYPE_ANY) { + /* Args, Env, etc. */ + lookup = &entry->members[0]; + } + else { + return ptql_error(error, "Unsupported %s attribute: %s", + parsed->name, parsed->attr); + } + } + + if (lookup->init) { + int status = lookup->init(parsed, branch, error); + if (status != SIGAR_OK) { + return status; + } + } + + branch->lookup = lookup; + + if ((lookup->type < PTQL_VALUE_TYPE_STR) && + (branch->op_name > PTQL_OP_MAX_NSTR)) + { + return ptql_error(error, "Unsupported operator '%s' for %s.%s", + parsed->op, parsed->name, parsed->attr); + } + + if (*parsed->value == '$') { + is_set = 1; + + if (branch->op_name == PTQL_OP_RE) { + /* not for use with .re */ + return ptql_error(error, "Unsupported operator '%s' with variable %s", + parsed->op, parsed->value); + } + + if (sigar_isdigit(*(parsed->value+1))) { + branch->op_flags |= PTQL_OP_FLAG_REF; + parsed->op_flags = branch->op_flags; /* for use by caller */ + branch->value.ui32 = atoi(parsed->value+1) - 1; + + if (branch->value.ui32 >= branches->number) { + /* out-of-range */ + return ptql_error(error, "Variable %s out of range (%d)", + parsed->value, branches->number); + } + else if (branch->value.ui32 == branches->number-1) { + /* self reference */ + return ptql_error(error, "Variable %s self reference", + parsed->value); + } + } + else { + if ((ptr = getenv(parsed->value+1))) { + branch->value.str = sigar_strdup(ptr); + } + else { + branch->value.str = NULL; + } + } + } + else if (branch->op_name == PTQL_OP_RE) { +#ifdef SIGAR_HAS_PCRE + const char *error; + int offset; + pcre *re = + pcre_compile(parsed->value, 0, + &error, &offset, NULL); + if (!re) { + /* XXX pcre_error ? */ + return ptql_error(error, "Invalid regex"); + } + is_set = 1; + branch->value.ptr = re; + branch->value_free = pcre_free; +#endif + } + + switch (lookup->type) { + case PTQL_VALUE_TYPE_UI64: + branch->match.ui64 = ptql_op_ui64[branch->op_name]; + if (!is_set) { + SIGAR_CLEAR_ERRNO(); + branch->value.ui64 = strtoull(parsed->value, &ptr, 10); + if (strtonum_failed(parsed->value, ptr)) { + return PTQL_ERRNAN; + } + } + break; + case PTQL_VALUE_TYPE_UI32: + branch->match.ui32 = ptql_op_ui32[branch->op_name]; + if (!is_set) { + SIGAR_CLEAR_ERRNO(); + branch->value.ui32 = strtoul(parsed->value, &ptr, 10); + if (strtonum_failed(parsed->value, ptr)) { + return PTQL_ERRNAN; + } + } + break; + case PTQL_VALUE_TYPE_DBL: + branch->match.dbl = ptql_op_dbl[branch->op_name]; + if (!is_set) { + SIGAR_CLEAR_ERRNO(); + branch->value.dbl = strtod(parsed->value, &ptr); + if (strtonum_failed(parsed->value, ptr)) { + return PTQL_ERRNAN; + } + } + break; + case PTQL_VALUE_TYPE_CHR: + branch->match.chr = ptql_op_chr[branch->op_name]; + if (!is_set) { + if (strlen(parsed->value) != 1) { + return ptql_error(error, "%s is not a char", parsed->value); + } + branch->value.chr[0] = parsed->value[0]; + } + break; + case PTQL_VALUE_TYPE_STR: + case PTQL_VALUE_TYPE_ANY: + branch->match.str = ptql_op_str[branch->op_name]; + if (!is_set) { + branch->value.str = sigar_strdup(parsed->value); + } + break; + } + + return SIGAR_OK; +} + +static int ptql_branch_compare(const void *b1, const void *b2) +{ + /* XXX can do better */ + ptql_branch_t *branch1 = (ptql_branch_t *)b1; + ptql_branch_t *branch2 = (ptql_branch_t *)b2; + return + branch1->lookup->type - + branch2->lookup->type; +} + +SIGAR_DECLARE(int) sigar_ptql_query_create(sigar_ptql_query_t **queryp, + char *ptql, + sigar_ptql_error_t *error) +{ + char *ptr, *ptql_copy = sigar_strdup(ptql); + int status = SIGAR_OK; + int has_ref = 0; + sigar_ptql_query_t *query = + *queryp = malloc(sizeof(*query)); + + (void)ptql_error(error, "Malformed query"); + +#ifdef PTQL_DEBUG + query->ptql = sigar_strdup(ptql); +#endif + + ptql = ptql_copy; + + ptql_branch_list_create(&query->branches); + + do { + ptql_parse_branch_t parsed; + + if ((ptr = strchr(ptql, ','))) { + *ptr = '\0'; + } + + status = ptql_branch_parse(ptql, &parsed, error); + if (status == SIGAR_OK) { + status = + ptql_branch_add(&parsed, &query->branches, error); + + if (status != SIGAR_OK) { + break; + } + if (parsed.op_flags & PTQL_OP_FLAG_REF) { + has_ref = 1; + } + } + else { + break; + } + + if (ptr) { + ptql = ++ptr; + } + else { + break; + } + } while (*ptql); + + free(ptql_copy); + + if (status != SIGAR_OK) { + sigar_ptql_query_destroy(query); + *queryp = NULL; + } + else if (!has_ref && (query->branches.number > 1)) { + qsort(query->branches.data, + query->branches.number, + sizeof(query->branches.data[0]), + ptql_branch_compare); + } + + if (status == SIGAR_OK) { + (void)ptql_error(error, "OK"); + } + return status; +} + +SIGAR_DECLARE(int) sigar_ptql_query_destroy(sigar_ptql_query_t *query) +{ +#ifdef PTQL_DEBUG + free(query->ptql); +#endif + ptql_branch_list_destroy(&query->branches); + free(query); + return SIGAR_OK; +} + +SIGAR_DECLARE(void) sigar_ptql_re_impl_set(sigar_t *sigar, void *data, + sigar_ptql_re_impl_t impl) +{ + sigar->ptql_re_data = data; + sigar->ptql_re_impl = impl; +} + +SIGAR_DECLARE(int) sigar_ptql_query_match(sigar_t *sigar, + sigar_ptql_query_t *query, + sigar_pid_t query_pid) +{ + int i; + + for (i=0; ibranches.number; i++) { + sigar_pid_t pid = query_pid; + int status, matched=0; + ptql_branch_t *branch = &query->branches.data[i]; + ptql_lookup_t *lookup = branch->lookup; + + if (branch->op_flags & PTQL_OP_FLAG_PARENT) { + sigar_proc_state_t state; + + status = sigar_proc_state_get(sigar, pid, &state); + if (status != SIGAR_OK) { + return status; + } + + pid = state.ppid; + } + + if (lookup->type == PTQL_VALUE_TYPE_ANY) { + /* Args, Env, etc. */ + status = lookup->get(sigar, pid, branch); + if (status == SIGAR_OK) { + matched = 1; + } + } + else { + /* standard sigar_proc_*_get / structptr + offset */ + if (!branch->data.ptr) { + branch->data_size = lookup->data_size; + branch->data.ptr = malloc(branch->data_size); + } + status = lookup->get(sigar, pid, branch->data.ptr); + if (status != SIGAR_OK) { + return status; + } + + if (branch->op_flags & PTQL_OP_FLAG_REF) { + ptql_branch_t *ref = + &query->branches.data[branch->value.ui32]; + + matched = ptql_branch_match_ref(branch, ref); + } +#ifndef SIGAR_HAS_PCRE + else if (branch->lookup->type == PTQL_VALUE_TYPE_STR) { + matched = ptql_str_match(sigar, branch, (char *)DATA_PTR(branch)); + } +#endif + else { + matched = ptql_branch_match(branch); + } + } + + if (!matched) { + return 1; + } + } + + return SIGAR_OK; +} + +static int ptql_proc_list_get(sigar_t *sigar, + sigar_ptql_query_t *query, + sigar_proc_list_t **proclist) +{ + int status; + int i; + + *proclist = NULL; + + for (i=0; ibranches.number; i++) { + ptql_branch_t *branch = &query->branches.data[i]; + + if (branch->op_flags & PTQL_OP_FLAG_PID) { + /* pre-filter pid list for Pid.* queries */ + /* XXX multiple Pid.* may result in dups */ + if (*proclist == NULL) { + *proclist = malloc(sizeof(**proclist)); + SIGAR_ZERO(*proclist); + sigar_proc_list_create(*proclist); + } + status = ptql_pid_list_get(sigar, branch, *proclist); + if (status != SIGAR_OK) { + sigar_proc_list_destroy(sigar, *proclist); + free(*proclist); + return status; + } + } + } + + if (*proclist) { + return SIGAR_OK; + } + + status = sigar_proc_list_get(sigar, NULL); + if (status != SIGAR_OK) { + return status; + } + *proclist = sigar->pids; + return SIGAR_OK; +} + +static int ptql_proc_list_destroy(sigar_t *sigar, + sigar_proc_list_t *proclist) +{ + if (proclist != sigar->pids) { + sigar_proc_list_destroy(sigar, proclist); + free(proclist); + } + + return SIGAR_OK; +} + +SIGAR_DECLARE(int) sigar_ptql_query_find_process(sigar_t *sigar, + sigar_ptql_query_t *query, + sigar_pid_t *pid) +{ + int status; + int i, matches=0; + sigar_proc_list_t *pids; + + status = ptql_proc_list_get(sigar, query, &pids); + if (status != SIGAR_OK) { + return status; + } + + for (i=0; inumber; i++) { + int query_status = + sigar_ptql_query_match(sigar, query, pids->data[i]); + + if (query_status == SIGAR_OK) { + *pid = pids->data[i]; + matches++; + } + else if (query_status == SIGAR_ENOTIMPL) { + /* let caller know query is invalid. */ + status = query_status; + break; + } /* else ok, e.g. permission denied */ + } + + ptql_proc_list_destroy(sigar, pids); + + if (status != SIGAR_OK) { + return status; + } + + if (matches == 1) { + return SIGAR_OK; + } + else if (matches == 0) { + sigar_strerror_set(sigar, + "Query did not match any processes"); + } + else { + sigar_strerror_printf(sigar, + "Query matched multiple processes (%d)", + matches); + } + + return -1; +} + +SIGAR_DECLARE(int) sigar_ptql_query_find(sigar_t *sigar, + sigar_ptql_query_t *query, + sigar_proc_list_t *proclist) +{ + int status; + int i; + sigar_proc_list_t *pids; + + status = ptql_proc_list_get(sigar, query, &pids); + if (status != SIGAR_OK) { + return status; + } + + sigar_proc_list_create(proclist); + + for (i=0; inumber; i++) { + int query_status = + sigar_ptql_query_match(sigar, query, pids->data[i]); + + if (query_status == SIGAR_OK) { + SIGAR_PROC_LIST_GROW(proclist); + proclist->data[proclist->number++] = pids->data[i]; + } + else if (query_status == SIGAR_ENOTIMPL) { + /* let caller know query is invalid. */ + status = query_status; + break; + } + } + + ptql_proc_list_destroy(sigar, pids); + + if (status != SIGAR_OK) { + sigar_proc_list_destroy(sigar, proclist); + return status; + } + + return SIGAR_OK; +} diff --git a/vendor/sigar/src/sigar_signal.c b/vendor/sigar/src/sigar_signal.c new file mode 100644 index 0000000..e32d231 --- /dev/null +++ b/vendor/sigar/src/sigar_signal.c @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2007 Hyperic, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_util.h" + +#ifdef WIN32 +#include +#endif + +#include +#include + +SIGAR_DECLARE(int) sigar_proc_kill(sigar_pid_t pid, int signum) +{ +#ifdef WIN32 + int status = -1; + HANDLE proc = + OpenProcess(PROCESS_ALL_ACCESS, + TRUE, (DWORD)pid); + + if (proc) { + switch (signum) { + case 0: + status = SIGAR_OK; + break; + default: + if (TerminateProcess(proc, signum)) { + status = SIGAR_OK; + } + break; + } + + CloseHandle(proc); + + if (status == SIGAR_OK) { + return SIGAR_OK; + } + } + return GetLastError(); +#else + if (kill(pid, signum) == -1) { + return errno; + } + return SIGAR_OK; +#endif +} + +SIGAR_DECLARE(int) sigar_signum_get(char *name) +{ + if (strnEQ(name, "SIG", 3)) { + name += 3; + } + + switch (*name) { + case 'A': +#ifdef SIGABRT + if (strEQ(name, "ABRT")) return SIGABRT; +#endif +#ifdef SIGALRM + if (strEQ(name, "ALRM")) return SIGALRM; +#endif + break; + case 'B': +#ifdef SIGBUS + if (strEQ(name, "BUS")) return SIGBUS; +#endif + break; + case 'C': +#ifdef SIGCONT + if (strEQ(name, "CONT")) return SIGCONT; +#endif +#ifdef SIGCHLD + if (strEQ(name, "CHLD")) return SIGCHLD; +#endif +#ifdef SIGCLD + if (strEQ(name, "CLD")) return SIGCLD; +#endif + break; + case 'E': +#ifdef SIGEMT + if (strEQ(name, "EMT")) return SIGEMT; +#endif + break; + case 'F': +#ifdef SIGFPE + if (strEQ(name, "FPE")) return SIGFPE; +#endif + break; + case 'H': +#ifdef SIGHUP + if (strEQ(name, "HUP")) return SIGHUP; +#endif + break; + case 'I': +#ifdef SIGINT + if (strEQ(name, "INT")) return SIGINT; +#endif +#ifdef SIGILL + if (strEQ(name, "ILL")) return SIGILL; +#endif +#ifdef SIGIOT + if (strEQ(name, "IOT")) return SIGIOT; +#endif +#ifdef SIGIO + if (strEQ(name, "IO")) return SIGIO; +#endif +#ifdef SIGINFO + if (strEQ(name, "INFO")) return SIGINFO; +#endif + break; + case 'K': +#ifdef SIGKILL + if (strEQ(name, "KILL")) return SIGKILL; +#endif + break; + case 'P': +#ifdef SIGPOLL + if (strEQ(name, "POLL")) return SIGPOLL; +#endif +#ifdef SIGPIPE + if (strEQ(name, "PIPE")) return SIGPIPE; +#endif +#ifdef SIGPROF + if (strEQ(name, "PROF")) return SIGPROF; +#endif +#ifdef SIGPWR + if (strEQ(name, "PWR")) return SIGPWR; +#endif + break; + case 'Q': +#ifdef SIGQUIT + if (strEQ(name, "QUIT")) return SIGQUIT; +#endif + break; + case 'S': +#ifdef SIGSEGV + if (strEQ(name, "SEGV")) return SIGSEGV; +#endif +#ifdef SIGSYS + if (strEQ(name, "SYS")) return SIGSYS; +#endif +#ifdef SIGSTOP + if (strEQ(name, "STOP")) return SIGSTOP; +#endif +#ifdef SIGSTKFLT + if (strEQ(name, "STKFLT")) return SIGSTKFLT; +#endif + break; + case 'T': +#ifdef SIGTRAP + if (strEQ(name, "TRAP")) return SIGTRAP; +#endif +#ifdef SIGTERM + if (strEQ(name, "TERM")) return SIGTERM; +#endif +#ifdef SIGTSTP + if (strEQ(name, "TSTP")) return SIGTSTP; +#endif +#ifdef SIGTTIN + if (strEQ(name, "TTIN")) return SIGTTIN; +#endif +#ifdef SIGTTOU + if (strEQ(name, "TTOU")) return SIGTTOU; +#endif + break; + case 'U': +#ifdef SIGURG + if (strEQ(name, "URG")) return SIGURG; +#endif +#ifdef SIGUSR1 + if (strEQ(name, "USR1")) return SIGUSR1; +#endif +#ifdef SIGUSR2 + if (strEQ(name, "USR2")) return SIGUSR2; +#endif + break; + case 'V': +#ifdef SIGVTALRM + if (strEQ(name, "VTALRM")) return SIGVTALRM; +#endif + break; + case 'W': +#ifdef SIGWINCH + if (strEQ(name, "WINCH")) return SIGWINCH; +#endif + break; + case 'X': +#ifdef SIGXCPU + if (strEQ(name, "XCPU")) return SIGXCPU; +#endif +#ifdef SIGXFSZ + if (strEQ(name, "XFSZ")) return SIGXFSZ; +#endif + break; + default: + break; + } + + return -1; +} + diff --git a/vendor/sigar/src/sigar_util.c b/vendor/sigar/src/sigar_util.c new file mode 100644 index 0000000..3c668fc --- /dev/null +++ b/vendor/sigar/src/sigar_util.c @@ -0,0 +1,1060 @@ +/* + * Copyright (c) 2004-2009 Hyperic, Inc. + * Copyright (c) 2009 SpringSource, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include "sigar.h" +#include "sigar_private.h" +#include "sigar_util.h" +#include "sigar_os.h" + +#ifndef WIN32 + +#include +#include + +SIGAR_INLINE char *sigar_uitoa(char *buf, unsigned int n, int *len) +{ + char *start = buf + UITOA_BUFFER_SIZE - 1; + + *start = 0; + + do { + *--start = '0' + (n % 10); + ++*len; + n /= 10; + } while (n); + + return start; +} + +SIGAR_INLINE char *sigar_skip_line(char *buffer, int buflen) +{ + char *ptr = buflen ? + (char *)memchr(buffer, '\n', buflen) : /* bleh */ + strchr(buffer, '\n'); + return ++ptr; +} + +SIGAR_INLINE char *sigar_skip_token(char *p) +{ + while (sigar_isspace(*p)) p++; + while (*p && !sigar_isspace(*p)) p++; + return p; +} + +SIGAR_INLINE char *sigar_skip_multiple_token(char *p, int count) +{ + int i; + + for (i = 0; i < count; i++) { + p = sigar_skip_token(p); + } + + return p; +} + +char *sigar_getword(char **line, char stop) +{ + char *pos = *line; + int len; + char *res; + + while ((*pos != stop) && *pos) { + ++pos; + } + + len = pos - *line; + res = malloc(len + 1); + memcpy(res, *line, len); + res[len] = 0; + + if (stop) { + while (*pos == stop) { + ++pos; + } + } + + *line = pos; + + return res; +} + +/* avoiding sprintf */ + +char *sigar_proc_filename(char *buffer, int buflen, + sigar_pid_t bigpid, + const char *fname, int fname_len) +{ + int len = 0; + char *ptr = buffer; + unsigned int pid = (unsigned int)bigpid; /* XXX -- This isn't correct */ + char pid_buf[UITOA_BUFFER_SIZE]; + char *pid_str = sigar_uitoa(pid_buf, pid, &len); + + assert((unsigned int)buflen >= + (SSTRLEN(PROCP_FS_ROOT) + UITOA_BUFFER_SIZE + fname_len + 1)); + + memcpy(ptr, PROCP_FS_ROOT, SSTRLEN(PROCP_FS_ROOT)); + ptr += SSTRLEN(PROCP_FS_ROOT); + + memcpy(ptr, pid_str, len); + ptr += len; + + memcpy(ptr, fname, fname_len); + ptr += fname_len; + *ptr = '\0'; + + return buffer; +} + +int sigar_proc_file2str(char *buffer, int buflen, + sigar_pid_t pid, + const char *fname, + int fname_len) +{ + int retval; + + buffer = sigar_proc_filename(buffer, buflen, pid, + fname, fname_len); + + retval = sigar_file2str(buffer, buffer, buflen); + + if (retval != SIGAR_OK) { + switch (retval) { + case ENOENT: + retval = ESRCH; /* no such process */ + default: + break; + } + } + + return retval; +} + +int sigar_proc_list_procfs_get(sigar_t *sigar, + sigar_proc_list_t *proclist) +{ + DIR *dirp = opendir("/proc"); + struct dirent *ent; +#ifdef HAVE_READDIR_R + struct dirent dbuf; +#endif + + if (!dirp) { + return errno; + } + +#ifdef HAVE_READDIR_R + while (readdir_r(dirp, &dbuf, &ent) == 0) { + if (ent == NULL) { + break; + } +#else + while ((ent = readdir(dirp))) { +#endif + if (!sigar_isdigit(*ent->d_name)) { + continue; + } + + /* XXX: more sanity checking */ + + SIGAR_PROC_LIST_GROW(proclist); + + proclist->data[proclist->number++] = + strtoul(ent->d_name, NULL, 10); + } + + closedir(dirp); + + return SIGAR_OK; +} + +int sigar_proc_fd_count(sigar_t *sigar, sigar_pid_t pid, + sigar_uint64_t *total) +{ + DIR *dirp; + struct dirent *ent; +#ifdef HAVE_READDIR_R + struct dirent dbuf; +#endif + char name[BUFSIZ]; + + (void)SIGAR_PROC_FILENAME(name, pid, "/fd"); + + *total = 0; + + if (!(dirp = opendir(name))) { + return errno; + } + +#ifdef HAVE_READDIR_R + while (readdir_r(dirp, &dbuf, &ent) == 0) { + if (ent == NULL) { + break; + } +#else + while ((ent = readdir(dirp))) { +#endif + if (!sigar_isdigit(*ent->d_name)) { + continue; + } + + (*total)++; + } + + closedir(dirp); + + return SIGAR_OK; +} + +int sigar_procfs_args_get(sigar_t *sigar, sigar_pid_t pid, + sigar_proc_args_t *procargs) +{ + char buffer[9086], *buf=NULL, *ptr; + int fd, len, total=0; + + (void)SIGAR_PROC_FILENAME(buffer, pid, "/cmdline"); + + if ((fd = open(buffer, O_RDONLY)) < 0) { + if (errno == ENOENT) { + return ESRCH; + } + return errno; + } + + buffer[0] = '\0'; + + /* XXX: possible to get rid of some mallocs here. + * but, unlikely this will be called often so it + * might not even matter much. + */ + while ((len = read(fd, buffer, sizeof(buffer)-1)) > 0) { + if (len == 0) { + break; + } + buf = realloc(buf, total+len+1); + memcpy(buf+total, buffer, len); + total += len; + } + + close(fd); + + /* e.g. /proc/2/cmdline */ + if (total == 0) { + procargs->number = 0; + return SIGAR_OK; + } + + buf[total] = '\0'; + ptr = buf; + + while (total > 0) { + int alen = strlen(ptr)+1; + char *arg = malloc(alen); + + SIGAR_PROC_ARGS_GROW(procargs); + memcpy(arg, ptr, alen); + + procargs->data[procargs->number++] = arg; + + total -= alen; + if (total > 0) { + ptr += alen; + } + } + + free(buf); + + return SIGAR_OK; +} + +#endif /* WIN32 */ + +/* from httpd/server/util.c */ +char *sigar_strcasestr(const char *s1, const char *s2) +{ + char *p1, *p2; + if (*s2 == '\0') { + /* an empty s2 */ + return((char *)s1); + } + while(1) { + for ( ; (*s1 != '\0') && (sigar_tolower(*s1) != sigar_tolower(*s2)); s1++); + if (*s1 == '\0') { + return(NULL); + } + /* found first character of s2, see if the rest matches */ + p1 = (char *)s1; + p2 = (char *)s2; + for (++p1, ++p2; sigar_tolower(*p1) == sigar_tolower(*p2); ++p1, ++p2) { + if (*p1 == '\0') { + /* both strings ended together */ + return((char *)s1); + } + } + if (*p2 == '\0') { + /* second string ended, a match */ + break; + } + /* didn't find a match here, try starting at next character in s1 */ + s1++; + } + return((char *)s1); +} + +int sigar_mem_calc_ram(sigar_t *sigar, sigar_mem_t *mem) +{ + sigar_int64_t total = mem->total / 1024, diff; + sigar_uint64_t lram = (mem->total / (1024 * 1024)); + int ram = (int)lram; /* must cast after division */ + int remainder = ram % 8; + + if (remainder > 0) { + ram += (8 - remainder); + } + + mem->ram = ram; + + diff = total - (mem->actual_free / 1024); + mem->used_percent = + (double)(diff * 100) / total; + + diff = total - (mem->actual_used / 1024); + mem->free_percent = + (double)(diff * 100) / total; + + return ram; +} + +#ifndef WIN32 + +sigar_iodev_t *sigar_iodev_get(sigar_t *sigar, + const char *dirname) +{ + sigar_cache_entry_t *entry; + struct stat sb; + sigar_uint64_t id; + sigar_file_system_list_t fslist; + int i, status, is_dev=0; + int debug = SIGAR_LOG_IS_DEBUG(sigar); + char dev_name[SIGAR_FS_NAME_LEN]; + + if (!sigar->fsdev) { + sigar->fsdev = sigar_cache_new(15); + } + + if (*dirname != '/') { + snprintf(dev_name, sizeof(dev_name), + SIGAR_DEV_PREFIX "%s", dirname); + dirname = dev_name; + is_dev = 1; + } + else if (SIGAR_NAME_IS_DEV(dirname)) { + is_dev = 1; + } + + if (stat(dirname, &sb) < 0) { + if (debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[iodev] stat(%s) failed", + dirname); + } + return NULL; + } + + id = SIGAR_FSDEV_ID(sb); + + entry = sigar_cache_get(sigar->fsdev, id); + + if (entry->value != NULL) { + return (sigar_iodev_t *)entry->value; + } + + if (is_dev) { + sigar_iodev_t *iodev; + entry->value = iodev = malloc(sizeof(*iodev)); + SIGAR_ZERO(iodev); + SIGAR_SSTRCPY(iodev->name, dirname); + if (debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[iodev] %s is_dev=true", dirname); + } + return iodev; + } + + status = sigar_file_system_list_get(sigar, &fslist); + + if (status != SIGAR_OK) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[iodev] file_system_list failed: %s", + sigar_strerror(sigar, status)); + return NULL; + } + + for (i=0; itype == SIGAR_FSTYPE_LOCAL_DISK) { + int retval = stat(fsp->dir_name, &sb); + sigar_cache_entry_t *ent; + + if (retval < 0) { + if (debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[iodev] inode stat(%s) failed", + fsp->dir_name); + } + continue; /* cant cache w/o inode */ + } + + ent = sigar_cache_get(sigar->fsdev, SIGAR_FSDEV_ID(sb)); + if (ent->value) { + continue; /* already cached */ + } + + if (SIGAR_NAME_IS_DEV(fsp->dev_name)) { + sigar_iodev_t *iodev; + ent->value = iodev = malloc(sizeof(*iodev)); + SIGAR_ZERO(iodev); + iodev->is_partition = 1; + SIGAR_SSTRCPY(iodev->name, fsp->dev_name); + + if (debug) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[iodev] map %s -> %s", + fsp->dir_name, iodev->name); + } + } + } + } + + sigar_file_system_list_destroy(sigar, &fslist); + + if (entry->value && + (((sigar_iodev_t *)entry->value)->name[0] != '\0')) + { + return (sigar_iodev_t *)entry->value; + } + else { + return NULL; + } +} +#endif + +double sigar_file_system_usage_calc_used(sigar_t *sigar, + sigar_file_system_usage_t *fsusage) +{ + /* + * win32 will not convert __uint64 to double. + * convert to KB then do unsigned long -> double. + */ + sigar_uint64_t b_used = (fsusage->total - fsusage->free) / 1024; + sigar_uint64_t b_avail = fsusage->avail / 1024; + unsigned long utotal = b_used + b_avail; + unsigned long used = b_used; + + if (utotal != 0) { + unsigned long u100 = used * 100; + double pct = u100 / utotal + + ((u100 % utotal != 0) ? 1 : 0); + return pct / 100; + } + + return 0; +} + +typedef struct { + sigar_uint32_t eax; + sigar_uint32_t ebx; + sigar_uint32_t ecx; + sigar_uint32_t edx; +} sigar_cpuid_t; + +#if defined(__GNUC__) && !defined(__sun) + +# if defined(__i386__) +# define SIGAR_HAS_CPUID +static void sigar_cpuid(sigar_uint32_t request, sigar_cpuid_t *id) +{ + /* derived from: */ + /* http://svn.red-bean.com/repos/minor/trunk/gc/barriers-ia-32.c */ + asm volatile ("mov %%ebx, %%esi\n\t" + "cpuid\n\t" + "xchgl %%ebx, %%esi" + : "=a" (id->eax), + "=S" (id->ebx), + "=c" (id->ecx), + "=d" (id->edx) + : "0" (request) + : "memory"); +} +# elif defined(__amd64__) +# define SIGAR_HAS_CPUID +static void sigar_cpuid(sigar_uint32_t request, + sigar_cpuid_t *id) +{ + /* http://svn.red-bean.com/repos/minor/trunk/gc/barriers-amd64.c */ + asm volatile ("cpuid\n\t" + : "=a" (id->eax), + "=b" (id->ebx), + "=c" (id->ecx), + "=d" (id->edx) + : "0" (request) + : "memory"); +} +# endif +#elif defined(WIN32) +# ifdef _M_X64 +# include +# define SIGAR_HAS_CPUID +static void sigar_cpuid(sigar_uint32_t request, + sigar_cpuid_t *id) +{ + sigar_uint32_t info[4]; + __cpuid(info, request); /* as of MSVC 7 */ + memcpy(id, &info[0], sizeof(info)); +} +# else +# define SIGAR_HAS_CPUID +static void sigar_cpuid(sigar_uint32_t request, + sigar_cpuid_t *id) +{ + __asm { + mov edi, id + mov eax, [edi].eax + mov ecx, [edi].ecx + cpuid + mov [edi].eax, eax + mov [edi].ebx, ebx + mov [edi].ecx, ecx + mov [edi].edx, edx + } +} +# endif +#endif + +#define INTEL_ID 0x756e6547 +#define AMD_ID 0x68747541 + +int sigar_cpu_core_count(sigar_t *sigar) +{ +#if defined(SIGAR_HAS_CPUID) + sigar_cpuid_t id; + + if (sigar->lcpu == -1) { + sigar->lcpu = 1; + + sigar_cpuid(0, &id); + + if ((id.ebx == INTEL_ID) || (id.ebx == AMD_ID)) { + sigar_cpuid(1, &id); + + if (id.edx & (1<<28)) { + sigar->lcpu = (id.ebx & 0x00FF0000) >> 16; + } + } + + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[cpu] %d cores per socket", sigar->lcpu); + } + + return sigar->lcpu; +#elif defined(__sun) || defined(__hpux) || defined(_AIX) + return 1; +#else + sigar->lcpu = 1; + return sigar->lcpu; +#endif +} + +int sigar_cpu_core_rollup(sigar_t *sigar) +{ +#ifdef SIGAR_HAS_CPUID + int log_rollup = + SIGAR_LOG_IS_DEBUG(sigar) && + (sigar->lcpu == -1); + + (void)sigar_cpu_core_count(sigar); + + if (sigar->cpu_list_cores) { + if (log_rollup && (sigar->lcpu > 1)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[cpu] treating cores as-is"); + } + } + else { + if (log_rollup && (sigar->lcpu > 1)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "[cpu] rolling up cores to sockets"); + return 1; + } + } +#endif + return 0; +} + +#define IS_CPU_R(p) \ + ((*p == '(') && (*(p+1) == 'R') && (*(p+2) == ')')) + +typedef struct { + char *name; /* search */ + int len; + char *rname; /* replace */ + int rlen; +} cpu_model_str_t; + +/* to later replace 's' with 'r' */ +#define CPU_MODEL_ENT_R(s, r) \ + { s, sizeof(s)-1, r, sizeof(r) } + +#define CPU_MODEL_ENT(s) \ + CPU_MODEL_ENT_R(s, s) + +/* after the vendor part of the string is removed, + * looking for startsWith the entries below + * to remove the crap after the model name, see + * ../exp/intel_amd_cpu_models.txt + */ +static const cpu_model_str_t cpu_models[] = { + /* intel */ + CPU_MODEL_ENT("Xeon"), + CPU_MODEL_ENT_R("XEON", "Xeon"), + CPU_MODEL_ENT("Pentium III"), + CPU_MODEL_ENT("Pentium II"), + CPU_MODEL_ENT_R("Pentium(R) III", "Pentium III"), + CPU_MODEL_ENT_R("Pentium(R) 4", "Pentium 4"), + CPU_MODEL_ENT_R("Pentium(R) M", "Pentium M"), + CPU_MODEL_ENT("Pentium Pro"), + CPU_MODEL_ENT("Celeron"), + + /* amd */ + CPU_MODEL_ENT("Opteron"), + CPU_MODEL_ENT("Athlon"), + CPU_MODEL_ENT("Duron"), + CPU_MODEL_ENT_R("K6(tm)-III", "K6 III"), + CPU_MODEL_ENT_R("K6(tm) 3D+", "K6 3D+"), + { NULL } +}; + +/* common to win32 and linux */ +void sigar_cpu_model_adjust(sigar_t *sigar, sigar_cpu_info_t *info) +{ + int len, i; + char model[128], *ptr=model, *end; + + memcpy(model, info->model, sizeof(model)); + + /* trim leading and trailing spaces */ + len = strlen(model); + end = &model[len-1]; + while (*ptr == ' ') ++ptr; + while (*end == ' ') *end-- = '\0'; + + /* remove vendor from model name */ + len = strlen(info->vendor); + if (strnEQ(ptr, info->vendor, len)) { + ptr += len; + if (IS_CPU_R(ptr)) { + ptr += 3; /* remove (R) */ + } + while (*ptr == ' ') ++ptr; + } + + if (*ptr == '-') { + ++ptr; /* e.g. was AMD-K6... */ + } + + for (i=0; cpu_models[i].name; i++) { + const cpu_model_str_t *cpu_model = &cpu_models[i]; + + if (strnEQ(ptr, cpu_model->name, cpu_model->len)) { + memcpy(info->model, cpu_model->rname, cpu_model->rlen); + return; + } + } + + strcpy(info->model, ptr); +} + +/* attempt to derive MHz from model name + * currently works for certain intel strings + * see exp/intel_amd_cpu_models.txt + */ +int sigar_cpu_mhz_from_model(char *model) +{ + int mhz = SIGAR_FIELD_NOTIMPL; + char *ptr = model; + + while (*ptr && (ptr = strchr(ptr, ' '))) { + while(*ptr && !sigar_isdigit(*ptr)) { + ptr++; + } + mhz = sigar_strtoul(ptr); + + if (*ptr == '.') { + /* e.g. "2.40GHz" */ + ++ptr; + mhz *= 100; + mhz += sigar_strtoul(ptr); + break; + } + else if (strnEQ(ptr, "GHz", 3) || + strnEQ(ptr, "MHz", 3)) + { + /* e.g. "1500MHz" */ + break; + } + else { + mhz = SIGAR_FIELD_NOTIMPL; + } + } + + if (mhz != SIGAR_FIELD_NOTIMPL) { + if (strnEQ(ptr, "GHz", 3)) { + mhz *= 10; + } + } + + return mhz; +} + +#if !defined(WIN32) && !defined(NETWARE) +#include +#include +#include +#include +#ifdef SIGAR_HPUX +#include +#endif +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun) || defined(DARWIN) +#include +#endif +#if defined(__sun) || defined(SIGAR_HPUX) +#include +#endif +#if defined(_AIX) || defined(SIGAR_HPUX) || defined(__OpenBSD__) || defined(__NetBSD__) +#include +#endif + +static enum clnt_stat get_sockaddr(struct sockaddr_in *addr, char *host) +{ + register struct hostent *hp; + sigar_hostent_t data; + + memset(addr, 0, sizeof(struct sockaddr_in)); + addr->sin_family = AF_INET; + + if ((addr->sin_addr.s_addr = inet_addr(host)) == -1) { + if (!(hp = sigar_gethostbyname(host, &data))) { + return RPC_UNKNOWNHOST; + } + memcpy(&addr->sin_addr, hp->h_addr, hp->h_length); + } + + return RPC_SUCCESS; +} + +char *sigar_rpc_strerror(int err) +{ + return (char *)clnt_sperrno(err); +} + +SIGAR_DECLARE(int) sigar_rpc_ping(char *host, + int protocol, + unsigned long program, + unsigned long version) +{ + CLIENT *client; + struct sockaddr_in addr; + int sock; + struct timeval timeout; + unsigned short port = 0; + enum clnt_stat rpc_stat; + + rpc_stat = get_sockaddr(&addr, host); + if (rpc_stat != RPC_SUCCESS) { + return rpc_stat; + } + + timeout.tv_sec = 2; + timeout.tv_usec = 0; + addr.sin_port = htons(port); + sock = RPC_ANYSOCK; + + if (protocol == SIGAR_NETCONN_UDP) { + client = + clntudp_create(&addr, program, version, + timeout, &sock); + } + else if (protocol == SIGAR_NETCONN_TCP) { + client = + clnttcp_create(&addr, program, version, + &sock, 0, 0); + } + else { + return RPC_UNKNOWNPROTO; + } + + if (!client) { + return rpc_createerr.cf_stat; + } + + timeout.tv_sec = 10; + timeout.tv_usec = 0; + rpc_stat = clnt_call(client, NULLPROC, (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_void, NULL, timeout); + + clnt_destroy(client); + + return rpc_stat; +} +#endif + +int sigar_file2str(const char *fname, char *buffer, int buflen) +{ + int len, status; + int fd = open(fname, O_RDONLY); + + if (fd < 0) { + return ENOENT; + } + + if ((len = read(fd, buffer, buflen)) < 0) { + status = errno; + } + else { + status = SIGAR_OK; + buffer[len] = '\0'; + } + close(fd); + + return status; +} + +#ifdef WIN32 +#define vsnprintf _vsnprintf +#endif + +#ifdef WIN32 +# define rindex strrchr +#endif + +static int proc_module_get_self(void *data, char *name, int len) +{ + sigar_t *sigar = (sigar_t *)data; + char *ptr = rindex(name, '/'); + + if (!ptr) { + return SIGAR_OK; + } + + if (strnEQ(ptr+1, "libsigar-", 9)) { + int offset = ptr - name; + + sigar->self_path = sigar_strdup(name); + *(sigar->self_path + offset) = '\0'; /* chop libsigar-*.so */ + + if (SIGAR_LOG_IS_DEBUG(sigar)) { + sigar_log_printf(sigar, SIGAR_LOG_DEBUG, + "detected sigar-lib='%s'", + sigar->self_path); + } + + return !SIGAR_OK; /* break loop */ + } + + return SIGAR_OK; +} + +char *sigar_get_self_path(sigar_t *sigar) +{ + if (!sigar->self_path) { + sigar_proc_modules_t procmods; + char *self_path = getenv("SIGAR_PATH"); + + if (self_path) { + sigar->self_path = sigar_strdup(self_path); + return sigar->self_path; + } + + procmods.module_getter = proc_module_get_self; + procmods.data = sigar; + + sigar_proc_modules_get(sigar, + sigar_pid_get(sigar), + &procmods); + + if (!sigar->self_path) { + /* dont try again */ + sigar->self_path = sigar_strdup("."); + } + } + + return sigar->self_path; +} + +#ifdef SIGAR_HAS_DLINFO_MODULES + +static int sigar_dlinfo_get(sigar_t *sigar, const char *func, + void **handle, Link_map **map) +{ + Dl_info dli; + + if (!dladdr((void *)((uintptr_t)sigar_dlinfo_get), &dli)) { + sigar_log_printf(sigar, SIGAR_LOG_ERROR, + "[%s] dladdr(%s) = %s", + func, SIGAR_FUNC, dlerror()); + return ESRCH; + } + + if (!(*handle = dlopen(dli.dli_fname, RTLD_LAZY))) { + sigar_log_printf(sigar, SIGAR_LOG_ERROR, + "[%s] dlopen(%s) = %s", + func, dli.dli_fname, dlerror()); + return ESRCH; + } + + dlinfo(*handle, RTLD_DI_LINKMAP, map); + + if (!map) { + sigar_log_printf(sigar, SIGAR_LOG_ERROR, + "[%s] dlinfo = %s", + func, dlerror()); + return ESRCH; + } + + return SIGAR_OK; +} + +int sigar_dlinfo_modules(sigar_t *sigar, sigar_proc_modules_t *procmods) +{ + int status; + void *handle; + Link_map *map; + + status = sigar_dlinfo_get(sigar, SIGAR_FUNC, &handle, &map); + if (status != SIGAR_OK) { + return status; + } + + while (map->l_prev != NULL) { + map = map->l_prev; + } + + do { + int status = + procmods->module_getter(procmods->data, + (char *)map->l_name, + strlen(map->l_name)); + + if (status != SIGAR_OK) { + /* not an error; just stop iterating */ + break; + } + } while ((map = map->l_next)); + + dlclose(handle); + + return SIGAR_OK; +} +#endif + +SIGAR_DECLARE(void) sigar_log_printf(sigar_t *sigar, int level, + const char *format, ...) +{ + va_list args; + char buffer[8192]; + + if (level > sigar->log_level) { + return; + } + + if (!sigar->log_impl) { + return; + } + + va_start(args, format); + vsnprintf(buffer, sizeof(buffer), format, args); + va_end(args); + + sigar->log_impl(sigar, sigar->log_data, level, buffer); +} + +SIGAR_DECLARE(void) sigar_log(sigar_t *sigar, int level, char *message) +{ + if (level > sigar->log_level) { + return; + } + + if (!sigar->log_impl) { + return; + } + + sigar->log_impl(sigar, sigar->log_data, level, message); +} + +SIGAR_DECLARE(void) sigar_log_impl_set(sigar_t *sigar, void *data, + sigar_log_impl_t impl) +{ + sigar->log_data = data; + sigar->log_impl = impl; +} + +SIGAR_DECLARE(int) sigar_log_level_get(sigar_t *sigar) +{ + return sigar->log_level; +} + +static const char *log_levels[] = { + "FATAL", + "ERROR", + "WARN", + "INFO", + "DEBUG", + "TRACE" +}; + +SIGAR_DECLARE(const char *) sigar_log_level_string_get(sigar_t *sigar) +{ + return log_levels[sigar->log_level]; +} + +SIGAR_DECLARE(void) sigar_log_level_set(sigar_t *sigar, int level) +{ + sigar->log_level = level; +} + +SIGAR_DECLARE(void) sigar_log_impl_file(sigar_t *sigar, void *data, + int level, char *message) +{ + FILE *fp = (FILE*)data; + fprintf(fp, "[%s] %s\n", log_levels[level], message); +} + +#ifndef WIN32 +sigar_int64_t sigar_time_now_millis(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return ((tv.tv_sec * SIGAR_USEC) + tv.tv_usec) / SIGAR_MSEC; +} +#endif diff --git a/vendor/sigar/src/sigar_version_autoconf.c b/vendor/sigar/src/sigar_version_autoconf.c new file mode 100644 index 0000000..7b1f865 --- /dev/null +++ b/vendor/sigar/src/sigar_version_autoconf.c @@ -0,0 +1,22 @@ +#include "sigar.h" + +static sigar_version_t sigar_version = { + __DATE__, + "@SCM_REVISION@", + "libsigar 1.6.2", + "x86_64-apple-darwin11.4.0", + "darwin11.4.0", + "x86_64", + "SIGAR-1.6.2, " + "SCM revision @SCM_REVISION@, " + "built "__DATE__" as x86_64", + 1, + 6, + 2, + 0 +}; + +SIGAR_DECLARE(sigar_version_t *) sigar_version_get(void) +{ + return &sigar_version; +}