What's wrong with my C-code? - mainframe

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.

Related

Dubious behaviour in multithreaded client-server in C

void* thread_request_server_static(void* args); , This is where the worker threads will handle the connection (i have got 4 threads created)
request.c:
struct conn_args
{
int fd;
int filename;
int filesize;
struct conn_args *next;
}
/* other functions */
int add(int fd, char *filename, int filesize)
{
if(buffer_size >= buffer_max_size)
return 1;
struct conn_args *temp = malloc(sizeof(struct conn_args));
temp->fd = fd;
temp->filename = filename;
temp->filesize = filesize;
temp->next = NULL;
if (head == NULL)
{
head = temp;
tail = temp;
}
else
{
tail->next = temp;
tail = temp;
}
buffer_size++;
return 0;
}
struct conn_args* get_args()
{
struct conn_args *temp = NULL;
if(head!=NULL)
{
temp = head;
head = head->next;
buffer_size--;
}
return temp;
}
void *thread_request_serve_static(void *arg)
{
while (1)
{
pthread_mutex_lock(&lock);
struct conn_args *arg = get_args();
if (!arg)
pthread_cond_wait(&c, &lock);
else
{
request_serve_static(arg->fd, arg->filename, arg->filesize);
printf("Request for %s is removed from the buffer\n-----------------\n",
arg->filename);
close_or_die(arg->fd);
free(arg);
}
pthread_mutex_unlock(&lock);
}
// TODO: write code to actualy respond to HTTP requests
}
void request_handle(int fd)
{
/* variable declarations and condition checks */
pthread_mutex_lock(&lock);
int stat = add(fd, filename, sbuf.st_size);
pthread_mutex_unlock(&lock);
if (!stat)
{
printf("-----------------\nRequest for %s is added to the buffer\n",
filename);
pthread_cond_signal(&c); // wake up thread since connections arrive at the buffer.
}
else
{
printf("Server overload: Try again later!");
}
}
wserver.c:
int main(int argc, char *argv[])
{
/* variable initializations and argument reading */
pthread_t thread_pool[num_threads];
for(int i=0; i<num_threads; i++)
pthread_create(&thread_pool[i], NULL, thread_request_serve_static, NULL);
// open the socket connection
int listen_fd = open_listen_fd_or_die(port);
while (1) {
// start accepting HTTP requests from client
struct sockaddr_in client_addr;
int client_len = sizeof(client_addr);
int conn_fd = accept_or_die(listen_fd, (sockaddr_t *) &client_addr, (socklen_t *) &client_len);
// process the HTTP request
request_handle(conn_fd);
// close the connection to client
//close_or_die(conn_fd); // this has to be carefully done at the correct time in request.c
}
Starting the server,
./wserver -p 8003 (port 8003)
bash file for testing multiple connections,
multiple_clients.bash:
echo Starting requests
for ((i=15;i>0;i-=1))
do
./wclient localhost 8003 /files/test$i.html &
done
echo Requests completed
I piped the output into a test.txt and got the following, bash multiple_clients.bash > test.txt
test.txt:
/* Meta data */
This is a test HTML file -------------- 15.
/* Meta data */
/* Meta data */
This is a test HTML file ------------ 13.
/* Meta data */
/* Meta data */
This is a test HTML file ------------ 13.
/* Meta data */
/* Meta data */
This is a test HTML file ---------- 11.
/* Meta data */
/* Meta data */
This is a test HTML file --------- 10.
/* Meta data */
/* Meta data */
This is a test HTML file ---------- 11.
/* Meta data */
/* Meta data */
This is a test HTML file ----- 6.
/* Meta data */
/* Meta data */
This is a test HTML file 1.
/* Meta data */
/* Meta data */
This is a test HTML file - 2.
/* Meta data */
/* Meta data */
This is a test HTML file --- 4.
/* Meta data */
/* Meta data */
This is a test HTML file - 2.
/* Meta data */
/* Meta data */
This is a test HTML file -------- 9.
/* Meta data */
/* Meta data */
This is a test HTML file -- 3.
/* Meta data */
/* Meta data */
This is a test HTML file ---- 5.
/* Meta data */
/* Meta data */
This is a test HTML file ------- 8.
/* Meta data */
As you can see, some files are getting repeated and some are not showing up (7 and 14). Why is this? Although the total output file count is 15, this probably means it is successfully adding all the files to the buffer, but somehow skipping some files and producing duplicates of others.
The program doesn't even crash on double free error, so how is a single file getting handled twice?
Do let me know if any more info is required.
Any help would be appreciated.

USB to Serial adapter - receive works OK for a limited time

I borrowed much of the following code from the Linux Serial HOWTO pages to create my program to read characters endlessly from the serial port. I'm using a USB to serial port adapter (made by micro innovations) so I can get a serial port. Linux recognizes the device as /dev/ttyUSB0.
When I use the device in other native linux programs (such as the output dump program), the adapter works flawlessly and data continuously comes in. However, with my program, the data comes in for roughly 10 seconds, then I receive no more data, yet I know the hardware that the adapter is connected to has more data to process.
Is there something in this code I can fix to allow me to receive unlimited characters as they arrive without me having to restart the program to receive more characters?
I still want to make the mainline code asynchronous to the serial routine as I will be adding more code later on.
#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>
#define BAUDRATE B57600
#define MODEMDEVICE "/dev/ttyUSB0" /* My USB to serial converter */
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
void signal_handler_IO (); /* definition of signal handler */
int wait_flag=TRUE; /* TRUE while no signal received */
int main(){
int fd,res;
struct termios oldtio,newtio;
struct sigaction saio; /* definition of signal action */
char buf[255];
/* open the device */
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY);
if (fd <0) {perror(MODEMDEVICE); return -1; }
/* install the signal handler before making the device asynchronous */
saio.sa_handler = signal_handler_IO;
saio.sa_flags=0;
saio.sa_restorer = NULL;
sigaction(SIGIO,&saio,NULL);
/* allow the process to receive SIGIO */
fcntl(fd, F_SETOWN, getpid());
/* Make the file descriptor asynchronous */
fcntl(fd, F_SETFL, FASYNC);
tcgetattr(fd,&oldtio); /* save current port settings */
/* set new port settings for canonical input processing */
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = ICANON;
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
/* loop while waiting for input. */
while (1) {
usleep(100000);
/* after receiving SIGIO, wait_flag = FALSE,
input is available and can be read */
if (wait_flag==FALSE) {
res=0;
/* Read up to 11 bytes which is remote packet length if file handle is valid */
if (fd){
res = read(fd,buf,11);
}
/* If there's at least 2 bytes (character plus ending null) then process it */
if (res > 1){
int n;
/* Print each character as 2-digit hex even if value is 0. */
for (n=0;n<(res-1);n++){
printf("%2X ",(unsigned char)buf[n]);
}
/* Print total number of characters received */
printf(" = %d\n",res);
}
wait_flag = TRUE; /* wait for new input */
}
/* Return to start of endless loop */
}
return 0;
}
/***************************************************************************
* signal handler. sets wait_flag to FALSE, to indicate above loop that *
* characters have been received. *
***************************************************************************/
void signal_handler_IO ()
{
wait_flag = FALSE;
}
Classic race condition:
The signal_handler_IO() may be called before your code sets wait_flag = TRUE; e.g. during those printf() calls.
At this point your program will simply stop.
A remedy could be setting the wait_flag immediately after the if - but I would recommend looking into linux poll() call for async I/O.

DOS: how to get current country code or code page in Turbo C

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(&regs, &regs, &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.

copy_to_user not working in kernel module

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.

Memory fault error in LINUX but not in UNIX

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 :-)

Resources