#pragma ident "@(#) cmsctl.c 1.0.3 2012.12.10,15:00"
#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<sys/types.h>
#include	<sys/ipc.h>
#include	<sys/msg.h>
#include	<sys/sem.h>
#include	<sys/shm.h>
#include	<unistd.h>
#include	<errno.h>

#define MAXMSG 1024
#define	LOCK -1
#define	UNLOCK 1

struct quemsg {
	long type;
	char msg[MAXMSG+1];
};

char err_code[7];

int createque (key_t quekey)
{
	int	fd;
	errno = 0;

	fd = msgget (quekey, IPC_CREAT | 0666);
	if (fd < 0)
	{
		sprintf(err_code, "%05d", errno);
		return -1;
	}
	return(fd);
}

int connectque (key_t quekey)
{
	int	fd;
	fd = msgget (quekey, 0666);
	if (fd < 0)
	{
		 sprintf(err_code, "%05d", errno);
		return -1;
	}
	return(fd);
}

int disconnectque (int quefd)
{
	struct msqid_ds mqstat;
	int uid, ret;

	uid = getuid();
	errno = 0;
	ret = msgctl (quefd, IPC_STAT, &mqstat);

	if (ret < 0){
		return (ret);
	}
	if (mqstat.msg_perm.cuid == uid || mqstat.msg_perm.uid == uid)
	{
		ret = msgctl (quefd, IPC_RMID, &mqstat);

	    if (ret < 0){
		    sprintf(err_code, "%05d", errno);
			return (-1);
		}
		return(0);
	}
	return (mqstat.msg_perm.cuid);
}

int createque_del (key_t quekey)
{
	int	fd;
   //int ret;
	errno = 0;

	fd = msgget (quekey, IPC_CREAT|IPC_EXCL | 0666);

    if (errno == EEXIST)
	{
       fd = connectque(quekey);
	   if (fd >= 0)
	   {
         disconnectque(fd);
		 fd = msgget (quekey, IPC_CREAT | 0666);
       }
	   else
	   {
		 return -1;
	   }	 
	}
	if (fd < 0){
		 sprintf(err_code, "%05d", errno);
		return -1;
	}
	return fd;
}

/*
int connectque (key_t quekey)
{
	int	fd;
	fd = msgget (quekey, 0666);
	if (fd < 0)
	{
		 sprintf(err_code, "%05d", errno);
		return -1;
	}
	return(fd);
}

int disconnectque (int quefd)
{
	struct msqid_ds mqstat;
	int uid, ret;

	uid = getuid();
	errno = 0;
	ret = msgctl (quefd, IPC_STAT, &mqstat);

	if (ret < 0){
		return (ret);
	}
	if (mqstat.msg_perm.cuid == uid || mqstat.msg_perm.uid == uid)
	{
		ret = msgctl (quefd, IPC_RMID, &mqstat);

	    if (ret < 0){
		    sprintf(err_code, "%05d", errno);
			return (-1);
		}
		return(0);
	}
	return (mqstat.msg_perm.cuid);
}
*/

int sendque (int quefd, long type, const void *s, size_t size)
{
	struct quemsg	qmsg;
	int ret;

	qmsg.type = type;
	memcpy (qmsg.msg, s, size);
	qmsg.msg[size] = 0;
	ret = msgsnd (quefd, &qmsg, size, 0);
	if (ret < 0){
		 sprintf(err_code, "%05d", errno);
	}
	return(ret);
}

int recvque (int quefd, long type, void *s)
{
	struct quemsg qmsg;
	int	ret;

	qmsg.type = type;
	ret = msgrcv (quefd, &qmsg, MAXMSG, type, 0);

	if (ret < 0)
	{
		if (errno != EINTR)
		{
			sprintf(err_code, "%05d", errno);
		}
	//	((char *)s)[0] = NULL;
		s = NULL;
		return(ret);
	}
	memcpy (s, qmsg.msg, ret);
	qmsg.msg[ret] = 0;
	return(ret);
}

int recvqueH(int quefd, long type, void *s)
{
	struct quemsg qmsg;
	int	ret;

	qmsg.type = type;
	ret = msgrcv (quefd, &qmsg, MAXMSG, type, 0);

	if (ret < 0)
	{
		if (errno != EINTR)
		{
			sprintf(err_code, "%05d", errno);
		}
		((char *)s)[0] = 0;
		return(ret);
	}
	memcpy (s, &qmsg.type, ret+4);
	qmsg.msg[ret] = 0;
	return(ret+4);
}

char *basename(char *path)
{
	int i,j;
	int len;
	char *p;

	len = strlen(path);
	p = (char *)malloc(sizeof(path));
	for(i=0;i<len;i++)
	{
		if(path[len-i] == '/')
		{
			i--;
			break;
		}
	}
	for(j=0;i != 0;j++,i--)
	{
		p[j] = path[len-i];
	}
	p[j] = '\0';
	return((char *)p);
}

int main(int argc ,char **argv)
{
//	int	quefd;
	int	fd;
//	int i,j,k;
	int i,j;
	key_t nque;
	char opt[32][256];
	char msg[2048];
	char *buf;

    struct	sembuf		sem_buf;
    //struct	shmid_ds	shm_buf;
    unsigned	int		shm_no = 0;
    int		sem_id;

	if (argc < 3 || argc > 24)
	{
		fprintf(stderr,"Usage: %s [ -r que-id ] [ -s que-id]\n",basename(argv[0]));
		exit(1);
	}
    sem_id = semget(shm_no,0,IPC_CREAT);

	for (i=0;i<argc;i++)
	{
		if(*(argv[i]) == '-')
		{
			*argv[i]++;
			for (j=0;*(argv[i]+j) != '\0';j++)
			{
				opt[i][j]  = *(argv[i]+j);
			}
			opt[i][j] = '\0';
		}
	}
	for(i=0;i<argc;i++)
	{
		for(j=0;j < (int)strlen(opt[i]);j++)
		{
			switch(opt[i][j])
			{
			case 's':

				if (argc != 5)
					exit(1);
    			sem_buf.sem_op = LOCK;
    			if(sem_id != -1)
        			semop(sem_id,&sem_buf,0);
				if((nque = atoi(*(argv+i+1))) < 10000)
				{
        			sem_buf.sem_op = UNLOCK;
        			if(sem_id != -1)
            			semop(sem_id,&sem_buf,0);
					exit(1);
				}
				if((fd = createque(nque)) == -1)
				{
					printf("CREATE ERROR:%s\n",err_code);
					break;
				}
				if(strlen(*(argv+i+2)) < (size_t)1 || argc < 4)
				{
					break;
				}
			//	buf = (char *)malloc(sizeof(*(argv+i+2))+sizeof(*(argv+i+3))+1);
				buf = (char *)malloc(512);
				sprintf(buf,"%s",*(argv+3));
				if((sendque(fd,0x0060,buf,strlen(buf))) < 0)
				{
					printf("SEND ERROR:%s\n",err_code);
					free((char *)buf);
					break;
				}
			//	free((char *)buf);
        			sem_buf.sem_op = UNLOCK;
        			if(sem_id != -1)
            			semop(sem_id,&sem_buf,0);
				break;
			case 'r':
				if (argc != 3)
					exit(1);
    			sem_id = semget(shm_no,0,IPC_CREAT);

    			sem_buf.sem_op = LOCK;
    			if(sem_id != -1)
        			semop(sem_id,&sem_buf,0);
				nque = atoi(*(argv+i+1));
				if ((fd = connectque(nque)) < 0)
				{
					printf("CONECT ERROR:%s\n",err_code);
					break;
				}
				if((recvque(fd, 0x0060, &msg)) < 0)
				{
					printf("RECV ERROR:%s\n",err_code);
					break;
				}
				printf("%s\n",msg);
        			sem_buf.sem_op = UNLOCK;
        			if(sem_id != -1)
            			semop(sem_id,&sem_buf,0);
				break;
			default:
				fprintf(stderr,"Usage: %s [ -r que-id ] [ -s que-id]\n",basename(argv[0]));
				break;
			}
		}
	}
}
