/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * COPYING NOTES
 *
 * shmtool.c -- functions to manage shared memory
 * 
 * Copyright (C) 1995 Scott Burkett <scottb@IntNet.net>.
 *   as heavily derived from the Chapter 6 of The Linux Programmer's Guide
 * Copyright (C) 2002 Roberto A. Foglietta <robang@libero.it>
 * Copyright (C) 2002 GEA-Automotive <fogliettar@gea-automotive.com>
 *
 *   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.
 *
 *   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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 
 * REVISION NOTES:
 * released 17-10-2002 by Roberto A. Foglietta
 * bugfixed 22-01-2003 by Roberto A. Foglietta
 * modified 29-05-2003 by Roberto A. Foglietta
 */
 
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "shmtool.h"

//LOCAL FUNCTION
static char *getsegprt (int shmid);


int
initshm (key_t key, int del)
{
        int shmid;

        if(del) {
                /* RAF 2003-05-29: Delete segment if it exist */
                shmid = shmget (key, 0, 0);
                if(shmid != -1)
                        removeshm(shmid);
        }
                
        /* Open the shared memory segment - create if necessary */
        if ((shmid = shmget (key, SEGSIZE, IPC_CREAT | IPC_EXCL | 0666)) == -1) {
#ifdef SHM_TEST
                perror ("shmget (key, SEGSIZE, IPC_CREAT | IPC_EXCL | 0666)");
                printf ("Shared memory key: %ld - opening as client\n", (unsigned long)key);
#endif
                /* RAF 2003-05-29: Segment wasn't deleted or didn't create proprely */
                if(del) return -1;
                        
                /* Segment probably already exists - try as a client */
                shmid = shmget (key, 0, 0);
                if (shmid == -1)
                        perror ("shmget (key, 0, 0)");
        } else {
#ifdef SHM_TEST
                printf ("Creating new shared memory segment\n");
#endif
        }

        return shmid;
}


static char *
getsegprt (int shmid)
{
        static char *segptr = NULL;

        //printf("shmtools> getsegprt(%d);\n", shmid);
        /* RAF 2003-01-22: set off bug that induce a memory leak every call of this func */
        if(segptr == NULL) {
                /* Attach (map) the shared memory segment into the current process */
                segptr = (char *) shmat (shmid, 0, 0);
                if (segptr == (char *) -1) {
                        perror ("shmat");
                        segptr = NULL;
                }
        }

        return segptr;
}


int
writeshm (int shmid, char *text)
{
        int ret = 0;
        char *segptr = getsegprt (shmid);
        
        //printf("shmtools> writeshm(%d, 0x%lx);\n", shmid, (unsigned long)text);
        if (segptr != NULL) {
                //printf("shmtools> %s\n", text);
                ret = strlen (strncpy (segptr, text, SEGSIZE));
                segptr[SEGSIZE-1] = 0; //RAF 2003-05-29
        } else
                ret = -1;

        return ret;
}


char *
readshm (int shmid)
{
        char *segptr = getsegprt (shmid);

        if (segptr != NULL)
                return strdup (segptr);
        else
                return NULL;
}


int
removeshm (int shmid)
{
#ifdef SHM_TEST                        
        printf("Shared memory segment marked for deletion\n");
#endif        
        return shmctl (shmid, IPC_RMID, 0);
}


int
changemode (int shmid, char *mode)
{
        struct shmid_ds myshmds;
        unsigned int perms;

        /* Get current values for internal data structure */
        shmctl (shmid, IPC_STAT, &myshmds);

#ifdef SHM_TEST                
        /* Display old permissions */
        printf("Old permissions were: %o\n", myshmds.shm_perm.mode);
#endif
        
        /* Convert and load the mode */
        sscanf (mode, "%o", &perms);
        myshmds.shm_perm.mode = (unsigned short) perms;

        /* Update the mode */
#ifdef SHM_TEST                
        printf("New permissions are : %o\n", myshmds.shm_perm.mode);
#endif        
        return shmctl (shmid, IPC_SET, &myshmds);
}