diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..e72f527 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,30 @@ +language: c +services: + - docker +env: + - ORACLE_HOME=$HOME/instantclient_18_3 LD_LIBRARY_PATH=$ORACLE_HOME PATH=$ORACLE_HOME:$PATH +addons: + apt: + update: true + packages: + - libpopt-dev +sudo: required +before_install: +- echo "$DOCKER_PASSWORD" | docker login --username $DOCKER_USERNAME --password-stdin +- docker run --detach + --privileged + --publish 127.0.0.1:1521:1521 + --env ORACLE_PWD + maxsatula/agile:18.4.0-xe +- | + (cd $HOME + for t in basic sdk sqlplus tools + do + f=instantclient-${t}-linux.x64-18.3.0.0.0dbru.zip + wget https://github.com/bumpx/oracle-instantclient/raw/master/$f + unzip -q $f && rm $f + done) +- .travis/oracle/wait.sh +- .travis/oracle/customize.sh +before_script: autoreconf --install +script: ./configure --with-oci=y --with-oci-include=$ORACLE_HOME/sdk/include --with-oci-lib=$ORACLE_HOME && make && .travis/test.sh diff --git a/.travis/oracle/customize.sh b/.travis/oracle/customize.sh new file mode 100755 index 0000000..3ab0d5a --- /dev/null +++ b/.travis/oracle/customize.sh @@ -0,0 +1,36 @@ +#!/bin/sh -e + +sqlplus -L -S sys/$ORACLE_PWD@127.0.0.1:1521/XEPDB1 AS SYSDBA < @@ -276,64 +276,3 @@ TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - {description} - Copyright (C) {year} {fullname} - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along - with this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - {signature of Ty Coon}, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. \ No newline at end of file diff --git a/ChangeLog b/ChangeLog index 640a663..802b321 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2019-01-12 Max Satula + +* Allow connection as SYSASM, SYSBKP, SYSDGD, SYSKMT, and SYSRAC + +2017-07-16 Max Satula + +* Add man page + +2017-07-12 Max Satula + +* Fix crash in --ls when Oracle directory object points + to a nonexistent directory +* Do not print column names if no files found in --ls + 2016-04-18 Max Satula * Fix compiler warnings diff --git a/Makefile.am b/Makefile.am index ac2609b..b301451 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,5 +1,6 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = progressmeter yesno src dist_noinst_SCRIPTS = updateforeigns.sh win/build.cmd -dist_noinst_DATA = m4/ax_lib_oracle_oci.m4.patch win/README.md +dist_noinst_DATA = README.md win/README.md dist_noinst_HEADERS = win/include/config.h win/include/unistd.h +dist_man1_MANS = ocp.1 diff --git a/NEWS b/NEWS index c0cd62a..4e5a2e0 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,11 @@ +ocp 0.3 + +* added man page +* added --sysasm, --sysbkp, --sysdgd, --syskmt, and --sysrac options + to connect to Oracle with roles introduced in 12c + +---------------------------------------------------------------------------- + ocp 0.2 * added --sysdba and --sysoper options to connect to Oracle accordingly diff --git a/README.md b/README.md index 463bb58..6ce5877 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ ocp === +[![Build Status](https://travis-ci.org/maxsatula/ocp.svg?branch=develop)](https://travis-ci.org/maxsatula/ocp) +[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=P3D68AUUXLNQU&lc=US&item_number=github%2docp¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted) + `ocp` is a command line tool to download and upload files from/to Oracle Database directories (e.g. DATA_PUMP_DIR) using Oracle SQL Net connection only. Hence no other kind of filesystem access required to a database server. diff --git a/configure.ac b/configure.ac index 4af2918..272b792 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) -AC_INIT([ocp],[0.2],[Max Satula ]) +AC_INIT([ocp],[0.3],[Max Satula ]) AM_INIT_AUTOMAKE AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_SRCDIR([src/ocp.h]) @@ -20,18 +20,18 @@ AC_SYS_LARGEFILE # Checks for libraries. AX_LIB_ORACLE_OCI if test "x${HAVE_ORACLE_OCI}" = xno; then - AC_MSG_ERROR([---------------------------------------------- + AC_MSG_ERROR([ +---------------------------------------------- This software requires Oracle installation 1. Have you set \$ORACLE_HOME? 2. Check if Oracle Home 64/32-bit is OK 3. Check whether native compiler (not GCC) is used for non-Linux platforms -----------------------------------------------)]) +----------------------------------------------]) fi AC_SUBST([ORACLE_OCI_CFLAGS]) AC_SUBST([ORACLE_OCI_LDFLAGS]) -#AC_SEARCH_LIBS([OCIEnvCreate], [clntsh]) AC_SEARCH_LIBS([poptGetContext], [popt]) AC_SEARCH_LIBS([deflateInit2_], [z]) AC_SEARCH_LIBS([clock_gettime], [rt]) diff --git a/m4/ax_lib_oracle_oci.m4 b/m4/ax_lib_oracle_oci.m4 index 9a99b97..a08a7b0 100644 --- a/m4/ax_lib_oracle_oci.m4 +++ b/m4/ax_lib_oracle_oci.m4 @@ -26,7 +26,7 @@ # NOTE: These options described above do not take yes|no values. If 'yes' # value is passed, then WARNING message will be displayed, 'no' value, as # well as the --without-oci-* variations will cause the macro to not check -# enything. +# anything. # # This macro calls: # @@ -48,7 +48,7 @@ # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 13 +#serial 16 AC_DEFUN([AX_LIB_ORACLE_OCI], [ @@ -156,8 +156,11 @@ Please, locate Oracle directories using --with-oci or \ dnl Depending on later Oracle version detection, dnl -lnnz10 flag might be removed for older Oracle < 10.x saved_LDFLAGS="$LDFLAGS" - oci_ldflags="-L$oracle_lib_dir -lclntsh" + saved_LIBS="$LIBS" + oci_ldflags="-L$oracle_lib_dir" + oci_libs="-lclntsh" LDFLAGS="$LDFLAGS $oci_ldflags" + LIBS="$LIBS $oci_libs" dnl dnl Check OCI headers @@ -170,11 +173,11 @@ Please, locate Oracle directories using --with-oci or \ [[ #if defined(OCI_MAJOR_VERSION) #if OCI_MAJOR_VERSION == 10 && OCI_MINOR_VERSION == 2 -// Oracle 10.2 detected +/* Oracle 10.2 detected */ #endif #elif defined(OCI_V7_SYNTAX) -// OK, older Oracle detected -// TODO - mloskot: find better macro to check for older versions; +/* OK, older Oracle detected */ +/* TODO - mloskot: find better macro to check for older versions; */ #else # error Oracle oci.h header not found #endif @@ -214,7 +217,7 @@ if (envh) OCIHandleFree(envh, OCI_HTYPE_ENV); ]] )], [ - ORACLE_OCI_LDFLAGS="$oci_ldflags" + ORACLE_OCI_LDFLAGS="$oci_ldflags $oci_libs" oci_lib_found="yes" AC_MSG_RESULT([yes]) ], @@ -228,6 +231,7 @@ if (envh) OCIHandleFree(envh, OCI_HTYPE_ENV); CPPFLAGS="$saved_CPPFLAGS" LDFLAGS="$saved_LDFLAGS" + LIBS="$saved_LIBS" fi dnl diff --git a/m4/ax_lib_oracle_oci.m4.patch b/m4/ax_lib_oracle_oci.m4.patch deleted file mode 100644 index 7e12a8d..0000000 --- a/m4/ax_lib_oracle_oci.m4.patch +++ /dev/null @@ -1,38 +0,0 @@ ---- ax_lib_oracle_oci.m4.orig 2015-03-29 12:02:04.246725378 -0400 -+++ ax_lib_oracle_oci.m4 2015-03-29 12:02:43.611724292 -0400 -@@ -163,7 +163,7 @@ - dnl - AC_MSG_CHECKING([for Oracle OCI headers in $oracle_include_dir]) - -- AC_LANG_PUSH(C++) -+ AC_LANG_PUSH(C) - AC_COMPILE_IFELSE([ - AC_LANG_PROGRAM([[@%:@include ]], - [[ -@@ -194,7 +194,7 @@ - AC_MSG_RESULT([not found]) - ] - ) -- AC_LANG_POP([C++]) -+ AC_LANG_POP([C]) - - dnl - dnl Check OCI libraries -@@ -203,7 +203,7 @@ - - AC_MSG_CHECKING([for Oracle OCI libraries in $oracle_lib_dir]) - -- AC_LANG_PUSH(C++) -+ AC_LANG_PUSH(C) - AC_LINK_IFELSE([ - AC_LANG_PROGRAM([[@%:@include ]], - [[ -@@ -222,7 +222,7 @@ - AC_MSG_RESULT([not found]) - ] - ) -- AC_LANG_POP([C++]) -+ AC_LANG_POP([C]) - fi - - CPPFLAGS="$saved_CPPFLAGS" diff --git a/ocp.1 b/ocp.1 new file mode 100644 index 0000000..81168e8 --- /dev/null +++ b/ocp.1 @@ -0,0 +1,587 @@ +.TH OCP 1 2019-01-12 GNU "ocp man page" + +.SH NAME +ocp \- copy a file from/to an Oracle database server + +.SH SYNOPSIS +.BI ocp " CONNECTION ORACLEDIRECTORY" : "SOURCE TARGET" +.RI [ OPTIONS " ...]" + +.PP +.BI ocp " CONNECTION SOURCE ORACLEDIRECTORY" :\c +.RI [ TARGET "] [" OPTIONS " ...]" + +.PP +.BI ocp " CONNECTION " \-\-list\-directories +.RI [ OPTIONS " ...]" + +.PP +.BI ocp " CONNECTION " \-\-ls= ORACLEDIRECTORY +.RI [ PATTERN " ...] [" OPTIONS " ...]" + +.PP +.BI ocp " CONNECTION " \-\-rm " ORACLEDIRECTORY" : FILENAME +.RI [ OPTIONS " ...]" + +.PP +.BI ocp " CONNECTION " \-\-gzip " ORACLEDIRECTORY" : FILENAME +.RI [ OPTIONS " ...]" + +.PP +.BI ocp " CONNECTION " \-\-gunzip " ORACLEDIRECTORY" : FILENAME +.RI [ OPTIONS " ...]" + +.PP +.BI ocp " CONNECTION " +.BR \-\-install | \-\-deinstall +.RI [ OPTIONS " ...]" + +.PP +.BR "ocp \-?" | \-\-help | \-\-usage + +.SH DESCRIPTION +.PP +.B ocp +is a command line tool to transfer files between a local system and an +Oracle database server via database connection. +.PP +Here are Oracle privileges required in most cases. +.IP \(bu +CREATE SESSION +.IP \(bu +READ ON DIRECTORY +.I ORACLEDIRECTORY +.IP \(bu +WRITE ON DIRECTORY +.I ORACLEDIRECTORY +.IP \(bu +EXECUTE ON SYS.UTL_FILE, which is granted to PUBLIC by default. +.PP +Some special cases require additional privileges, which are described +later. +.PP +.B ocp +can run in multiple modes, as described below. + +.SS File transfer +File transfer is a primary purpose of +.BR ocp . +When +.IR SOURCE " and " TARGET +are specified as arguments, then +.B ocp +copies a file. + +.PP +If +.I ORACLEDIRECTORY +with a following colon (:) precedes +.IR SOURCE , +then a file is searched on a database server and downloaded to a path +specified as +.IR TARGET . +Correspondingly, if +.I ORACLEDIRECTORY +with a following colon precedes +.IR TARGET , +then a local +.I SOURCE +file is uploaded to a database server. + +.PP +A local file can be either specified as a simple filename, a relative +or an absolute path. For a remote side, only Oracle directory name and +filename separated by a colon are allowed. + +.PP +In download mode a local target may refer to a directory, in this case +a file is copied with the name unchanged. For example, a simple dot +.RB ( . ) +tells to copy a file into a current directory with the same name. + +.PP +In upload mode a target file +name is optional, but the colon must be specified after an Oracle +directory name. If remote filename is omitted, a file is copied with +the name unchanged. + +.PP +To be able to use +.B ocp +in a pipeline, a dash (\-) can be specified as a local filename. That +means standard input is used during upload, or standard output is used +during download. In this case remote filename cannot be omitted. + +.SS File transfer with on the fly compression +Similar to a regular file transfer, but the file contents is +compressed on the source site (either local or remote) before being +transferred over a network to target, where it is immediately +decompressed back to original. Therefore, compressed data is used +temporary just to reduce network traffic. That might be a good option +for slow networks, but where extra CPU load is affordable. In both +upload and download modes, the whole compressed file is temporarily +placed into a Temporary LOB object, so make sure that TEMP tablespace +is large enough. + +.PP +On the fly compression turns on when any of the following switches +specified during transfer: +.BR \-1 .. \-9 , \-\-fast , \-\-best . + +.PP +On the fly compression requires EXECUTE ON SYS.UTL_COMPRESS privilege, +which is granted to PUBLIC by default. + +.SS List Oracle directories +To list all the Oracle directories accessible to a database user, use +.B \-\-list\-directories +option. + +.PP +Output is one Oracle directory per line, with two characters +indicating privileges, Oracle directory name, and the full path name +of the operating system directory of the database server, enclosed in +parentheses. + +.PP +The first character in each line tells whether a database user can +read the directory, and its meaning is as follows. +.TP +.B \- +no read privilege +.TP +.B r +READ ON DIRECTORY +.TP +.B R +READ ON DIRECTORY WITH GRANT OPTION + +.PP +Similarly, the second character in each line tells whether a database user can +write into the directory, and its meaning is as follows. +.TP +.B \- +no write privilege +.TP +.B w +WRITE ON DIRECTORY +.TP +.B W +WRITE ON DIRECTORY WITH GRANT OPTION + +.SS List files in Oracle directory +To list files of an Oracle directory, use +.B \-\-ls +option and specify an Oracle directory name as an argument. +Optionally, one or more file matching patterns can be specified as +additional command line arguments to filter an output. +.PP +Beware while using an asterisk wildcard +.RB ( * ) +in patterns, as shell may resolve it with some filename on a local +system before passing to +.BR ocp , +so most likely asterisks must be escaped by a backslash in UNIX +systems command line. +.PP +Java permissions are required. +.PP +To be able to list filenames, run as DBA +.PP +.BI "dbms_java.grant_permission( '" user "', 'SYS:java.io.FilePermission', '" path "', 'read' )" +.PP +The second permission is recommended but not mandatory. It allows to +view file sizes and last modified times, not just filenames. Also, it +allowes to calculate MD5 and SHA1 hashes. If you need any of these, +run as DBA +.PP +.BI "dbms_java.grant_permission( '" user "', 'SYS:java.io.FilePermission', '" path "/*', 'read' )" +.PP +Where +.I user +is an Oracle user and +.I path +is the full path name of the operating system directory of the +database server. + +.PP +Listing files in Oracle directory requires some objects to be created +in the Oracle database beforehand, which can be done with help of +.B \-\-install +option. + +.SS Remove file from Oracle directory +Remove a file from a database server. Use +.B \-\-rm +and specify Oracle directory name and filename separated by a colon. + +.SS Compress and decompress file in Oracle directory +Files in Oracle directory can be remotely compressed and decompressed +using +.BR gzip (1) +compatible algorithm. The operation runs on a Database server and does +not involve any file transfer over network. + +When compressing +.RB ( \-\-gzip " option)," +a +.B .gz +suffix is added to a filename. +Conversely, when decompressing +.RB ( \-\-gunzip " option)," +the suffix is removed. + +.PP +The whole compressed file is temporarily placed into a Temporary LOB +object, so make sure that TEMP tablespace is large enough. + +.PP +Compression and decompression require EXECUTE ON SYS.UTL_COMPRESS +privilege, which is granted to PUBLIC by default. + +.SS Supporting objects maintenance +List files in Oracle directory is the only feature that requires some +supporting objects to reside in a database. + +.PP +Thus, before using +.BR \-\-ls , +run +.B ocp +with +.B \-\-install +option first to install those objects. +It is safe to run +.BR ocp " with " \-\-install +multiple times when objects are already in the database, as it drops +and recreates them. +The objects are installed locally in the database user schema, which +is why these objects have to be installed for every Oracle account +which intends to list files in Oracle directory, even if these +accounts are in the same database. + +CREATE TYPE and CREATE PROCEDURE privileges are required at the time +of supporting objects installation. + +.PP +Once +.BR \-\-ls +is not needed anymore, +.B \-\-deinstall +option may be used to clean up the mess by dropping the supported +objects previously created by +.BR \-\-install +option. + +.SS Monitoring +.PP +.B ocp +activities may be monitored in Oracle database. +MODULE column of V$SESSION view has a value of \(aqocp\(aq, which is one of the ways how +.B ocp +sessions can be identified, +and ACTION column points out what exact kind of acivity is happening. +Also, whenever (de-)compression is involved, the progress can be +tracked via V$SESSION_LONGOPS view. + +.SS License warning +.PP +Whenever compression or decompression is involved, either standalone or as a part of file transfer, +.B ocp +uses UTL_COMPRESS package. There is controversy whether use of this +package requries a license for Oracle Advanced Compression option, +please contact your Oracle representative for details. +Author of +.B ocp +program is not responsible for any legal consequences +caused by possible Oracle licensing violation while using +.BR ocp . + +.SH OPTIONS + +.TP +.B \-b \-\-background +Submit an Oracle Scheduler job and exit immediately. +.B ocp +does not wait until (de-)compression finishes. +Can only be specified together with either +.B \-\-gzip +or +.BR \-\-gunzip . +Requires CREATE JOB privilege. + +.TP +.B \-c \-\-continue +Continue copying a partially transferred file. This is useful when +you want to finish up a transfer started by a previous instance of +.BR ocp , +or by another program. +Implies +.B \-\-keep\-partial +and overrides previous +.B \-f \-i +options. +Applicable only for file transfer mode, with or without on the fly +compression. + +.TP +.B \-f \-\-force +If a destination file already exists, overwrite it without asking. +Overrides previous +.B \-i \-c +options. +Applicable for file transfer mode, with or without on the fly +compression, and for stand alone compression and decompression. + +.TP +.B \-i \-\-interactive +Prompt before overwrite (overrides previous +.B \-f \-c +options). +Applicable for file transfer mode, with or without on the fly +compression, and for stand alone compression and decompression. + +.TP +.B \-k \-\-keep +Keep (do not delete) source file after (de-)compression finishes. +Can only be used with either +.BR \-\-gzip " or " \-\-gunzip . + +.TP +.B \-\-keep\-partial +If an error or another sort of interruption occurred during file +transfer, do not delete partially transferred file on +destination. Keeping an incomplete file may be useful to retry transfer with +.B \-\-continue +opton. +Applicable only for file transfer mode, with or without on the fly +compression. + +.TP +.B \-\-md5 +Calculate MD5 hashes on listed files and display them instead of size +and last modified time columns. +Can only be used with +.BR \-\-ls . + +.TP +.B \-\-sha1 +Calculate SHA1 hashes on listed files and display them instead of size +and last modified time columns. +Can only be used with +.BR \-\-ls . + +.TP +.B \-\-sysdba +Connect to a database as SYSDBA +.TP +.B \-\-sysoper +Connect to a database as SYSOPER +.TP +.B \-\-sysasm +Connect to a database as SYSASM +.TP +.B \-\-sysbkp +Connect to a database as SYSBKP +.TP +.B \-\-sysdgd +Connect to a database as SYSDGD +.TP +.B \-\-syskmt +Connect to a database as SYSKMT +.TP +.B \-\-sysrac +Connect to a database as SYSRAC + +.TP +.B \-\-usage +Display brief usage message + +.TP +.BI \- # " \-\-fast \-\-best" +Regulate the speed of compression using the specified digit +.IR # , +where +.B \-1 +or +.B \-\-fast +indicates the fastest compression method (less compression) +and +.B \-9 +or +.B \-\-best +indicates the slowest compression method (best compression). +The default compression level is +.BR \-6 +(that is, biased towards high compression at expense of speed). +Can only be specified for file transfer or when using +.BR \-\-gzip . + +.TP +.B \-? \-\-help +Show help message + +.SH "EXIT STATUS" + +.IP 0 +Success + +.IP 1 +Error in command line arguments + +.IP 2 +Error in OCI object initialization + +.IP 3 +Failed to login to a database + +.IP 4 +Local filesystem related error + +.IP 5 +Oracle error + +.IP 6 +(De-)compression error on a local side + +.IP 7 +Error listing files in Oracle directory + +.SH ENVIRONMENT + +.PP +Since +.B ocp +connects to an Oracle database, it requires Oracle client installed on +the system. Either full or Instant Client is good. + +.SH BUGS + +When downloading a file through SHARED server connection, Oracle may +give corrupt data. Upload works fine. Nonetheless, it is poor practice +to use SHARED server for file transfer. +.B ocp +protects from download attempts via SHARED server connection whenever +possible. The best option is to use DEDICATED server connection +instead, however if by some reason environment does not allow that, +use on the fly compression (does not matter which compression method) +as a workaround. + +.SH EXAMPLES + +.PP +.B ocp scott/tiger@orcl DATA_PUMP_DIR:myfile.dmp . \-i +.PP +Connect as user +.B scott +with password +.B tiger +using connection string +.B orcl +and download +.B myfile.dmp +from Oracle directory +.B DATA_PUMP_DIR +to a current directory of the local system. If a file already exists +in the current directory, prompt before overwrite. + +.PP +.B ocp scott@orcl file2.dmp DATA_PUMP_DIR: \-c +.PP +As user +.B scott +connect to +.B orcl +database, ask for a password interactively, +and upload +.B file2.dmp +to Oracle directory +.B DATA_PUMP_DIR\c +, keeping the same filename. If a file already exists on the Oracle +side, assume it is partially uploaded file and resume transfer +operation from the point it was interrupted. + +.PP +.B ocp /@oraclehost:1521/mydb.example.com MY_PUMP_DIR:source.dmp ~/Downloads/dest.dmp \-9 +.PP +Use External Password Store (Oracle Wallet) for database +authentication and easy connect naming method, download +.B source.dmp +and save it as +.B dest.dmp +on a local file system in +.B Downloads +subdirectory of the home directory. Use best on the fly compression +method. + +.PP +.B ocp /@canada SRC_DIR:myfile.dmp \- | ocp /@australia \- DEST_DIR:myfile.dmp +.PP +If +.BR canada " and " australia +databases cannot access each other over network directly, two +.B ocp +invocations can be pipelined on a third intermediate system which have +connection to both databases, as shown above. + +.PP +.B ocp user123/weakpassword@mydb \-\-list-directories +.PP +List Oracle directories and access levels for +.B user123 +database user. + +.PP +.B ocp /@mydb \-\-install +.PP +.B ocp /@mydb \-\-ls=DATA_PUMP_DIR bkp_201[0\-5]\e*.dmp expdp_{prod,test,qa,dev}.dmp +.PP +Install supporting objects before the first use of +.B \-\-ls +and then list files (with sizes and last modified times, if user has privileges) +matching two patterns. + +.PP +.B ocp /@mydb \-\-ls=DATA_PUMP_DIR \-\-sha1 +.PP +List all files in +.B DATA_PUMP_DIR +Oracle directory and calculate their SHA1 hashes. + +.PP +.B ocp sys/oracle@proddb \-\-gzip MY_DIR2:bigfile.dmp \-f \-\-sysdba +.PP +Connect as +.B SYS +user with +.B SYSDBA +role and compress +.B bigfile.dmp +file in +.B MY_DIR2 +Oracle directory using default compression method into +.BR bigfile.dmp.gz . +If file +.B bigfile.dmp.gz +already exists, overwrite it without asking. +Wait until Oracle server completes compression. + +.PP +.B ocp /@proddb \-\-gunzip DATA_PUMP_DIR:another_file.dmp.gz \-k \-b +.PP +Submit an Oracle Scheduler job to decompress +.B another_file.dmp.gz +into +.B another_file.dmp +and exit immediately without waiting for completion. Once job +finishes decompression, it will not delete an original file +.BR another_file.dmp.gz . + +.SH AUTHOR + +Written by Max Satula. + +.SH "SEE ALSO" +.UR https://github.com/maxsatula/ocp +Project page +.UE diff --git a/progressmeter/atomicio.c b/progressmeter/atomicio.c index 336bd83..d61f09b 100644 --- a/progressmeter/atomicio.c +++ b/progressmeter/atomicio.c @@ -35,8 +35,7 @@ /* * Modified by Max Satula by adding of an extra include below */ -#define __need_IOV_MAX -#include +#define __USE_XOPEN #include #include "atomicio.h" diff --git a/progressmeter/atomicio.c.patch b/progressmeter/atomicio.c.patch index f501421..555b2da 100644 --- a/progressmeter/atomicio.c.patch +++ b/progressmeter/atomicio.c.patch @@ -1,14 +1,13 @@ --- atomicio.c.orig 2015-03-29 12:02:02.508726981 -0400 +++ atomicio.c 2015-03-29 11:54:55.114741280 -0400 -@@ -32,6 +32,11 @@ +@@ -32,6 +32,10 @@ #include #include #include +/* + * Modified by Max Satula by adding of an extra include below + */ -+#define __need_IOV_MAX -+#include ++#define __USE_XOPEN #include #include "atomicio.h" diff --git a/progressmeter/atomicio.h b/progressmeter/atomicio.h index 0d728ac..8b3cc6e 100644 --- a/progressmeter/atomicio.h +++ b/progressmeter/atomicio.h @@ -1,4 +1,4 @@ -/* $OpenBSD: atomicio.h,v 1.11 2010/09/22 22:58:51 djm Exp $ */ +/* $OpenBSD: atomicio.h,v 1.12 2018/12/27 03:25:25 djm Exp $ */ /* * Copyright (c) 2006 Damien Miller. All rights reserved. @@ -29,6 +29,8 @@ #ifndef _ATOMICIO_H #define _ATOMICIO_H +struct iovec; + /* * Ensure all of data on socket comes through. f==read || f==vwrite */ diff --git a/progressmeter/misc.c b/progressmeter/misc.c index 50a77c1..36bc740 100644 --- a/progressmeter/misc.c +++ b/progressmeter/misc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: misc.c,v 1.107 2016/11/30 00:28:31 dtucker Exp $ */ +/* $OpenBSD: misc.c,v 1.136 2018/12/27 03:25:25 djm Exp $ */ /* * Copyright (c) 2000 Markus Friedl. All rights reserved. * Copyright (c) 2005,2006 Damien Miller. All rights reserved. @@ -32,13 +32,18 @@ #include #include +void +monotime_ts(struct timespec *ts) +{ + /*if (*/clock_gettime(CLOCK_MONOTONIC, ts)/* != 0) + fatal("clock_gettime: %s", strerror(errno))*/; +} + double monotime_double(void) { struct timespec ts; - /*if (*/clock_gettime(CLOCK_MONOTONIC, &ts)/* != 0) - fatal("clock_gettime: %s", strerror(errno))*/; - - return (ts.tv_sec + (double)ts.tv_nsec / 1000000000); + monotime_ts(&ts); + return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0; } diff --git a/src/compress.c b/src/compress.c index 10c5cb4..d90567e 100644 --- a/src/compress.c +++ b/src/compress.c @@ -75,7 +75,7 @@ void Compress(struct ORACLEALLINONE *oraAllInOne, char* pDirectory, int compress #endif if (ociResult) - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to compress file in oracle directory\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to compress file in oracle directory\n"); ReleaseStmt(oraAllInOne); SetSessionAction(oraAllInOne, 0); @@ -121,7 +121,7 @@ void Uncompress(struct ORACLEALLINONE *oraAllInOne, char* pDirectory, int isKeep #endif if (ociResult) - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to uncompress file in oracle directory\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to uncompress file in oracle directory\n"); ReleaseStmt(oraAllInOne); SetSessionAction(oraAllInOne, 0); @@ -154,7 +154,7 @@ void SubmitCompressJob(struct ORACLEALLINONE *oraAllInOne, char* pDirectory, int PrepareStmtAndBind(oraAllInOne, &oraStmtCompress); if (ExecuteStmt(oraAllInOne)) - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to submit a compression job\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to submit a compression job\n"); printf("Submitted a job %s\n", vJobName); ReleaseStmt(oraAllInOne); @@ -183,7 +183,7 @@ void SubmitUncompressJob(struct ORACLEALLINONE *oraAllInOne, char* pDirectory, i PrepareStmtAndBind(oraAllInOne, &oraStmtUncompress); if (ExecuteStmt(oraAllInOne)) - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to submit a decompression job\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to submit a decompression job\n"); printf("Submitted a job %s\n", vJobName); ReleaseStmt(oraAllInOne); diff --git a/src/exitstatus.h b/src/exitstatus.h new file mode 100644 index 0000000..b86f7a8 --- /dev/null +++ b/src/exitstatus.h @@ -0,0 +1,35 @@ +/***************************************************************************** +Copyright (C) 2018 Max Satula + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*****************************************************************************/ + +#ifndef _EXITSTATUS_H_ +#define _EXITSTATUS_H_ + +/* Program return values */ + +#define RET_DONOTEXIT -1 /* Print error message but do not exit program */ +#define RET_OK 0 /* Success */ +#define RET_USAGE 1 /* Error in command line arguments */ +#define RET_OCIINIT 2 /* Error in OCI object initialization */ +#define RET_LOGIN 3 /* Failed to login to a database */ +#define RET_FS 4 /* Local filesystem related error */ +#define RET_ORA 5 /* Oracle error */ +#define RET_ZLIB 6 /* LIBZ error */ +#define RET_LS 7 /* Error listing files in Oracle directory */ + +#endif diff --git a/src/j_ocp_DirList.java b/src/j_ocp_DirList.java index be32555..b98c940 100644 --- a/src/j_ocp_DirList.java +++ b/src/j_ocp_DirList.java @@ -20,7 +20,7 @@ public class j_ocp_DirList { public static ARRAY getList(String directory, String pattern, String hashAlgorithm) - throws SQLException, NoSuchAlgorithmException + throws SQLException, NoSuchAlgorithmException, FileNotFoundException { Connection conn = new OracleDriver().defaultConnection(); ArrayDescriptor arrayDescriptor = new ArrayDescriptor("T_OCP_FILE_LIST", conn); @@ -42,6 +42,9 @@ public boolean accept(File dir, String name) { } else { files = path.listFiles(); } + if (files == null) { + throw new FileNotFoundException(directory); + } Object[][] result = new Object[files.length][4]; for (int i = 0; i < files.length; i++) { diff --git a/src/j_ocp_DirList.text b/src/j_ocp_DirList.text index 95e3a22..5f6ca8b 100644 --- a/src/j_ocp_DirList.text +++ b/src/j_ocp_DirList.text @@ -20,7 +20,7 @@ import java.util.regex.PatternSyntaxException;\n\ public class j_ocp_DirList\n\ {\n\ public static ARRAY getList(String directory, String pattern, String hashAlgorithm)\n\ - throws SQLException, NoSuchAlgorithmException\n\ + throws SQLException, NoSuchAlgorithmException, FileNotFoundException\n\ {\n\ Connection conn = new OracleDriver().defaultConnection();\n\ ArrayDescriptor arrayDescriptor = new ArrayDescriptor(\"T_OCP_FILE_LIST\", conn);\n\ @@ -42,6 +42,9 @@ public class j_ocp_DirList\n\ } else {\n\ files = path.listFiles();\n\ }\n\ + if (files == null) {\n\ + throw new FileNotFoundException(directory);\n\ + }\n\ Object[][] result = new Object[files.length][4];\n\ for (int i = 0; i < files.length; i++)\n\ {\n\ diff --git a/src/ls.c b/src/ls.c index 60f844a..61909e0 100644 --- a/src/ls.c +++ b/src/ls.c @@ -85,24 +85,6 @@ SELECT t.file_name,\n\ SetSessionAction(oraAllInOne, "LS"); PrepareStmtAndBind(oraAllInOne, &oraStmtLs); - if (hashAlgorithm != HASH_NONE) - { - printf("Contents of %s directory\n\ -%-40s %s hash\n\ ----------------------------------------- ", - pDirectory, "File Name", vHashAlgorithm); - for (j = 0; j < hashLength*2; j++) - printf("-"); - printf("\n"); - } - else - { - printf("Contents of %s directory\n\ -%-40s %-12s %s\n\ ----------------------------------------- ------------ -------------------\n", - pDirectory, "File Name", " Size", "Last Modified"); - } - i = 0; totalBytes = 0; foundKnownSize = foundUnknownSize = 0; @@ -111,6 +93,17 @@ SELECT t.file_name,\n\ { if (hashAlgorithm != HASH_NONE) { + if (!i) + { + printf("Contents of %s directory\n\ +%-40s %s hash\n\ +---------------------------------------- ", + pDirectory, "File Name", vHashAlgorithm); + for (j = 0; j < hashLength*2; j++) + printf("-"); + printf("\n"); + } + printf("%-40s ", vFileName); if (oraStmtLs.oraDefines[3].indp != -1) @@ -122,25 +115,37 @@ SELECT t.file_name,\n\ } printf("\n"); } - else if (oraStmtLs.oraDefines[1].indp != -1 && - oraStmtLs.oraDefines[2].indp != -1) - { - printf("%-40s %12lld %02d/%02d/%d %02d:%02d:%02d\n", - vFileName, - (long long)vBytes, - (int)vLastModified[2], - (int)vLastModified[3], - ((int)vLastModified[0]-100) * 100 + ((int)vLastModified[1] - 100), - (int)vLastModified[4] - 1, - (int)vLastModified[5] - 1, - (int)vLastModified[6] - 1); - totalBytes += vBytes; - foundKnownSize = 1; - } else { - printf("%-40s (no access) (no access)\n", vFileName); - foundUnknownSize = 1; + if (!i) + { + printf("Contents of %s directory\n\ +%-40s %-12s %s\n\ +---------------------------------------- ------------ -------------------\n", + pDirectory, "File Name", " Size", "Last Modified"); + } + + if (oraStmtLs.oraDefines[1].indp != -1 && + oraStmtLs.oraDefines[2].indp != -1) + { + + printf("%-40s %12lld %02d/%02d/%d %02d:%02d:%02d\n", + vFileName, + (long long)vBytes, + (int)vLastModified[2], + (int)vLastModified[3], + ((int)vLastModified[0]-100) * 100 + ((int)vLastModified[1] - 100), + (int)vLastModified[4] - 1, + (int)vLastModified[5] - 1, + (int)vLastModified[6] - 1); + totalBytes += vBytes; + foundKnownSize = 1; + } + else + { + printf("%-40s (no access) (no access)\n", vFileName); + foundUnknownSize = 1; + } } i++; @@ -149,18 +154,21 @@ SELECT t.file_name,\n\ } if (ociResult != OCI_NO_DATA) - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to list files in oracle directory\n"); + ExitWithError(oraAllInOne, RET_LS, ERROR_OCI, "Failed to list files in oracle directory\n"); - if (hashAlgorithm == HASH_NONE) + if (i) { - if (i) - printf("---------------------------------------- ------------ -------------------\n"); - printf("%5d File(s)", i); - if (!foundKnownSize && foundUnknownSize) - printf("\n"); - else - printf(" %39lld%s\n", totalBytes, foundUnknownSize ? "+" : ""); + if (hashAlgorithm == HASH_NONE) + { + printf("---------------------------------------- ------------ -------------------\n%5d File(s)", i); + if (!foundKnownSize && foundUnknownSize) + printf("\n"); + else + printf(" %39lld%s\n", totalBytes, foundUnknownSize ? "+" : ""); + } } + else + printf("No files found\n"); ReleaseStmt(oraAllInOne); SetSessionAction(oraAllInOne, 0); diff --git a/src/lsdir.c b/src/lsdir.c index 3050607..8f478ff 100644 --- a/src/lsdir.c +++ b/src/lsdir.c @@ -81,7 +81,7 @@ SELECT d.directory_name,\n\ } if (ociResult != OCI_NO_DATA) - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to list oracle directories\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to list oracle directories\n"); ReleaseStmt(oraAllInOne); SetSessionAction(oraAllInOne, 0); diff --git a/src/main.c b/src/main.c index b104e7f..62c8412 100644 --- a/src/main.c +++ b/src/main.c @@ -65,8 +65,7 @@ void ExitWithUsage(poptContext* poptcon) #else fprintf(stderr, "Try to run with --help or --usage option\n"); #endif - exit(1); - /* 1 - Error in command line arguments */ + exit(RET_USAGE); } void SplitToDirectoryAndFileName(poptContext *poptcon, char* pDirectory, char* pFileName) @@ -109,14 +108,14 @@ void ConfirmOverwrite(struct ORACLEALLINONE *oraAllInOne, struct PROGRAM_OPTIONS switch (programOptions->transferMode) { case TRANSFER_MODE_FAIL: - ExitWithError(oraAllInOne, 1, ERROR_NONE, "File already exists on destination\n"); + ExitWithError(oraAllInOne, RET_FS, ERROR_NONE, "File already exists on destination\n"); break; case TRANSFER_MODE_INTERACTIVE: /* TODO: if !isatty then just fail w/o asking? */ fprintf (stderr, "%s: overwrite %s? ", PACKAGE, fileName); if (!yesno()) - ExitWithError(oraAllInOne, 0, ERROR_NONE, 0); + ExitWithError(oraAllInOne, RET_OK, ERROR_NONE, 0); break; } } @@ -189,8 +188,13 @@ int main(int argc, const char *argv[]) { "list-directories", '\0', POPT_ARG_NONE, 0, ACTION_LSDIR, "List Oracle directories" }, { "ls", '\0', POPT_ARG_STRING, &programOptions.lsDirectoryName, ACTION_LS, "List files in Oracle directory", "DIRECTORY" }, { "rm", '\0', POPT_ARG_NONE, 0, ACTION_RM, "Remove file from Oracle directory" }, - { "sysdba", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSDBA, "Connect as SYSDBA" }, + { "sysdba", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSDBA, "Connect as SYSDBA" }, { "sysoper", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSOPER, "Connect as SYSOPER" }, + { "sysasm", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSASM, "Connect as SYSASM" }, + { "sysbkp", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSBKP, "Connect as SYSBKP" }, + { "sysdgd", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSDGD, "Connect as SYSDGD" }, + { "syskmt", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSKMT, "Connect as SYSKMT" }, + { "sysrac", '\0', POPT_ARG_VAL, &programOptions.adminMode, OCI_SYSRAC, "Connect as SYSRAC" }, { NULL, '\0', POPT_ARG_INCLUDE_TABLE, transferModeOptions, 0, "Transfer options:" }, { NULL, '\0', POPT_ARG_INCLUDE_TABLE, compressionOptions, 0, "Compression options:" }, { NULL, '\0', POPT_ARG_INCLUDE_TABLE, lsOptions, 0, "File list options:" }, @@ -465,7 +469,7 @@ int main(int argc, const char *argv[]) } #endif if (!pwdptr) - ExitWithError(&oraAllInOne, 1, ERROR_OS, 0); + ExitWithError(&oraAllInOne, RET_USAGE, ERROR_OS, 0); OracleLogon(&oraAllInOne, connectionString, pwdptr, dbconptr, programOptions.adminMode, PACKAGE, programOptions.numberOfOracleSessions); @@ -533,5 +537,5 @@ int main(int argc, const char *argv[]) break; } - ExitWithError(&oraAllInOne, 0, ERROR_NONE, 0); + ExitWithError(&oraAllInOne, RET_OK, ERROR_NONE, 0); } diff --git a/src/oracle.c b/src/oracle.c index 18de297..185fb7b 100644 --- a/src/oracle.c +++ b/src/oracle.c @@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include "oracle.h" +#define ORA_JAVA_EXCEPTION 29532 + struct BINDVARIABLE NO_BIND_VARIABLES[] = { { 0 } }; struct ORACLEDEFINE NO_ORACLE_DEFINES[] = { { 0 } }; @@ -60,7 +62,7 @@ void PrepareStmtAndBind2(struct ORACLEALLINONE *oraAllInOne, struct ORACLESTATEM strlen(oracleStatement->sql), 0, 0, OCI_NTV_SYNTAX, OCI_DEFAULT)) { - ExitWithError(oraAllInOne, 2, ERROR_OCI, "Failed to prepare %s\n", oracleStatement->sql); + ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_OCI, "Failed to prepare %s\n", oracleStatement->sql); } for (i = 0; oracleStatement->oraDefines[i].value; i++) @@ -74,7 +76,7 @@ void PrepareStmtAndBind2(struct ORACLEALLINONE *oraAllInOne, struct ORACLESTATEM &oracleStatement->oraDefines[i].indp, 0, 0, OCI_DEFAULT)) { - ExitWithError(oraAllInOne, 2, ERROR_OCI, "Failed to set up SQL query output field #%d\n", i + 1); + ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_OCI, "Failed to set up SQL query output field #%d\n", i + 1); } } @@ -90,7 +92,7 @@ void PrepareStmtAndBind2(struct ORACLEALLINONE *oraAllInOne, struct ORACLESTATEM oracleStatement->bindVariables[i].dty, 0, 0, 0, 0, 0, OCI_DEFAULT)) { - ExitWithError(oraAllInOne, 2, ERROR_OCI, "Failed to bind %s\n", oracleStatement->bindVariables[i].name); + ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_OCI, "Failed to bind %s\n", oracleStatement->bindVariables[i].name); } } } @@ -134,6 +136,9 @@ void ExitWithError(struct ORACLEALLINONE *oraAllInOne, int exitCode, enum ERROR_ int i; sb4 errorCode; char errorMsg[MAX_FMT_SIZE]; + char* msgPtr; + + static const char* javaFileNotFoundException = "java.io.FileNotFoundException: "; fflush(stdout); if (message) @@ -153,7 +158,16 @@ void ExitWithError(struct ORACLEALLINONE *oraAllInOne, int exitCode, enum ERROR_ if (oraAllInOne->errhp) { OCIErrorGet(oraAllInOne->errhp, 1, 0, &errorCode, errorMsg, sizeof(errorMsg), OCI_HTYPE_ERROR); - fprintf(stderr, "%s", errorMsg); + if (exitCode == RET_LS && errorCode == ORA_JAVA_EXCEPTION && + (msgPtr = strstr(errorMsg, javaFileNotFoundException))) + { + fprintf(stderr, "Directory does not exist on the database server: %s", + msgPtr + strlen(javaFileNotFoundException)); + } + else + { + fprintf(stderr, "%s", errorMsg); + } } break; case ERROR_OS: @@ -176,17 +190,19 @@ void ExitWithError(struct ORACLEALLINONE *oraAllInOne, int exitCode, enum ERROR_ for (i = 0; i < MAX_ORA_SESSIONS; i++) { - if (oraAllInOne->svchp[i]) - { - OCISessionEnd(oraAllInOne->svchp[i], oraAllInOne->errhp, oraAllInOne->usrhp[i], OCI_DEFAULT); - OCIHandleFree(oraAllInOne->svchp[i], OCI_HTYPE_SVCCTX); - oraAllInOne->svchp[i] = 0; - } if (oraAllInOne->usrhp[i]) { + OCISessionEnd(oraAllInOne->svchp[i], oraAllInOne->errhp, oraAllInOne->usrhp[i], OCI_DEFAULT); OCIHandleFree(oraAllInOne->usrhp[i], OCI_HTYPE_SESSION); oraAllInOne->usrhp[i] = 0; } + + if (oraAllInOne->svchp[i]) + { + OCIHandleFree(oraAllInOne->svchp[i], OCI_HTYPE_SVCCTX); + oraAllInOne->svchp[i] = 0; + } + if (oraAllInOne->srvhp[i]) { OCIServerDetach(oraAllInOne->srvhp[i], oraAllInOne->errhp, OCI_DEFAULT); @@ -200,6 +216,7 @@ void ExitWithError(struct ORACLEALLINONE *oraAllInOne, int exitCode, enum ERROR_ OCIHandleFree(oraAllInOne->errhp, OCI_HTYPE_ERROR); oraAllInOne->errhp = 0; } + if (oraAllInOne->envhp) { OCITerminate(OCI_DEFAULT); @@ -226,43 +243,42 @@ void OracleLogon(struct ORACLEALLINONE *oraAllInOne, (void (*)(void *, void *))0, (size_t)0, (void **)0)) { - ExitWithError(oraAllInOne, 2, ERROR_NONE, "Failed to create OCI environment\n"); - /* 2 - Error in OCI object initialization */ + ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_NONE, "Failed to create OCI environment\n"); } if (OCIHandleAlloc( (dvoid *) oraAllInOne->envhp, (dvoid **) &oraAllInOne->errhp, (ub4) OCI_HTYPE_ERROR, 0, (dvoid **) 0)) { - ExitWithError(oraAllInOne, 2, ERROR_NONE, "Failed to initialize OCIError\n"); + ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_NONE, "Failed to initialize OCIError\n"); } for (i = 0; i < numberOfConnections; i++) { if (OCIHandleAlloc(oraAllInOne->envhp, (void*) &oraAllInOne->srvhp[i], OCI_HTYPE_SERVER, 0, 0)) { - ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to attach to a server\n"); + ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to attach to a server\n"); } if (OCIServerAttach(oraAllInOne->srvhp[i], oraAllInOne->errhp, (text*)connection, (ub4)strlen(connection), OCI_DEFAULT)) { - ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to attach to server\n"); + ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to attach to server\n"); } if (OCIHandleAlloc(oraAllInOne->envhp, (void*) &oraAllInOne->svchp[i], OCI_HTYPE_SVCCTX, 0, 0)) { - ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to login to a database\n"); + ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to login to a database\n"); } if (OCIAttrSet(oraAllInOne->svchp[i], OCI_HTYPE_SVCCTX, oraAllInOne->srvhp[i], 0, OCI_ATTR_SERVER, oraAllInOne->errhp)) { - ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to login to a database\n"); + ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to login to a database\n"); } if (OCIHandleAlloc(oraAllInOne->envhp, (void*) &oraAllInOne->usrhp[i], OCI_HTYPE_SESSION, 0, 0)) { - ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to login to a database\n"); + ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to login to a database\n"); } if (*userName) @@ -274,7 +290,7 @@ void OracleLogon(struct ORACLEALLINONE *oraAllInOne, (text*)password, (ub4)strlen(password), OCI_ATTR_PASSWORD, oraAllInOne->errhp)) { - ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to login to a database\n"); + ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to login to a database\n"); } attrType = OCI_CRED_RDBMS; } @@ -285,24 +301,23 @@ void OracleLogon(struct ORACLEALLINONE *oraAllInOne, oraAllInOne->usrhp[i], attrType, adminMode)) { case OCI_SUCCESS_WITH_INFO: - ExitWithError(oraAllInOne, -1, ERROR_OCI, 0); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, 0); case OCI_SUCCESS: break; default: - ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to login to a database\n"); - /* 3 - Failed to login to a database */ + ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to login to a database\n"); } if (OCIAttrSet(oraAllInOne->svchp[i], OCI_HTYPE_SVCCTX, oraAllInOne->usrhp[i], 0, OCI_ATTR_SESSION, oraAllInOne->errhp)) { - ExitWithError(oraAllInOne, 3, ERROR_OCI, "Failed to login to a database\n"); + ExitWithError(oraAllInOne, RET_LOGIN, ERROR_OCI, "Failed to login to a database\n"); } if (OCIAttrSet(oraAllInOne->usrhp[i], OCI_HTYPE_SESSION, (void*)module, strlen(module), OCI_ATTR_MODULE, oraAllInOne->errhp)) { - ExitWithError(oraAllInOne, -1, ERROR_OCI, "Could not set MODULE in V$SESSION\n"); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Could not set MODULE in V$SESSION\n"); } } } @@ -312,7 +327,7 @@ void SetSessionAction2(struct ORACLEALLINONE *oraAllInOne, const char* action, i if (OCIAttrSet(oraAllInOne->usrhp[index], OCI_HTYPE_SESSION, (void*)action, action ? strlen(action) : 0, OCI_ATTR_ACTION, oraAllInOne->errhp)) { - ExitWithError(oraAllInOne, -1, ERROR_OCI, "Could not set ACTION in V$SESSION\n"); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Could not set ACTION in V$SESSION\n"); } } @@ -334,7 +349,7 @@ void ExecuteSimpleSqls(struct ORACLEALLINONE *oraAllInOne, struct ORACLESIMPLESQ if (!oracleSimpleSqls->errCodeToIgnore || (OCIErrorGet(oraAllInOne->errhp, 1, 0, &errorCode, errorMsg, sizeof(errorMsg), OCI_HTYPE_ERROR), errorCode != oracleSimpleSqls->errCodeToIgnore)) - ExitWithError(oraAllInOne, 4, ERROR_OCI, 0); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, 0); } ReleaseStmt(oraAllInOne); oracleSimpleSqls++; @@ -358,6 +373,6 @@ select sys_context('USERENV', 'SID'),\n\ PrepareStmtAndBind2(oraAllInOne, &oraStmtGetSid, index); if (ExecuteStmt2(oraAllInOne, index)) - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Cannot get SID of the current session\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Cannot get SID of the current session\n"); ReleaseStmt2(oraAllInOne, index); } diff --git a/src/oracle.h b/src/oracle.h index e8bd833..f577a66 100644 --- a/src/oracle.h +++ b/src/oracle.h @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define _ORACLE_H_ #include +#include "exitstatus.h" #define MAX_FMT_SIZE 4096 #define ORA_IDENTIFIER_SIZE 30 diff --git a/src/orafileattr.c b/src/orafileattr.c index d1354b6..882ffd7 100644 --- a/src/orafileattr.c +++ b/src/orafileattr.c @@ -58,7 +58,7 @@ end;", PrepareStmtAndBind(oraAllInOne, &oraStmtFattr); if (ExecuteStmt(oraAllInOne)) - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to get remote file attributes\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to get remote file attributes\n"); ReleaseStmt(oraAllInOne); } diff --git a/src/rm.c b/src/rm.c index fba2042..fbce7af 100644 --- a/src/rm.c +++ b/src/rm.c @@ -42,7 +42,7 @@ void Rm(struct ORACLEALLINONE *oraAllInOne, char* pDirectory, char* pFileName) PrepareStmtAndBind(oraAllInOne, &oraStmtRm); if (ExecuteStmt(oraAllInOne)) - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to remove file in oracle directory\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to remove file in oracle directory\n"); ReleaseStmt(oraAllInOne); SetSessionAction(oraAllInOne, 0); diff --git a/src/transfer.c b/src/transfer.c index 39dc0c5..f63eff3 100644 --- a/src/transfer.c +++ b/src/transfer.c @@ -182,7 +182,7 @@ select server\n\ } else if (strcmp(vServerType, "DEDICATED")) { - ExitWithError(oraAllInOne, 4, ERROR_NONE, "Must connect through DEDICATED server, got %s\n", vServerType); + ExitWithError(oraAllInOne, RET_LOGIN, ERROR_NONE, "Must connect through DEDICATED server, got %s\n", vServerType); } ReleaseStmt(oraAllInOne); } @@ -221,7 +221,7 @@ select server\n\ PrepareStmtAndBind(oraAllInOne, &oraStmtOpen); if (ExecuteStmt(oraAllInOne)) - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to open an Oracle remote file for %s\n", + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to open an Oracle remote file for %s\n", readingDirection ? "reading" : "writing"); ReleaseStmt(oraAllInOne); @@ -252,21 +252,21 @@ select server\n\ if (!isStdUsed && (fp = fopen(pLocalFile, readingDirection ? (isResume ? "ab" : "wb") : "rb")) == NULL) { - ExitWithError(oraAllInOne, -1, ERROR_OS, "Error opening a local %s file for %s\n", + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OS, "Error opening a local %s file for %s\n", readingDirection ? "destination" : "source", readingDirection ? "writing" : "reading"); - /* 4 - Local filesystem related errors */ + if (!readingDirection && !isKeepPartial) { PrepareStmtAndBind(oraAllInOne, &oraStmtClose); if (ExecuteStmt(oraAllInOne)) { - ExitWithError(oraAllInOne, -1, ERROR_OCI, "Error closing an Oracle remote file\n"); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Error closing an Oracle remote file\n"); } ReleaseStmt(oraAllInOne); Rm(oraAllInOne, pDirectory, pRemoteFile); } - ExitWithError(oraAllInOne, 4, ERROR_NONE, 0); + ExitWithError(oraAllInOne, RET_FS, ERROR_NONE, 0); } if (isStdUsed) @@ -281,14 +281,14 @@ select server\n\ { if (!isStdUsed) fclose(fp); - ExitWithError(oraAllInOne, -1, ERROR_OCI, "Failed execution of %s\n", + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Failed execution of %s\n", oraAllInOne->currentStmt[0]->sql); if (!isKeepPartial) { if (unlink(pLocalFile)) - ExitWithError(oraAllInOne, 3, ERROR_OS, "Could not remove partial file %s\n", pLocalFile); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OS, "Could not remove partial file %s\n", pLocalFile); } - ExitWithError(oraAllInOne, 3, ERROR_NONE, 0); + ExitWithError(oraAllInOne, RET_ORA, ERROR_NONE, 0); } else { @@ -297,13 +297,13 @@ select server\n\ { if (!isStdUsed) fclose(fp); - ExitWithError(oraAllInOne, -1, ERROR_OS, "Error writing to a local file\n"); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OS, "Error writing to a local file\n"); if (!isKeepPartial) { if (unlink(pLocalFile)) - ExitWithError(oraAllInOne, 4, ERROR_OS, "Could not remove partial file %s\n", pLocalFile); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OS, "Could not remove partial file %s\n", pLocalFile); } - ExitWithError(oraAllInOne, 4, ERROR_NONE, 0); + ExitWithError(oraAllInOne, RET_FS, ERROR_NONE, 0); } cnt += vSize; } @@ -317,7 +317,7 @@ select server\n\ if (fseek(fp, cnt, SEEK_SET)) { fclose(fp); - ExitWithError(oraAllInOne, 4, ERROR_OS, "Error setting reading position in a local file\n"); + ExitWithError(oraAllInOne, RET_FS, ERROR_OS, "Error setting reading position in a local file\n"); } } @@ -327,18 +327,18 @@ select server\n\ { if (!isStdUsed) fclose(fp); - ExitWithError(oraAllInOne, -1, ERROR_OS, "Error reading from a local file\n"); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OS, "Error reading from a local file\n"); if (!isKeepPartial) { PrepareStmtAndBind(oraAllInOne, &oraStmtClose); if (ExecuteStmt(oraAllInOne)) { - ExitWithError(oraAllInOne, -1, ERROR_OCI, "Error closing an Oracle remote file\n"); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Error closing an Oracle remote file\n"); } ReleaseStmt(oraAllInOne); Rm(oraAllInOne, pDirectory, pRemoteFile); } - ExitWithError(oraAllInOne, 4, ERROR_NONE, 0); + ExitWithError(oraAllInOne, RET_FS, ERROR_NONE, 0); } if (OCIBindByName(oraAllInOne->currentStmt[0]->stmthp, &ociBind, oraAllInOne->errhp, @@ -347,18 +347,18 @@ select server\n\ { if (!isStdUsed) fclose(fp); - ExitWithError(oraAllInOne, -1, ERROR_OCI, "Failed to bind :buffer\n"); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Failed to bind :buffer\n"); if (!isKeepPartial) { PrepareStmtAndBind(oraAllInOne, &oraStmtClose); if (ExecuteStmt(oraAllInOne)) { - ExitWithError(oraAllInOne, -1, ERROR_OCI, "Error closing an Oracle remote file\n"); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Error closing an Oracle remote file\n"); } ReleaseStmt(oraAllInOne); Rm(oraAllInOne, pDirectory, pRemoteFile); } - ExitWithError(oraAllInOne, 4, ERROR_NONE, 0); + ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_NONE, 0); } if (ExecuteStmt(oraAllInOne)) @@ -366,19 +366,19 @@ select server\n\ if (!isStdUsed) fclose(fp); OCIHandleFree(ociBind, OCI_HTYPE_BIND); - ExitWithError(oraAllInOne, -1, ERROR_OCI, "Failed execution of %s\n", + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Failed execution of %s\n", oraAllInOne->currentStmt[0]->sql); if (!isKeepPartial) { PrepareStmtAndBind(oraAllInOne, &oraStmtClose); if (ExecuteStmt(oraAllInOne)) { - ExitWithError(oraAllInOne, -1, ERROR_OCI, "Error closing an Oracle remote file\n"); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Error closing an Oracle remote file\n"); } ReleaseStmt(oraAllInOne); Rm(oraAllInOne, pDirectory, pRemoteFile); } - ExitWithError(oraAllInOne, 4, ERROR_NONE, 0); + ExitWithError(oraAllInOne, RET_ORA, ERROR_NONE, 0); } OCIHandleFree(ociBind, OCI_HTYPE_BIND); cnt += vActualSize; @@ -396,7 +396,7 @@ select server\n\ PrepareStmtAndBind(oraAllInOne, &oraStmtClose); if (ExecuteStmt(oraAllInOne)) { - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Error closing an Oracle remote file\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Error closing an Oracle remote file\n"); } ReleaseStmt(oraAllInOne); SetSessionAction(oraAllInOne, 0); diff --git a/src/transfercompr.c b/src/transfercompr.c index d121858..1d5d79c 100644 --- a/src/transfercompr.c +++ b/src/transfercompr.c @@ -85,7 +85,7 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire SetSessionAction(oraAllInOne, "GZIP_AND_DOWNLOAD: GZIP"); if (OCIDescriptorAlloc(oraAllInOne->envhp, (void**)&oraAllInOne->blob, OCI_DTYPE_LOB, 0, 0)) { - ExitWithError(oraAllInOne, 4, ERROR_NONE, "Failed to allocate BLOB\n"); + ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_NONE, "Failed to allocate BLOB\n"); } cnt = 0; @@ -115,13 +115,13 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire #endif if (ociResult) - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to compress file in oracle directory\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to compress file in oracle directory\n"); #ifndef _WIN32 if (showProgress) { if (OCILobGetLength2(oraAllInOne->svchp[0], oraAllInOne->errhp, oraAllInOne->blob, (oraub8*)&sourceSize)) - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Error getting BLOB length\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Error getting BLOB length\n"); strcpy(progressLine, "TRANSFER & GUNZIP: "); strncat(progressLine, basename(pLocalFile), MAX_FMT_SIZE - 1 - strlen(progressLine)); start_progress_meter(progressLine, sourceSize, &cnt); @@ -131,7 +131,7 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire SetSessionAction(oraAllInOne, "GZIP_AND_DOWNLOAD: DOWNLOAD"); if (!isStdUsed && (fp = fopen(pLocalFile, isResume ? "ab" : "wb")) == NULL) { - ExitWithError(oraAllInOne, 4, ERROR_OS, "Error opening a local file for writing\n"); + ExitWithError(oraAllInOne, RET_FS, ERROR_OS, "Error opening a local file for writing\n"); } if (isStdUsed) fp = stdout; @@ -146,7 +146,7 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire { if (!isStdUsed) fclose(fp); - ExitWithError(oraAllInOne, 5, ERROR_NONE, "ZLIB initialization failed\n"); + ExitWithError(oraAllInOne, RET_ZLIB, ERROR_NONE, "ZLIB initialization failed\n"); } vSize = 0; @@ -170,7 +170,7 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire (void)inflateEnd(&zStrm); if (!isStdUsed) fclose(fp); - ExitWithError(oraAllInOne, 5, ERROR_NONE, "ZLIB inflate failed: %d, size %d\n", zRet, vSize); + ExitWithError(oraAllInOne, RET_ZLIB, ERROR_NONE, "ZLIB inflate failed: %d, size %d\n", zRet, vSize); } fwrite(zOut, sizeof(unsigned char), ORA_BLOB_BUFFER_SIZE - zStrm.avail_out, fp); @@ -179,13 +179,13 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire (void)inflateEnd(&zStrm); if (!isStdUsed) fclose(fp); - ExitWithError(oraAllInOne, -1, ERROR_OS, "Error writing to a local file\n"); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OS, "Error writing to a local file\n"); if (!isKeepPartial) { if (unlink(pLocalFile)) - ExitWithError(oraAllInOne, 4, ERROR_OS, "Could not remove partial file %s\n", pLocalFile); + ExitWithError(oraAllInOne, RET_FS, ERROR_OS, "Could not remove partial file %s\n", pLocalFile); } - ExitWithError(oraAllInOne, 4, ERROR_NONE, 0); + ExitWithError(oraAllInOne, RET_FS, ERROR_NONE, 0); } } while (zStrm.avail_out == 0); @@ -205,7 +205,7 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire if (ociResult != OCI_SUCCESS) { - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Error reading BLOB\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Error reading BLOB\n"); } ReleaseStmt(oraAllInOne); @@ -215,7 +215,7 @@ void DownloadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDire if (OCIDescriptorFree(oraAllInOne->blob, OCI_DTYPE_LOB)) { - ExitWithError(oraAllInOne, 4, ERROR_NONE, "Failed to free BLOB\n"); + ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_NONE, "Failed to free BLOB\n"); } oraAllInOne->blob = 0; } @@ -268,17 +268,14 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect SetSessionAction(oraAllInOne, "UPLOAD_AND_GUNZIP: UPLOAD"); if (OCIDescriptorAlloc(oraAllInOne->envhp, (void**)&oraAllInOne->blob, OCI_DTYPE_LOB, 0, 0)) { - ExitWithError(oraAllInOne, 4, ERROR_NONE, "Failed to allocate BLOB\n"); + ExitWithError(oraAllInOne, RET_OCIINIT, ERROR_NONE, "Failed to allocate BLOB\n"); } if (OCILobCreateTemporary(oraAllInOne->svchp[0], oraAllInOne->errhp, oraAllInOne->blob, OCI_DEFAULT, 0, OCI_TEMP_BLOB, TRUE/*cache*/, OCI_DURATION_SESSION)) { - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to create temporary BLOB\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to create temporary BLOB\n"); } - /*if (OCILobOpen(oraAllInOne->svchp[0], oraAllInOne->errhp, oraAllInOne->blob, OCI_LOB_READWRITE)) - { - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to open temporary BLOB for write\n"); - }*/ + piece = OCI_FIRST_PIECE; #ifndef _WIN32 @@ -310,7 +307,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect if (!isStdUsed && (fp = fopen(pLocalFile, "rb")) == NULL) { - ExitWithError(oraAllInOne, 4, ERROR_OS, "Error opening a local file for reading\n"); + ExitWithError(oraAllInOne, RET_FS, ERROR_OS, "Error opening a local file for reading\n"); } if (isStdUsed) fp = stdin; @@ -320,7 +317,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect if (fseek(fp, cnt, SEEK_SET)) { fclose(fp); - ExitWithError(oraAllInOne, 4, ERROR_OS, "Error setting reading position in a local file\n"); + ExitWithError(oraAllInOne, RET_FS, ERROR_OS, "Error setting reading position in a local file\n"); } } @@ -333,7 +330,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect { if (!isStdUsed) fclose(fp); - ExitWithError(oraAllInOne, 5, ERROR_NONE, "ZLIB initialization failed\n"); + ExitWithError(oraAllInOne, RET_ZLIB, ERROR_NONE, "ZLIB initialization failed\n"); } while (!feof(fp)) @@ -345,7 +342,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect (void)deflateEnd(&zStrm); if (!isStdUsed) fclose(fp); - ExitWithError(oraAllInOne, 4, ERROR_OS, "Error reading from a local file\n"); + ExitWithError(oraAllInOne, RET_FS, ERROR_OS, "Error reading from a local file\n"); } zFlush = feof(fp) ? Z_FINISH : Z_NO_FLUSH; @@ -361,7 +358,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect (void)deflateEnd(&zStrm); if (!isStdUsed) fclose(fp); - ExitWithError(oraAllInOne, 5, ERROR_NONE, "ZLIB deflate failed: %d, size %d\n", zRet, zStrm.avail_in); + ExitWithError(oraAllInOne, RET_ZLIB, ERROR_NONE, "ZLIB deflate failed: %d, size %d\n", zRet, zStrm.avail_in); } if (zRet == Z_STREAM_END) @@ -376,7 +373,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect (void)deflateEnd(&zStrm); if (!isStdUsed) fclose(fp); - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Error writing to BLOB\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Error writing to BLOB\n"); } if (piece == OCI_FIRST_PIECE) piece = OCI_NEXT_PIECE; @@ -392,16 +389,6 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect if (!isStdUsed) fclose(fp); - /*vSize = 0; - if (OCILobWrite2(oraAllInOne->svchp[0], oraAllInOne->errhp, oraAllInOne->blob, &vSize, 0, 1, blobBuffer, 0, OCI_LAST_PIECE, 0, 0, 0, 0)) - { - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Error writing last piece to BLOB\n"); - } - if (OCILobClose(oraAllInOne->svchp[0], oraAllInOne->errhp, oraAllInOne->blob)) - { - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to close temporary BLOB\n"); - }*/ - isError = 0; strcpy(vOpenMode, isResume ? "ab" : "wb"); SetSessionAction(oraAllInOne, "UPLOAD_AND_GUNZIP: GUNZIP"); @@ -419,7 +406,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect #endif if (ociResult) { - ExitWithError(oraAllInOne, -1, ERROR_OCI, "Failed to decompress file in oracle directory\n"); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_OCI, "Failed to decompress file in oracle directory\n"); isError = 1; } else @@ -431,7 +418,7 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect if (OCIDescriptorFree(oraAllInOne->blob, OCI_DTYPE_LOB)) { if (!isError) - ExitWithError(oraAllInOne, -1, ERROR_NONE, "Failed to free BLOB\n"); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_NONE, "Failed to free BLOB\n"); isError = 1; } oraAllInOne->blob = 0; @@ -440,6 +427,6 @@ void UploadFileWithCompression(struct ORACLEALLINONE *oraAllInOne, char* pDirect { if (!isKeepPartial) Rm(oraAllInOne, pDirectory, pRemoteFile); - ExitWithError(oraAllInOne, 4, ERROR_NONE, 0); + ExitWithError(oraAllInOne, RET_ORA, ERROR_NONE, 0); } } diff --git a/src/trydir.c b/src/trydir.c index b51b253..19b87ec 100644 --- a/src/trydir.c +++ b/src/trydir.c @@ -53,7 +53,7 @@ SELECT MIN(DECODE(directory_name, :directory, 1, 2))\n\ PrepareStmtAndBind(oraAllInOne, &oraStmtTryDirectory); if (ExecuteStmt(oraAllInOne)) - ExitWithError(oraAllInOne, 4, ERROR_OCI, "Failed to get an Oracle Directory\n"); + ExitWithError(oraAllInOne, RET_ORA, ERROR_OCI, "Failed to get an Oracle Directory\n"); ReleaseStmt(oraAllInOne); @@ -62,11 +62,11 @@ SELECT MIN(DECODE(directory_name, :directory, 1, 2))\n\ case 1: break; case 2: - ExitWithError(oraAllInOne, -1, ERROR_NONE, "WARNING: directory \"%s\" not found, converting to uppercase\n", pDirectory); + ExitWithError(oraAllInOne, RET_DONOTEXIT, ERROR_NONE, "WARNING: directory \"%s\" not found, converting to uppercase\n", pDirectory); for (ptr = pDirectory; *ptr; ptr++) *ptr = toupper(*ptr); break; default: - ExitWithError(oraAllInOne, 4, ERROR_NONE, "Directory \"%s\" does not exist\n", pDirectory); + ExitWithError(oraAllInOne, RET_ORA, ERROR_NONE, "Directory \"%s\" does not exist\n", pDirectory); } } diff --git a/updateforeigns.sh b/updateforeigns.sh index 82c3dcd..9e683fa 100755 --- a/updateforeigns.sh +++ b/updateforeigns.sh @@ -40,7 +40,7 @@ done download "http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/lib/libc/string/strlcat.c" \ progressmeter/strlcat.c.orig download "http://git.savannah.gnu.org/gitweb/?p=autoconf-archive.git;a=blob_plain;f=m4/ax_lib_oracle_oci.m4" \ - m4/ax_lib_oracle_oci.m4.orig + m4/ax_lib_oracle_oci.m4 download "http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/yesno.h;hb=HEAD" \ yesno/yesno.h download "http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/yesno.c;hb=HEAD" \ @@ -59,7 +59,7 @@ done # 2.2. Medium case, sources need a slight patch for file in progressmeter/progressmeter.c progressmeter/atomicio.c progressmeter/strlcat.c \ - m4/ax_lib_oracle_oci.m4 src/Globs.java; do + src/Globs.java; do patch --backup-if-mismatch -u -o ${file} ${file}.orig ${file}.patch done @@ -81,13 +81,13 @@ cat << EOF EOF -grep -Ezo '(\w+)(\s*)monotime_double([^)]*)\)' progressmeter/misc.c.orig +grep -Ezo '(\w+)(\s*)monotime_double([^)]*)\)' progressmeter/misc.c.orig | sed 's/\x00/\n/' cat << EOF ; /* taken from the original OpenSSH misc.h/misc.c */ EOF -grep -Ezo '(\w+)(\s*)strlcat([^)]*)\)' progressmeter/strlcat.c.orig +grep -Ezo '(\w+)(\s*)strlcat([^)]*)\)' progressmeter/strlcat.c.orig | sed 's/\x00/\n/' cat << EOF ; /* declaration for strlcat.c */ @@ -112,10 +112,15 @@ cat << EOF #include EOF -grep -Ezo '(\w+)(\s*)monotime_double([^}]*)}' ${filename} | sed \ + +grep -Ezo '(\w+)(\s*)monotime_ts([^}]*)}' ${filename} | sed \ -e 's/if (/\/*if (*\//' \ -e 's/ != 0)/\/* != 0)/' \ - -e 's/strerror(errno))/strerror(errno))*\//' + -e 's/strerror(errno))/strerror(errno))*\//' \ + -e 's/\x00/\n\n/' + +grep -Ezo '(\w+)(\s*)monotime_double([^}]*)}' ${filename} | sed \ + -e 's/\x00/\n/' ) > progressmeter/misc.c # 3. Remove intermediate files @@ -126,6 +131,5 @@ rm progressmeter/progressmeter.h.orig \ progressmeter/atomicio.c.orig \ progressmeter/misc.c.orig \ progressmeter/strlcat.c.orig \ - m4/ax_lib_oracle_oci.m4.orig \ src/Globs.java.orig diff --git a/win/README.md b/win/README.md index 1f00c98..b47c373 100644 --- a/win/README.md +++ b/win/README.md @@ -8,12 +8,12 @@ Here are dependencies required to run pre-compiled `ocp.exe` ### Oracle Client -Download and unpack Oracle **Instant Client Package - Basic Lite** for Microsoft Windows (32-bit) version 12.1.0.2.0 from http://www.oracle.com/technetwork/topics/winsoft-085727.html -`instantclient-basiclite-nt-12.1.0.2.0.zip` (33,851,306 bytes) +Download and unpack Oracle **Basic Light Package** for Microsoft Windows (32-bit) version 18.3.0.0.0 from http://www.oracle.com/technetwork/topics/winsoft-085727.html +`instantclient-basiclite-nt-18.3.0.0.0dbru.zip` (3,544,0728 bytes) Full Oracle Client (or Server) installations will also work. Use 32-bit installations only. -As usual, make sure Oracle Instant Client directory is in `PATH` environment variable. If using full installation, then `%ORACLE_HOME%\bin` should be in `PATH`. +As usual, make sure Oracle Instant Client directory is in `PATH` environment variable. If using full Oracle Client installation, then `%ORACLE_HOME%\bin` should be in `PATH`. ### GnuWin32 Libraries @@ -25,22 +25,22 @@ Download and unpack archives, and put files to a directory with `ocp.exe` or to | http://gnuwin32.sourceforge.net/downlinks/popt-dep-zip.php | popt-1.8-1-dep.zip | bin\libintl-2.dll, bin\libiconv-2.dll | | http://gnuwin32.sourceforge.net/downlinks/zlib-bin-zip.php | zlib-1.2.3-bin.zip | bin\zlib1.dll | -### Microsoft Visual C++ 2010 SP1 Redistributable Package (x86) +### Visual C++ Redistributable Packages for Visual Studio 2013 (x86) -Download and install `vcredist_x86.exe` from https://www.microsoft.com/en-us/download/details.aspx?id=8328 +Download and install `vcredist_x86.exe` from https://www.microsoft.com/en-us/download/details.aspx?id=40784 Build ----- -Here are dependencies required to compile `ocp.exe` from source. Please follow instructions in **Runtime** section above (except **Microsoft Visual C++ 2010 SP1 Redistributable Package (x86)**, that one is automatically supplied by **Microsoft Visual C++ 2010 Express SP1** installation), then proceed with the steps below. +Here are dependencies required to compile `ocp.exe` from source. Please follow instructions in **Runtime** section above (except **Visual C++ Redistributable Packages for Visual Studio 2013 (x86)**, that one is automatically supplied by **Visual Studio Community 2013** installation), then proceed with the steps below. -A version 2010 of Visual C++ (MSVC) was chosen because Oracle Instant Client 12.1.0.2.0 already has **Microsoft Visual C++ 2010 SP1 Redistributable Package (x86)** as its runtime dependency (it requires `MSVCR100.dll` file). +A version 2013 of Visual C++ (MSVC) was chosen because Oracle Instant Client 18.3.0.0.0 already has **Visual C++ Redistributable Packages for Visual Studio 2013 (x86)** as its runtime dependency (it requires `MSVCR120.dll` file). Thus, compiling `ocp` with the same MSVC version as Oracle used for their Instant Client will avoid dependencies on more than one version of `MSVCR*.dll`. ### Oracle Client -If using Instant Client, download and unpack to the same directory Oracle **Instant Client Package - SDK** for Microsoft Windows (32-bit) version 12.1.0.2.0 from http://www.oracle.com/technetwork/topics/winsoft-085727.html -`instantclient-sdk-nt-12.1.0.2.0.zip` (1,951,770 bytes) +If using Instant Client, download and unpack to the same directory Oracle **SDK Package** for Microsoft Windows (32-bit) version 18.3.0.0.0 from http://www.oracle.com/technetwork/topics/winsoft-085727.html +`instantclient-sdk-nt-18.3.0.0.0dbru.zip` (1,499,306 bytes) ### GnuWin32 Libraries @@ -51,15 +51,14 @@ Download and unpack archives to `win` subdirectory of ocp source tree: | http://gnuwin32.sourceforge.net/downlinks/popt-lib-zip.php | popt-1.8-1-lib.zip | | http://gnuwin32.sourceforge.net/downlinks/zlib-lib-zip.php | zlib-1.2.3-lib.zip | -### Microsoft Visual C++ 2010 Express SP1 +### Visual Studio Community 2013 - 1. Download and install **Microsoft Visual C++ 2010 Express**, - deselect any options during installation, as they are unnecessary. - 2. Download and install **Microsoft Visual Studio 2010 Service Pack 1** +Download and install **Visual Studio Community 2013**, +deselect any options during installation, as they are unnecessary. ### Run Compilation -Run **Visual Studio Command Prompt (2010)** +Run **VS2013 x86 Native Tools Command Prompt** Then review `win\build.cmd`, edit if necessary, and execute: ``` diff --git a/win/build.cmd b/win/build.cmd index 07d64db..3865e37 100644 --- a/win/build.cmd +++ b/win/build.cmd @@ -3,7 +3,7 @@ rem rem 1. Review and edit include\config.h (update version information) if necessary rem 2. Adjust the two variables (%INSTANT_CLIENT% and %OCP_ROOT%) if necessary -set INSTANT_CLIENT=c:\instantclient_12_1 +set INSTANT_CLIENT=c:\instantclient_18_3 set OCP_ROOT=.. set ICINCHOME=%INSTANT_CLIENT%\sdk\include diff --git a/win/include/config.h b/win/include/config.h index c0ff84e..0e10191 100644 --- a/win/include/config.h +++ b/win/include/config.h @@ -19,7 +19,7 @@ #undef PACKAGE_TARNAME /* Define to the version of this package. */ -#define PACKAGE_VERSION "0.2" +#define PACKAGE_VERSION "0.3" /* Version number of package */ -#define VERSION "0.2" +#define VERSION "0.3" diff --git a/yesno/yesno.c b/yesno/yesno.c index 12168b2..0a58727 100644 --- a/yesno/yesno.c +++ b/yesno/yesno.c @@ -1,6 +1,6 @@ /* yesno.c -- read a yes/no response from stdin - Copyright (C) 1990, 1998, 2001, 2003-2017 Free Software Foundation, Inc. + Copyright (C) 1990, 1998, 2001, 2003-2019 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -13,7 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program. If not, see . */ #include diff --git a/yesno/yesno.h b/yesno/yesno.h index be127b0..0c1b259 100644 --- a/yesno/yesno.h +++ b/yesno/yesno.h @@ -1,5 +1,5 @@ /* declare yesno - Copyright (C) 2004, 2009-2017 Free Software Foundation, Inc. + Copyright (C) 2004, 2009-2019 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12,7 +12,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program. If not, see . */ #ifndef YESNO_H_ # define YESNO_H_