dbsrv.c 9/15
/*
* QNX demo: Database server
*
* (c) Perlaki Attila, Fulep David 1996; Drotos Daniel 1997
*
* QNX part of the database server.
*
*/
#include <stdio.h>
#include <sys/name.h>
#include <errno.h>
#include <sys/kernel.h>
#include <sys/sendmx.h>
#include <unistd.h>
#include "globals.h"
#include "db-server.h"
#include "write.h"
#include "read.h"
#define VERSION_STR "1.0.0"
#define VERSION_HI 1
#define VERSION_LO 0
#define VERSION_P 0
#define TRUE 1
#define FALSE 0
/*
Query: HEADER
RECORD
[MASK]
Answer: HEADER
*/
int
do_write(pid_t client_pid, struct query_rec *query)
{
int i;
char *record, *mask;
struct answer_rec answer;
struct _mxfer_entry mx;
if (debug)
{
printf("WRITE command received from %d\n", client_pid);
printf("Header: db_name= %s\n", query->db_name);
printf("Header: w.record_size= %d\n", query->w.record_size);
printf("Header: w.is_mask = %d\n", query->w.is_mask);
}
record= (char *)malloc(query->w.record_size);
_setmx(&mx, record, query->w.record_size);
Readmsgmx(client_pid,
sizeof(struct query_rec),
1,
&mx);
if (debug)
{
printf("Record: ");
for (i=0; i < query->w.record_size; i++)
printf("%c%02x ", record[i], record[i]);
printf("\n");
}
if (query->w.is_mask)
{
mask= (char *)malloc(query->w.record_size);
_setmx(&mx, mask, query->w.record_size);
Readmsgmx(client_pid,
sizeof(struct query_rec) +
query->w.record_size,
1,
&mx);
if (debug)
{
printf("Mask: ");
for (i=0; i < query->w.record_size;i++)
printf("%c%02x ", mask[i], mask[i]);
printf("\n");
}
}
else
mask= NULL;
_setmx(&mx, &answer, sizeof(struct answer_rec));
i= db_write(query, record, mask, &answer);
Replymx(client_pid, 1, &mx);
free(record);
if (mask)
free(mask);
return(answer.result);
}
/*
Query: HEADER
MASK
Answer: HEADER
RECORD
*/
int
do_read(pid_t client_pid, struct query_rec *query)
{
int i;
char *mask, *record;
struct _mxfer_entry mx, mxa[2];
struct answer_rec answer;
if (debug)
{
printf("READ command received from %d\n", client_pid);
printf("Header: db_name= %s\n", query->db_name);
printf("Header: r.record_size= %d\n", query->r.record_size);
printf("Header: r.index= %ld\n", query->r.index);
}
mask= (char *)malloc(query->r.record_size);
_setmx(&mx, mask, query->r.record_size);
Readmsgmx(client_pid,
sizeof(struct query_rec),
1,
&mx);
if (debug)
{
printf("Mask: ");
for (i=0; i < query->r.record_size; i++)
printf("%c%02x ", mask[i], mask[i]);
printf("\n");
}
record= (char *)malloc(query->r.record_size);
_setmx(&mxa[0], &answer, sizeof(struct answer_rec));
_setmx(&mxa[1], record, query->r.record_size);
i= db_read(query, mask, &answer, record);
Replymx(client_pid, 2, &mxa);
free(mask);
free(record);
return(answer.result);
}
/*
Query: HEADER
MASK
Answer: HEADER
*/
int
do_recdel(pid_t client_pid, struct query_rec *query)
{
int i;
char *mask;
struct _mxfer_entry mx, mxa;
struct answer_rec answer;
if (debug)
{
printf("RECDEL command received from %d\n", client_pid);
printf("Header: db_name= %s\n", query->db_name);
printf("Header: d.record_size= %d\n", query->d.record_size);
}
mask= (char *)malloc(query->d.record_size);
_setmx(&mx, mask, query->d.record_size);
Readmsgmx(client_pid,
sizeof(struct query_rec),
1,
&mx);
if (debug)
{
printf("Mask: ");
for (i=0; i < query->d.record_size; i++)
printf("%c%02x ", mask[i], mask[i]);
printf("\n");
}
_setmx(&mxa, &answer, sizeof(struct answer_rec));
i= db_recdel(query, mask, &answer);
Replymx(client_pid, 1, &mxa);
free(mask);
return(answer.result);
}
/*
Query: HEADER
Answer: HEADER
*/
int
do_dbdel(pid_t client_pid, struct query_rec *query)
{
struct _mxfer_entry mxa;
struct answer_rec answer;
if (debug)
{
printf("DBDEL command received from %d\n", client_pid);
printf("Header: db_name= %s\n", query->db_name);
}
_setmx(&mxa, &answer, sizeof(struct answer_rec));
db_dbdel(query, &answer);
Replymx(client_pid, 1, &mxa);
return(answer.result);
}
/*
Query: HEADER
Answer: HEADER
*/
int
do_test(pid_t client_pid, struct query_rec *query)
{
struct _mxfer_entry mxa;
struct answer_rec answer;
if (debug)
printf("TEST command received from %d\n", client_pid);
_setmx(&mxa, &answer, sizeof(struct answer_rec));
answer.result= 0;
answer.t.version_hi= VERSION_HI;
answer.t.version_lo= VERSION_LO;
answer.t.version_p = VERSION_P;
strcpy(answer.t.version_str, VERSION_STR);
Replymx(client_pid, 1, &mxa);
return(answer.result);
}
/*
Query: HEADER
Answer: HEADER
*/
int
do_unknown(pid_t client_pid, struct query_rec *query)
{
struct _mxfer_entry mxa;
struct answer_rec answer;
if (debug)
{
printf("UNKNOWN command received from %d\n", client_pid);
printf("Header: command= %c\n", query->command);
}
_setmx(&mxa, &answer, sizeof(struct answer_rec));
answer.result= RES_UNKNOWN_COMMAND;
Replymx(client_pid, 1, &mxa);
return(answer.result);
}
static void
show_help(char *argv0)
{
printf("dbsrv %s\n", VERSION_STR);
printf("Use: %s [-Vhvs] [-N name]\n", argv0);
printf("Options:\n");
printf("\t-N name\tRegister server with `name'.\n");
printf("\t-s\tEnable STOP operation.\n");
printf("\t-V\tShow debug messages.\n");
printf("\t-h\tShow this short help.\n");
printf("\t-v\tPrint out version number.\n");
}
int
main(int argc, char *argv[])
{
char *server_name= NULL;
int NoRun= FALSE, enable_stop= FALSE;
int name_id;
int done;
int i;
server_name= (char *)malloc(strlen(SERVER_NAME)+1);
strcpy(server_name, SERVER_NAME);
while ((i= getopt(argc, argv, "VN:hvs")) != -1)
switch (i)
{
case 'V':
debug= TRUE;
break;
case 'N':
if (server_name)
free(server_name);
server_name= (char *)strdup(optarg);
break;
case 'v':
printf("dbsrv %s\n", VERSION_STR);
NoRun= TRUE;
break;
case 'h':
show_help(argv[0]);
NoRun= TRUE;
break;
case 's':
enable_stop= TRUE;
break;
case '?':
if (isprint(optopt))
fprintf(stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
exit(1);
break;
default:
abort();
break;
}
for (i= optind; i < argc; i++)
;
if (NoRun)
exit(0);
if (enable_stop &&
server_name[0] == '/')
{
fprintf(stderr, "Name can not be global if STOP is enabled.\n");
exit(2);
}
name_id= qnx_name_attach(0, server_name);
if (name_id < 0)
{
perror("Name attach");
exit(1);
}
if (debug)
printf("Server \"%s\" is running...\n", server_name);
done= 0;
while (!done)
{
struct _mxfer_entry mx;
int client_pid;
struct query_rec query;
_setmx(&mx, &query, sizeof(struct query_rec));
client_pid= Receivemx(0, 1, &mx);
switch (query.command)
{
case CM_WRITE:
do_write(client_pid, &query);
break;
case CM_READ:
do_read(client_pid, &query);
break;
case CM_RECDEL:
do_recdel(client_pid, &query);
break;
case CM_DBDEL:
do_dbdel(client_pid, &query);
break;
case CM_TEST:
do_test(client_pid, &query);
break;
case CM_STOP:
if (!enable_stop)
do_unknown(client_pid, &query);
else
{
if (debug)
printf("STOP command received from %d\n", client_pid);
done= 1;
}
break;
default:
do_unknown(client_pid, &query);
break;
}
}
return(0);
}
/* End of server.c */
read.c 11/15
/*
* QNX demo: Database server
*
* (c) Perlaki Attila, Fulep David 1996; Drotos Daniel 1997
*
* This file contains POSIX part of READ operation.
*
*/
#include <stdio.h>
#include <errno.h>
#include "globals.h"
#include "db-server.h"
#include "utils.h"
int
db_read(struct query_rec *query,
char *mask,
struct answer_rec *answer,
char *record)
{
FILE *f;
fpos_t fpos;
long idx;
int i;
answer->result= 0;
answer->r.index= -1;
if ((f= fopen(query->db_name, "r")) == NULL)
{
perror("Opening database");
answer->result= ERR_OPEN_DB;
return(ERR_OPEN_DB);
}
fpos= query->r.index * query->r.record_size;
idx=query->r.index;
if ((i= fsetpos(f, &fpos) < 0))
{
perror("Positioning to requested record");
answer->result= ERR_FILE_ERROR;
return(ERR_FILE_ERROR);
}
i= fgetpos(f, &fpos);
i= fread(record, 1, query->r.record_size, f);
if (i < 0)
{
perror("Reading database");
answer->result= ERR_READ_ERROR;
}
else
while ((i == query->r.record_size) &&
!(answer->result) &&
answer->r.index < 0)
{
if (debug)
{
printf("Comparing record %d (at pos %d) and the mask\n",
idx, fpos);
for (i= 0; i < query->r.record_size; i++)
printf("%c%02x ", record[i], record[i]);
printf("\n");
for (i= 0; i < query->r.record_size; i++)
printf("%c%02x ", mask[i], mask[i]);
printf("\n");
}
if (match(record, mask, query->r.record_size))
{
/* Found! */
if (debug)
printf("Found requested record (%d)\n", idx);
answer->result= 0;
answer->r.index= idx;
}
else
{
fgetpos(f, &fpos);
i= fread(record, 1, query->r.record_size, f);
if (i < 0)
{
perror("Reading database");
answer->result= ERR_READ_ERROR;
}
idx++;
}
}
if (answer->r.index < 0)
{
if (debug)
printf("Record not found\n");
answer->result= RES_RECORD_NOT_FOUND;
}
fclose(f);
return(answer->result);
}
/* End of read.c */
recdel.c 12/15
/*
* QNX demo: Database server
*
* (c) Perlaki Attila, Fulep David 1996; Drotos Daniel 1997
*
* This file contains POSIX part of RECDEL operation.
*
*/
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include "globals.h"
#include "db-server.h"
#include "utils.h"
int
db_recdel(struct query_rec *query, char *mask, struct answer_rec *answer)
{
FILE *f;
fpos_t fpos, act_long;
long idx;
int i;
char *record;
struct stat st;
answer->result= 0;
answer->d.nuof_deleted= 0;
if ((f= fopen(query->db_name, "r+")) == NULL)
{
perror("Opening database");
answer->result= ERR_OPEN_DB;
return(ERR_OPEN_DB);
}
if (fstat(fileno(f), &st) < 0)
{
perror("Checking size of database");
fclose(f);
answer->result= ERR_FILE_ERROR;
return(ERR_FILE_ERROR);
}
act_long= st.st_size;
if (debug)
printf("File size: %ld; number of records: %d\n",
act_long, act_long/query->d.record_size);
if (act_long % query->d.record_size)
{
if (debug)
printf("Truncating broken record from the end of the database\n");
if (trunc_file(f,
(act_long/query->d.record_size)*query->d.record_size) < 0)
{
fclose(f);
answer->result= ERR_FILE_ERROR;
return(ERR_FILE_ERROR);
}
}
if (fstat(fileno(f), &st) < 0)
{
perror("Checking size of database");
fclose(f);
answer->result= ERR_FILE_ERROR;
return(ERR_FILE_ERROR);
}
act_long= st.st_size;
record= (char *)malloc(query->d.record_size);
idx= 0;
fgetpos(f, &fpos);
i= fread(record, 1, query->d.record_size, f);
if (i < 0)
{
perror("Reading database");
answer->result= ERR_READ_ERROR;
}
else
while ((i == query->d.record_size) &&
!(answer->result) &&
act_long)
{
if (debug)
{
printf("Checking record %d at pos %ld to delete\n", idx, fpos);
printf("Record: ");
for (i= 0; i < query->d.record_size; i++)
printf("%c%02x ", record[i], record[i]);
printf("\nMask : ");
for (i= 0; i < query->d.record_size; i++)
printf("%c%02x ", mask[i], mask[i]);
printf("\n");
}
if (match(record, mask, query->d.record_size))
{
fpos_t l;
char *lr;
/* deleting record */
if (debug)
printf("Deleting record %d at pos %ld\n", idx, fpos);
answer->d.nuof_deleted++;
l= act_long - query->d.record_size;
fsetpos(f, &l);
lr= (char *)malloc(query->d.record_size);
if (l != fpos)
{
if (fread(lr, 1, query->d.record_size, f) !=
query->d.record_size)
{
perror("Reading database");
answer->result= ERR_READ_ERROR;
}
else
{
fsetpos(f, &fpos);
if (fwrite(lr,
1,
query->d.record_size, f) !=
query->d.record_size)
{
perror("Reading database");
answer->result= ERR_WRITE_ERROR;
}
else
if (trunc_file(f, l) < 0)
answer->result= ERR_FILE_ERROR;
else
act_long= l;
}
}
else
/* deleting last record */
if (trunc_file(f, l) < 0)
answer->result= ERR_FILE_ERROR;
else
act_long= l;
fsetpos(f, &fpos);
free(lr);
idx--;
}
fgetpos(f, &fpos);
if ((i= fread(record, 1, query->d.record_size, f)) < 0)
{
perror("Reading database");
answer->result= ERR_READ_ERROR;
}
idx++;
}
free(record);
fclose(f);
return(answer->result);
}
/* End of recdel.c */
t.c 13/15
/*
* QNX demo: Database server
*
* (c) Drotos Daniel 1997
*
* Test program to demonstrate how to write client programs
* for the database server.
*
*/
#include <stdio.h>
#include <sys/name.h>
#include <errno.h>
#include <sys/kernel.h>
#include <sys/sendmx.h>
/* Header file of the database server */
#include "db-server.h"
/* Structure of records stored in our database file */
struct myrecord
{
int data1; /* Numeric field */
char data2[10]; /* Character field */
};
/*
* Testing WRITE operation
*____________________________________________________________________________
*
*/
int
test_write(pid_t server)
{
struct _mxfer_entry mxq[2], mxa; /* Pointers for query and answer */
struct query_rec query; /* Query */
struct answer_rec ans; /* Answer */
struct myrecord data; /* Data to write into database */
printf("Testing write...\n");
/*
* Setting up pointers to point to data structures. This query
* will contain two part: fix header and one record to write
*/
_setmx(&mxq[0], &query, sizeof(struct query_rec));
_setmx(&mxq[1], &data , sizeof(struct myrecord));
_setmx(&mxa , &ans , sizeof(struct answer_rec));
/* Setting up query structure */
query.command= CM_WRITE;
strcpy(query.db_name, "proba.db");
query.w.record_size= sizeof(struct myrecord);
query.w.is_mask= 0; /* We do not provide MASK */
/* Setting up data record */
printf("Enter data1: ");
scanf("%d", &data.data1); /* Num field and.. */
strcpy(data.data2, "adatmezo"); /* ..char field */
/* Sending the query to the server and getting the answer */
if (Sendmx(server,
2, /* Two part query */
1, /* One part answer */
&mxq,/* Pointers to parts of query */
&mxa /* Pointer to asnwer record */) < 0)
perror("WRITE not answered");
else
printf("Answer: %d\n", ans.result);
return(ans.result);
}
/*
* Testing replace operation (write with MASK)
*____________________________________________________________________________
*
*/
int
test_replace(pid_t server)
{
struct _mxfer_entry mxq[3], mxa; /* Pointers for query and answer */
struct query_rec query; /* Query */
struct answer_rec ans; /* Answer */
struct myrecord mask, newr; /* Data records: MASK and the new record */
printf("Testing replace...\n");
/*
* Setting up pointers to point the real data structures.
* Query will contain three part: fix header, record to write
* and a mask record to search for
*/
_setmx(&mxq[0], &query, sizeof(struct query_rec));
_setmx(&mxq[1], &newr , sizeof(struct myrecord));
_setmx(&mxq[2], &mask , sizeof(struct myrecord));
_setmx(&mxa , &ans , sizeof(struct answer_rec));
/* Setting up query */
query.command= CM_WRITE;
strcpy(query.db_name, "proba.db");
query.w.record_size= sizeof(struct myrecord);
query.w.is_mask= 1; /* We provide MASK record */
/*
* Setting up MASK record. '*' character in mask will
* match with any byte in database's record
*/
/* Filling MASK up with joker '*' character */
memset(&mask, '*', sizeof(struct myrecord));
/* Setting up some parts of the MASK with specific data */
mask.data1= 123;
strcpy(mask.data2, "adatmezo");
/* Setting up new data record */
newr.data1= 321;
strcpy(newr.data2, "ujrekord");
/* Sending query to the server and getting answer */
if (Sendmx(server,
3, /* Three part query */
1, /* One part answer */
&mxq, /* Pointers to parts of query */
&mxa /* Pointer to answer */) < 0)
perror("WRITE not answered");
else
printf("Answer: %d\n", ans.result);
return(ans.result);
}
/*
* Testing READ operation
*____________________________________________________________________________
*
*/
int
test_read(pid_t server)
{
struct _mxfer_entry mxq[2], mxa[2]; /* Pointers for query and answer */
struct query_rec query; /* Query */
struct answer_rec ans; /* Answer */
struct myrecord mask, record; /* Data records */
printf("Testing read...\n");
/*
* Setting up pointers to point to real query and answer structures.
* READ query contains two parts: fix header and a MASK record.
* Answer contains two parts as well: fix header and a record which
* matches to MASK record.
*/
_setmx(&mxq[0], &query , sizeof(struct query_rec));
_setmx(&mxq[1], &mask , sizeof(struct myrecord));
_setmx(&mxa[0], &ans , sizeof(struct answer_rec));
_setmx(&mxa[1], &record, sizeof(struct myrecord));
/* Setting up query */
query.command= CM_READ;
strcpy(query.db_name, "proba.db");
query.r.record_size= sizeof(struct myrecord);
query.r.index= 0; /* Start search with first record */
/* Filling MASK record up with joker '*' */
memset(&mask, '*', sizeof(struct myrecord));
/* Setting up some parts of MASK with specific data */
mask.data1= 123;
strcpy(mask.data2, "adatmezo");
/* Sending query to server and getting answer */
if (Sendmx(server,
2, /* Two part query */
2, /* Two part asnwer */
&mxq,/* Pointers to parts of query */
&mxa /* Pointers to parts of answer */) < 0)
perror("READ not answered");
else
{
/* Checking asnwer */
printf("Answer: %d\n", ans.result);
printf("Answer: r.index= %ld\n", ans.r.index);
/* If `index' of answer is not negative we found a record */
if (ans.r.index >= 0)
{
printf("Record: data1= %d\n", record.data1);
printf("Record: data2= \"%s\"\n", record.data2);
}
}
/* Reading all records */
printf("\nReading all records\n");
/* Filling MASK up with joker '*' */
memset(&mask, '*', sizeof(struct myrecord));
/* Start search at the beginning of the database */
query.r.index= 0;
/* Continuing query until we run out of recors */
if (Sendmx(server, 2, 2, &mxq, &mxa) < 0)
ans.r.index= -1;
while (ans.r.index >= 0)
{
printf("%3d. %05d \"%s\"\n", ans.r.index, record.data1, record.data2);
/* Query again: continue search at the next record */
query.r.index= ans.r.index+1;
if (Sendmx(server, 2, 2, &mxq, &mxa) < 0)
ans.r.index= -1;
}
return(ans.result);
}
/*
* Testing RECDEL operation
*____________________________________________________________________________
*
*/
int
test_recdel(pid_t server)
{
struct _mxfer_entry mxq[2], mxa; /* Pointers for query and asnwer */
struct query_rec query; /* Query */
struct answer_rec ans; /* Answer */
struct myrecord mask; /* MASK record */
printf("Testing recdel...\n");
/*
* Setting up poniters. Delete operation needs two part into query.
* First is fix header, and second is a MASK record which specifies
* what are we going to delete.
*/
_setmx(&mxq[0], &query , sizeof(struct query_rec));
_setmx(&mxq[1], &mask , sizeof(struct myrecord));
_setmx(&mxa , &ans , sizeof(struct answer_rec));
/* Setting up query */
query.command= CM_RECDEL;
strcpy(query.db_name, "proba.db");
query.d.record_size= sizeof(struct myrecord);
/* Filling MASK up with joker '*' */
memset(&mask, '*', sizeof(struct myrecord));
/* Setting up some parts of the MASK record */
printf("Enter data1: ");
scanf("%d", &mask.data1);
/* Sending query to the server and getting answer */
if (Sendmx(server,
2, /* Two part query */
1, /* One part answer */
&mxq,/* Pointers to parts of query */
&mxa /* Pointer to answer */) < 0)
perror("RECDEL not answered");
else
{
printf("Answer: %d\n", ans.result);
printf("Answer: r.nuof_deleted= %ld\n", ans.d.nuof_deleted);
}
return(ans.result);
}
/*
* Testing DBDEL operation
*____________________________________________________________________________
*
*/
int
test_dbdel(pid_t server)
{
struct _mxfer_entry mxq, mxa; /* Pointers for query and answer */
struct query_rec query; /* Query */
struct answer_rec ans; /* Answer */
printf("Testing dbdel...\n");
/*
* Setting up pointers to point real data structures.
* This type of query contains only one part the fix header part.
*/
_setmx(&mxq, &query, sizeof(struct query_rec));
_setmx(&mxa, &ans , sizeof(struct answer_rec));
/* Setting up query */
query.command= CM_DBDEL;
strcpy(query.db_name, "proba.db");
/* Sending query and getting answer */
if (Sendmx(server,
1, /* One part query */
1, /* One part answer */
&mxq,/* Pointer to query */
&mxa /* Pointer to answer */) < 0)
perror("DBDEL not answered");
else
printf("Answer: %d\n", ans.result);
return(ans.result);
}
/*
* Testing TEST operation
*____________________________________________________________________________
*
*/
int
test_test(pid_t server)
{
struct _mxfer_entry mxq, mxa; /* Pointers for query and answer */
struct query_rec query; /* Query */
struct answer_rec ans; /* Answer */
printf("Testing test...\n");
/*
* Setting up pointers to point the real data structures.
* This type of query contains only one part the fix header part.
*/
_setmx(&mxq, &query, sizeof(struct query_rec));
_setmx(&mxa, &ans , sizeof(struct answer_rec));
/* Setting up query */
query.command= CM_TEST;
/* Sending query. This type of request is never answered! */
if (Sendmx(server,
1, /* One part query */
1, /* We expect something... */
&mxq,/* Pointer to query */
&mxa /* Pointer to answer */) < 0)
perror("STOP not answered");
else
{
printf("Answer: %d\n", ans.result);
printf("Answer: t.version_hi = %d\n", ans.t.version_hi);
printf("Answer: t.version_lo = %d\n", ans.t.version_lo);
printf("Answer: t.version_p = %d\n", ans.t.version_p);
printf("Answer: t.version_str= %s\n", ans.t.version_str);
}
return(ans.result);
}
/*
* Testing STOP operation
*____________________________________________________________________________
*
*/
int
test_stop(pid_t server)
{
struct _mxfer_entry mxq, mxa; /* Pointers for query and answer */
struct query_rec query; /* Query */
struct answer_rec ans; /* Answer */
printf("Testing stop...\n");
/*
* Setting up pointers to point the real data structures.
* This type of query contains only one part the fix header part.
*/
_setmx(&mxq, &query, sizeof(struct query_rec));
_setmx(&mxa, &ans , sizeof(struct answer_rec));
/* Setting up query */
query.command= CM_STOP;
/* Sending query. This type of request is never answered! */
if (Sendmx(server,
1, /* One part query */
1, /* We expect something... */
&mxq,/* Pointer to query */
&mxa /* Pointer to answer */) < 0)
perror("STOP not answered");
else
printf("Answer: %d\n", ans.result);
return(ans.result);
}
/*
* Program to test operations of database server
*____________________________________________________________________________
*
*/
int
main(int argc, char *argv[])
{
pid_t server;
char *c, *srvname;
if (argv[1][0] == '-')
{
printf("%s\n", &argv[1][1]);
server= qnx_name_locate(0, &argv[1][1], 0, NULL);
if (argc < 3)
exit(2);
c= argv[2];
}
else
{
server= qnx_name_locate(0, SERVER_NAME, 0, NULL);
if (argc < 2)
exit(2);
c= argv[1];
}
if (server < 0)
{
perror("Locate server");
exit(1);
}
test_test(server);
while (*c)
{
switch (*c)
{
case 'w':
test_write(server);
break;
case 'R':
test_replace(server);
break;
case 'r':
test_read(server);
break;
case 's':
test_stop(server);
break;
case 'd':
test_recdel(server);
break;
case 'D':
test_dbdel(server);
break;
default:
printf("Unknown test %c\n", *c);
break;
}
c++;
}
return(0);
}
/* End of t.c */
write.c 15/15
/*
* QNX demo: Database server
*
* (c) Perlaki Attila, Fulep David 1996; Drotos Daniel 1997
*
* This file contains POSIX part of WRITE operation.
*
*/
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/types.h>
#include <string.h>
#include "globals.h"
#include "db-server.h"
#include "utils.h"
static int
append(int fd, char *record, int n)
{
if ((lseek(fd, 0, SEEK_END) < 0) ||
(write(fd, record, n) < 0))
{
perror("Append to database");
return(ERR_FILE_ERROR);
}
if (debug)
printf("Record appended to database\n");
return(0);
}
int
db_write(struct query_rec *query,
char *record,
char *mask,
struct answer_rec *answer)
{
FILE *f;
f= fopen(query->db_name, "r+");
if (f == NULL)
{
if (errno == ENOENT)
{
if ((f= fopen(query->db_name, "w+")) == NULL)
{
perror("Creating database");
return(ERR_CREATE_DB);
}
else
if (debug)
printf("Database \"%s\" created\n", query->db_name);
}
else
{
perror("Opening database");
return(ERR_OPEN_DB);
}
}
answer->result= 0;
if (!mask)
{
/* Simply append */
answer->result= append(fileno(f), record, query->w.record_size);
}
else
{
char *actual;
fpos_t fpos;
long idx;
int i;
int was= 0;
actual= (char *)malloc(query->w.record_size);
idx= 0;
/* fpos is 0 now */
fgetpos(f, &fpos);
i= read(fileno(f), actual, query->w.record_size);
if (i < 0)
{
perror("Reading database");
answer->result= ERR_READ_ERROR;
}
else
while ((i == query->w.record_size) &&
!answer->result)
{
if (debug)
{
printf("Comparing record %d (at pos %d) and the mask\n",
idx, fpos);
for (i= 0; i < query->w.record_size; i++)
printf("%c%02x ", actual[i], actual[i]);
printf("\n");
for (i= 0; i < query->w.record_size; i++)
printf("%c%02x ", mask[i], mask[i]);
printf("\n");
}
if (match(actual, mask, query->w.record_size))
{
/* replacing record */
was= 1;
if (debug)
printf("replacing record %d\n", idx);
fsetpos(f, &fpos);
if (write(fileno(f), record, query->w.record_size) <
query->w.record_size)
answer->result= ERR_WRITE_ERROR;
}
fgetpos(f, &fpos);
i= read(fileno(f), actual, query->w.record_size);
if (i < 0)
{
perror("Reading database");
answer->result= ERR_READ_ERROR;
}
idx++;
}
if (!answer->result &&
!was)
answer->result= append(fileno(f), record, query->w.record_size);
free(actual);
}
fclose(f);
return(answer->result);
}
/* End of write.c */
Generated by GNU enscript 1.5.1.