We are running a ksh script that calls a ProC program that updates a table.
The program runs successfully in UNIX but when we run it in LINUX RHEL55 , it is causing a memory fault error
When we tried to debug where the last statement before the Memory fault error, it points to the point after we do a Fetch on the cursor and tries to use the values fetched to update a table
Here is a snippet of the code
#define PROGRAM "n377wlocgeo" /* name of this program */
#define USERNAME "/" /* ORACLE username */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
/* Include the ORACLE communication Area, a structure through which
ORACLE makes additional runtime Status available to the program
The ORACA=YES must be specified to enable use of oraca */
EXEC SQL INCLUDE ORACA;
EXEC ORACLE OPTION (ORACA=YES);
EXEC SQL INCLUDE SQLCA;
/*---------------------------------------------------------------------------
WORKING STORAGE */
/* GLOBAL EXTERNAL VARIABLES */
char *ptr; /* pointer for record layout */
char timestamp[26] = "\0"; /* current date and time */
/* Counters */
int rec_err_ctr = 0;
int cnt_rec = 0;
long update_no_ctr = 0;
long update_geo_ctr = 0;
long update_no_pr_ctr = 0;
long update_no_us_ctr = 0;
int no_fetch_rec_ctr = 0;
int geo_fetch_rec_ctr = 0;
int commit_ctr = 0;
int ws_err_sqlcode;
char para_name[25]; /* hold for displaying what paragraph abended */
char err_para_name[25]; /* hold for displaying what paragraph abended */
char abend_msg[240];
/*Pgm Control Vars */
char error_in_job = 'N';
char no_fetch_ended = 'N';
char geo_fetch_ended = 'N';
char clear_psl_cd[12];
/* UNIX ENVIRONMENT VARIABLES */
char debug[2];
/* Function delarations */
void initpara(); /* connect to Oracle */
void get_env_vars(); /* get the unix environment variables into C program */
void get_timestamp(); /* get the date and time from the system */
void connect_oracle();
void disconnect_oracle();
void get_update_timestamp();
void end_transaction();
void error_routine();
void echofields(); /* for debugging, echo all fields parsed */
void no_geo_cursor_process();
void geo_cursor_process();
void sql_no_update();
void sql_geo_update();
void sql_no_pr_update();
void sql_no_us_update();
EXEC SQL BEGIN DECLARE SECTION;
varchar hv_psl_cd[12];
varchar hv_rec_udt_ts[20];
varchar hv_geo_cny_cd[03];
varchar hv_geo_psl_cd[12];
varchar hv_geo_typ_cd[4];
varchar hv_cny_cd[03];
/* Cursor to set defaults for countries with no geo classification */
EXEC SQL DECLARE NO_GEO_CUR CURSOR FOR
SELECT CNY_CD
,PSL_CD
FROM TDLOCTN_BASE
WHERE CNY_CD NOT IN ('US', 'PR')
AND GEO_ARA_PSL_CSF_CD is null
GROUP BY CNY_CD, PSL_CD
ORDER BY CNY_CD, PSL_CD;
EXEC SQL DECLARE GEO_CUR CURSOR FOR
SELECT GEO_CNY_CD,
GEO_PSL_CD,
GEO_TYP_CD
FROM TDLOC_GEO_CD_EXT
GROUP BY GEO_CNY_CD,GEO_PSL_CD,GEO_TYP_CD
ORDER BY GEO_CNY_CD,GEO_PSL_CD;
EXEC SQL END DECLARE SECTION;
/*----------------------------------------------------------
PROCEDURE DIVISION
------------------------------------------------------------
MAINLINE */
/*------------------------------------------------------------*/
int main(int argc, char **argv)
{
printf ("Starting");
get_timestamp();
printf("PGM BEGIN DATE/TIME : %s \n", timestamp );
initpara();
if ( strcmp(debug, "Y") == 0 )
get_timestamp();
printf("main while loop: %s\n", timestamp);
/* get max rec_udt_tms for cursor process */
get_update_timestamp();
/* open the cursor and fetch all rows for defaults . */
no_geo_cursor_process();
if ( error_in_job == 'Y' )
exit(2);
else
exit(0);
}
/*------------------------------------------------------------*/
void get_timestamp()
{
strcpy(para_name, "Para = get_timestamp");
if ( strcmp(debug, "Y") == 0 )
printf("function: get_timestamp\n");
struct tm *tm_now;
time_t secs_now;
/no_geo_cursor
EXEC SQL
SELECT TRUNC(MAX(REC_UDT_TS))
INTO :hv_rec_udt_ts
FROM TDLOCTN_BASE;
if ( sqlca.sqlcode == 0 )
printf("CHAR %-25s : %s \n", "hv_rec_udt_ts", hv_rec_udt_ts.arr);
else
{
printf("SQL Select Error in - get_update_timestamp: %s\n");
strcpy(abend_msg, sqlca.sqlerrm.sqlerrmc);
printf("SQL ERROR CODE: %d\n", sqlca.sqlcode);
printf("SQL ERROR MSG: %s\n", abend_msg);
error_routine();
}
}
void no_geo_cursor_process ()
{
strcpy(para_name, "Para = no_geo_cursor_process");
if ( strcmp(debug, "Y") == 0 )
printf("function: no_geo_cursor_process\n");
EXEC SQL
OPEN NO_GEO_CUR;
if ( sqlca.sqlcode == 0 )
printf("Cursor Opened: %s\n");
else
{
printf("SQL Open Error in - no_geo_cursor_process: %s\n");
strcpy(abend_msg, sqlca.sqlerrm.sqlerrmc);
printf("SQL ERROR CODE: %d\n", sqlca.sqlcode);
printf("SQL ERROR MSG: %s\n", abend_msg);
error_routine();
}
char para_name[25];
strcpy(para_name, "Para = no_geo_cursor_process");
// 1 2
// 12345678901234567890123456789 (one extra for the NULL).
That's one thing that's probably not going to work. It's undefined behaviour if you write past the end of an array (you cant put twenty-nine biscuits into a biscuit tin built for twenty-five (a))
Increase the size of para_name to fix that problem.
The reason it may work on some systems is that one of the possible outcomes of undefined behaviour is that it just works. That doesn't make it a good idea, of course. You should avoid it as much as possible.
In addition, as pointed out in the comments, you have a few lines where you provide printf format strings with no corresponding values:
printf("SQL Select Error in - get_update_timestamp: %s\n");
printf("Cursor Opened: %s\n");
This is also undefined behaviour and will likely cause problems, usually by using whatever values happens to have been placed on the stack as a string pointer. You can just remove the offending %s from the string or, alternatively, figure out what string you wanted to include in the message and add that to the printf arguments.
(a) Unless you want biscuit crumble, of course :-)
Related
How to get some locale-specific information where the country can be detected? E.g. current country code, keyboard layout or code page in Turbo C in DOS environment?
If that is not possible with Turbo C library functions, some BIOS calls could do that (INT 21)?.
KEYB program is able to show e.g. keyboard layout. That would be more than enough for my purposes:
https://www.dosbox.com/wiki/KEYB
Use INT 21h, AX=6501h. Here's code for Turbo C:
#include <dos.h>
#include <stdio.h>
struct country_info_buffer
{
unsigned char info_id;
unsigned short buffer_size;
unsigned short country_id;
unsigned short code_page;
struct COUNTRY country_info;
};
int main()
{
/* Registers for INT21 call */
union REGS regs;
struct SREGS sregs;
/* Output buffer */
struct country_info_buffer info;
/* Get current value of segment registers */
segread(&sregs);
/* Get extended country information / general internationalization info */
regs.x.ax = 0x6501;
/* Global code page */
regs.x.bx = 0xFFFF;
/* Current country */
regs.x.dx = 0xFFFF;
/* Size of output buffer */
regs.x.cx = sizeof(info);
/* Pointer to output buffer goes to ES:DI */
sregs.es = FP_SEG(&info);
regs.x.di = FP_OFF(&info);
/* Call int21 */
intdosx(®s, ®s, &sregs);
if (regs.x.cflag)
{
printf("Call failed, ax=%d\n", regs.x.ax);
return 1;
}
printf("Country code: %d, Code page: %d\n", info.country_id, info.code_page);
return 0;
}
Btw. Ralf Brown's Interrupt List is great resource for DOS system calls. Too bad it stopped being maintained even before DOS ran out of favors, so some "newest" stuff isn't described there.
I'm actually working lkm on linux 2.6.32, and I don't to understand one thing. I'm trying to change the original read_proc and write_proc of /proc/version with my functions. Thus I can to change the original value of read_proc and write_proc, with values of my function. I can see it, because values of read_proc and write_proc change to NULL to adress of my functions, but that have no effect... And I don't understand why. I don't arrive to find if version is protected (I tried to change the value of file's right with chmod), or why even after change the value, I can't write in /proc/version with echo XXXX > /proc/version. I'll be grateful for your help.
Code where I try to change values of read_proc and write_proc:
static void Proc_init()
{
int find = 0;
pde = create_proc_entry("test", 0444, NULL); //that permit to create new file in /proc, only to get some useful values
ptdir = pde->parent; //affect to ptdir the value of the pointer on /proc
if(strcmp(ptdir->name, "/proc")!=0)
{
Erreur=1;
}
else
{
root = ptdir;
remove_proc_entry("test", NULL);
ptr_subdir=root->subdir;
while(find==0)
{
printk("%s \n", ptr_subdir->name);
if(strcmp("version", ptr_subdir->name)==0)
find=1;
else
ptr_subdir=ptr_subdir->next;
}
//Save original write et read proc
old_read_proc=ptr_subdir->read_proc;
old_write_proc=ptr_subdir->write_proc;
// Before I have null values for prt_subdir->read_proc and ptr_subdir->write_proc
ptr_subdir->read_proc=&new_read_proc_t;
ptr_subdir->write_proc=&new_write_proc_t;
// after that, values of prt_subdir->read_proc and ptr_subdir- >write_proc are egual to values of &new_write_proc_t and &new_read_proc_t
}
}
static int new_read_proc_t (char *page, char **start, off_t off,int count, int *eof, void *data)
{
int len;
/* For example - when content of our_buf is "hello" - when user executes command "cat /proc/test_proc"
he will see content of our_buf(in our example "hello" */
len = snprintf(page, count, "%s", our_buf);
return len;
}
static int new_write_proc_t(struct file *file, const char __user *buf,unsigned long count, void *data)
{
/* If count is bigger than 255, data which user wants to write is too big to fit in our_buf. We don't want
any buffer overflows, so we read only 255 bytes */
if(count > 255)
count = 255;
/* Here we read from buf to our_buf */
copy_from_user(our_buf, buf, count);
/* we write NULL to end the string */
our_buf[count] = '\0';
return count;
}
Working in z/os mainframe, I have the following situation. I can't record a transaction.
here is my code,
it is written for transaction using jcl. Bur something goes wrong.
/* Include standard C header files */
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Include WebSphere MQ API header file */
#include <cmqc.h>
/* Boolean constants */
#define TRUE 1
#define FALSE 0
/* Function prototypes */
void displayUsage (char *programName);
void displayMQError (char *message, MQLONG compCode, MQLONG reason);
double parseAmount (char *amountString);
/* Main Program */
int main (int argc, char *argv[])
{
/* Variable definitions */
double paymentAmount; /* Payment amount */
MQBYTE msgBuffer[1024]; /* Buffer for messages */
MQCHAR* qmgrName; /* Queue manager name */
MQCHAR* requestQueueName; /* Request queue name */
MQCHAR* replyQueueName; /* Reply queue name */
MQCHAR* userID; /* Contestant user ID */
MQCHAR* paymentDescription; /* Payment description */
MQGMO getMsgOptions = {MQGMO_DEFAULT}; /* Get options */
MQHCONN hConn = MQHC_UNUSABLE_HCONN; /* Connection handle */
MQHOBJ requestHObj = MQHO_UNUSABLE_HOBJ; /* Request queue handle */
MQHOBJ replyHObj = MQHO_UNUSABLE_HOBJ; /* Reply queue handle */
MQLONG compCode; /* API completion code */
MQLONG openOptions; /* Open queue options */
MQLONG reason; /* API reason code */
MQLONG replyMsgLength = 0; /* Reply msg length */
MQMD requestMsgDesc = {MQMD_DEFAULT}; /* Message descriptor */
MQMD replyMsgDesc = {MQMD_DEFAULT}; /* Message descriptor */
MQOD requestQueueDesc = {MQOD_DEFAULT}; /* Object descriptor */
MQOD replyQueueDesc = {MQOD_DEFAULT}; /* Object descriptor */
MQPMO putMsgOptions = {MQPMO_DEFAULT}; /* Put options */
/*****************************************/
/* Initialisation and parameter checking */
/*****************************************/
printf ("********************************************************\n");
printf ("Credit card payment unit test tool\n");
printf ("********************************************************\n");
printf (" \n");
switch (argc)
{
case 7 : qmgrName = argv[1];
requestQueueName = argv[2];
replyQueueName = argv[3];
userID = argv[4];
paymentAmount = parseAmount (argv[5]);
if ( ( paymentAmount < 0.01 )
|| ( paymentAmount > 9999.99 ) )
{
printf ("The payment amount must be a valid numeric " \
"within the range 0.01 to 9999.99\n");
displayUsage (argv[0]);
return (1);
}
paymentDescription = argv[6];
if ( ( strlen (paymentDescription) < 1 )
|| ( strlen (paymentDescription) > 35 ) )
{
printf ("The payment description must be 1-35 " \
"characters\n");
displayUsage (argv[0]);
return (1);
}
break;
default : printf ("Incorrect usage!\n");
displayUsage (argv[0]);
return (1);
}
printf ("You have requested a payment of %.2f with description " \
"'%s' for contestant %s\n", paymentAmount,
paymentDescription, userID);
printf (" \n");
Can you help me?
I don't know how to write my Parm parameters...
When you have a problem, try to track all the outputs back to the inputs via the program.
From one of your other questions:
********************************************************
Credit card payment unit test tool
********************************************************
Incorrect usage!
Program Usage
-------------
PAYMENT <queue manager> <cics request queue> <reply queue> <userid> <payment value> <payment description>
The payment description has a maximum length of 35 characters.
The monetary value must be within the range 0.01 - 9999.99
The first two lines are easy to explain. The last two lines, not so. They are there to blinker us, as that exact text appears in the program. However, it seems that the exact same text is used in the displayUsage function.
It is bad to display identical text in different error circumstances. That's why we use message numbers - the message may then be the same, but the number will identify exactly where it has come from.
A clue is that you can't even get a very simple PARM to be accepted.
A further clue is that Incorrect usage!.
When does that message get printed? When there are other than seven parameters. Err... but you only supply six.
So, if there are supposed to be six parameters, the program is wrong. If you should be supplying seven parameters, your PARM is wrong.
You can demonstrate this with
// PARM='A,B,C,D,1,F,G'
That will work.
As an aside, why was switch used instead of a simple if anyway? Using if would have made the problem more obvious.
I was trying to use copy_to_user in kernel module read function, but am not able to copy the data from kernel to user buffer. Please can anyone tell me if I am doing some mistake. My kernel version is 2.6.35. I am giving the portion of kernel module as well as the application being used to test it. Right now my focus is why this copy_to_user is not working. Any help will great.
///////////////////////////////////kernel module//////////////////////////////////////
#define BUF_LEN 80
static char msg[BUF_LEN];
static char *msg_Ptr;
static int device_open(struct inode *inode, struct file *file)
{
static int counter = 0;
if (Device_Open)
return -EBUSY;
Device_Open++;
printk(KERN_ALERT "In open device call\n");
sprintf(msg, "I already told you %d times Hello world!\n", counter++);
msg_Ptr = msg;
try_module_get(THIS_MODULE);
return SUCCESS;
}
static ssize_t device_read(struct file *filp,
char __user *buffer,
size_t length,
loff_t * offset)
{
/*
* Number of bytes actually written to the buffer
*/
int bytes_read = 0;
/*
* If we are at the end of the message,
* return 0 signifying end of file
*/
if (*msg_Ptr == 0)
return 0;
/*
* Actually put the data into the buffer
*/
else {
bytes_read=copy_to_user(buffer, msg, length);
if (bytes_read==-1);
{
printk(KERN_INFO "Error in else while copying the data \n");
}
}
return bytes_read;
}
////////////////////////////////////////application////////////////////////
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#define BUF_SIZE 40
int main()
{
ssize_t num_bytes;
int fd, n=0;
char buf[BUF_SIZE];
fd=open("/dev/chardev", O_RDWR);
if(fd== -1){perror("Error while opening device");exit(1);}
printf("fd=%d\n",fd);
num_bytes=read(fd, buf, BUF_SIZE);
if(num_bytes==-1){perror("Error while reading"); exit(2);}
printf("The value fetched is %lu bytes\n", num_bytes);
while(n<=num_bytes)
{
printf("%c",buf[n]);
n++;
}
close(fd);
return 0;
}
There are a few problems in the code snippet you wrote. First of all, it is not a good thing to make the call try_module_get(THIS_MODULE);
This statement tries to increase the refcount of the module ... in the module itself ! Instead, you should set the owner field of the file_ops structure to THIS_MODULE in your init method. This way, the reference handling will happen outside the module code, in the VFS layer. You might take a look at Linux Kernel Modules: When to use try_module_get / module_put.
Then, as it was stated by Vineet you should retrieve the pointer from the file_ops private_data field.
And last but not least, here is the reason why it seems an error happened while ... Actually ... It did not :
The copy_to_user call returns 0 if it has successfully copied all the desired bytes into the destination memory area and a strictly positive value stating the number of bytes that were NOT copied in case of error. That said, when you run :
/* Kernel part */
bytes_read=copy_to_user(buffer, msg, length);
/*
* Wrong error checking :
* In the below statement, "-1" is viewed as an unsigned long.
* With a simple equality test, this will not bother you
* But this is dangerous with other comparisons like "<" or ">"
* (unsigned long)(-1) is at least 2^32 - 1 so ...
*/
if (-1 == bytes_read) {
/* etc. */
}
return bytes_read;
/* App part */
num_bytes=read(fd, buf, BUF_SIZE);
/* etc.. */
while(n<=num_bytes) {
printf("%c",buf[n]);
n++;
}
You should only get one character upon a successful copy, that is only a single "I" in your case.
Moreover, you use your msg_Ptr pointer as a safeguard but you never update it. This might result in a wrong call to copy_to_user.
copy_to_user checks the user-space pointer with a call to access_ok, but if the kernel-space pointer and the given length are not allright, this might end in a Kernel Oops/Panic.
I think you should update the file->private_data in open and then you have to fetch that in your structure. Because I guess the msg buffer ( kernel buffer ) is not getting proper refernce.
I am trying out an example of obtaining advanced information about installed n/w devices from WinPcap.
I have even followed the instructions for including WinPcap library ,still the compiler complains that pcap_findalldevs_ex is undefined
at line if (pcap_findalldevs_ex(source, NULL, &alldevs, errbuf) == -1).
My Code :
#include "stdafx.h"
#include <stdio.h>
#include "pcap.h"
#include <winsock2.h>
#pragma comment(lib, "ws2_32")
// Function prototypes
void ifprint(pcap_if_t *d);
char *iptos(u_long in);
char* ip6tos(struct sockaddr *sockaddr, char *address, int addrlen);
int _tmain(int argc, _TCHAR* argv[])
{
pcap_if_t *alldevs;
pcap_if_t *d;
char errbuf[PCAP_ERRBUF_SIZE+1];
char source[PCAP_ERRBUF_SIZE+1];
printf("Enter the device you want to list:\n"
"rpcap:// ==> lists interfaces in the local machine\n"
"rpcap://hostname:port ==> lists interfaces in a remote machine\n"
" (rpcapd daemon must be up and running\n"
" and it must accept 'null' authentication)\n"
"file://foldername ==> lists all pcap files in the give folder\n\n"
"Enter your choice: ");
fgets(source, PCAP_ERRBUF_SIZE, stdin);
source[PCAP_ERRBUF_SIZE] = '\0';
/* Retrieve the interfaces list */
if (pcap_findalldevs_ex(source, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf);
exit(1);
}
/* Scan the list printing every entry */
for(d=alldevs;d;d=d->next)
{
ifprint(d);
}
pcap_freealldevs(alldevs);
return 1;
return 0;
}
/* Print all the available information on the given interface */
void ifprint(pcap_if_t *d)
{
//Code removed to reduce length and it contains no errors.
}
/* From tcptraceroute, convert a numeric IP address to a string */
#define IPTOSBUFFERS 12
char *iptos(u_long in)
{
//Code removed to reduce length
}
char* ip6tos(struct sockaddr *sockaddr, char *address, int addrlen)
{
//Code removed to reduce length
}
Can some one point me in the right direction?
Edit : If I use pcap_findalldevs(&alldevs, errbuf) in the above code it builds successfully. So I guess it has no problem linking to the dll.
Edit 1 : Error
error C3861: 'pcap_findalldevs_ex': identifier not found
IntelliSense:identifier "pcap_findalldevs_ex" is undefined
Thanks.
pcap_findalldevs_ex is only present if you define HAVE_REMOTE
Add HAVE_REMOTE as a preprocessor definition in project properties, or do the following for every include of pcap.h:
#define HAVE_REMOTE
#include "pcap.h"