home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / samba-1.9.18p7.tar.gz / samba-1.9.18p7.tar / samba-1.9.18p7 / source / shmem_sysv.c < prev    next >
C/C++ Source or Header  |  1998-05-11  |  17KB  |  715 lines

  1. /* 
  2.    Unix SMB/Netbios implementation.
  3.    Version 1.9.
  4.    Shared memory functions - SYSV IPC implementation
  5.    Copyright (C) Andrew Tridgell 1997-1998
  6.    
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2 of the License, or
  10.    (at your option) any later version.
  11.    
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.    
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21. */
  22.  
  23. #include "includes.h"
  24.  
  25.  
  26. #ifdef USE_SYSV_IPC
  27.  
  28. extern int DEBUGLEVEL;
  29.  
  30. #define SHMEM_KEY ((key_t)0x280267)
  31. #define SEMAPHORE_KEY (SHMEM_KEY+2)
  32.  
  33. #define SHM_MAGIC 0x53484100
  34. #define SHM_VERSION 2
  35.  
  36. #ifdef SHM_R
  37. #define IPC_PERMS ((SHM_R | SHM_W) | (SHM_R>>3) | (SHM_R>>6))
  38. #else
  39. #define IPC_PERMS 0644
  40. #endif
  41.  
  42.  
  43. #ifdef SECURE_SEMAPHORES
  44. /* secure semaphores are slow because we have to do a become_root()
  45.    on every call! */
  46. #define SEMAPHORE_PERMS IPC_PERMS
  47. #else
  48. #define SEMAPHORE_PERMS 0666
  49. #endif
  50.  
  51. #ifdef SEMMSL
  52. #define SHMEM_HASH_SIZE (SEMMSL-1)
  53. #else
  54. #define SHMEM_HASH_SIZE 63
  55. #endif
  56.  
  57. #define MIN_SHM_SIZE 0x1000
  58.  
  59. static int shm_id;
  60. static int sem_id;
  61. static int shm_size;
  62. static int hash_size;
  63. static int global_lock_count;
  64.  
  65. struct ShmHeader {
  66.    int shm_magic;
  67.    int shm_version;
  68.    int total_size;    /* in bytes */
  69.    BOOL consistent;
  70.    int first_free_off;
  71.    int userdef_off;    /* a userdefined offset. can be used to store
  72.               root of tree or list */
  73.    struct {        /* a cell is a range of bytes of sizeof(struct
  74.                ShmBlockDesc) size */
  75.        int cells_free;
  76.        int cells_used;
  77.        int cells_system; /* number of cells used as allocated
  78.                 block descriptors */
  79.    } statistics;
  80. };
  81.  
  82. #define SHM_NOT_FREE_OFF (-1)
  83. struct ShmBlockDesc
  84. {
  85.    int next;    /* offset of next block in the free list or
  86.            SHM_NOT_FREE_OFF when block in use */
  87.    int size;   /* user size in BlockDescSize units */
  88. };
  89.  
  90. #define    EOList_Addr    NULL
  91. #define EOList_Off      (0)
  92.  
  93. #define    CellSize    sizeof(struct ShmBlockDesc)
  94.  
  95. /* HeaderSize aligned on a 8 byte boundary */
  96. #define    AlignedHeaderSize ((sizeof(struct ShmHeader)+7) & ~7)
  97.  
  98. static struct ShmHeader *shm_header_p = NULL;
  99. static BOOL shm_initialize_called = False;
  100.  
  101. static int read_only;
  102.  
  103. static BOOL sem_change(int i, int op)
  104. {
  105. #ifdef SECURE_SEMAPHORES
  106.     extern struct current_user current_user;
  107.     int became_root=0;
  108. #endif
  109.     struct sembuf sb;
  110.     int ret;
  111.  
  112.     if (read_only) return True;
  113.  
  114. #ifdef SECURE_SEMAPHORES
  115.     if (current_user.uid != 0) {
  116.         become_root(0);
  117.         became_root = 1;
  118.     }
  119. #endif
  120.  
  121.     sb.sem_num = i;
  122.     sb.sem_op = op;
  123.     sb.sem_flg = 0;
  124.  
  125.     ret = semop(sem_id, &sb, 1);
  126.  
  127.     if (ret != 0) {
  128.         DEBUG(0,("ERROR: sem_change(%d,%d) failed (%s)\n", 
  129.              i, op, strerror(errno)));
  130.     }
  131.  
  132. #ifdef SECURE_SEMAPHORES
  133.     if (became_root) {
  134.         unbecome_root(0);
  135.     }
  136. #endif
  137.  
  138.     return ret == 0;
  139. }
  140.  
  141. static BOOL global_lock(void)
  142. {
  143.     global_lock_count++;
  144.     if (global_lock_count == 1)
  145.         return sem_change(0, -1);
  146.     return True;
  147. }
  148.  
  149. static BOOL global_unlock(void)
  150. {
  151.     global_lock_count--;
  152.     if (global_lock_count == 0)
  153.         return sem_change(0, 1);
  154.     return True;
  155. }
  156.  
  157. static void *shm_offset2addr(int offset)
  158. {
  159.    if (offset == 0 )
  160.       return (void *)(0);
  161.    
  162.    if (!shm_header_p)
  163.       return (void *)(0);
  164.    
  165.    return (void *)((char *)shm_header_p + offset);
  166. }
  167.  
  168. static int shm_addr2offset(void *addr)
  169. {
  170.    if (!addr)
  171.       return 0;
  172.    
  173.    if (!shm_header_p)
  174.       return 0;
  175.    
  176.    return (int)((char *)addr - (char *)shm_header_p);
  177. }
  178.  
  179.  
  180. static int shm_alloc(int size)
  181. {
  182.     unsigned num_cells ;
  183.     struct ShmBlockDesc *scanner_p;
  184.     struct ShmBlockDesc *prev_p;
  185.     struct ShmBlockDesc *new_p;
  186.     int result_offset;
  187.    
  188.    
  189.     if (!shm_header_p) {
  190.         /* not mapped yet */
  191.         DEBUG(0,("ERROR shm_alloc : shmem not mapped\n"));
  192.         return 0;
  193.     }
  194.     
  195.     global_lock();
  196.     
  197.     if (!shm_header_p->consistent) {
  198.         DEBUG(0,("ERROR shm_alloc : shmem not consistent\n"));
  199.         global_unlock();
  200.         return 0;
  201.     }
  202.     
  203.     /* calculate the number of cells */
  204.     num_cells = (size + (CellSize-1)) / CellSize;
  205.     
  206.     /* set start of scan */
  207.     prev_p = (struct ShmBlockDesc *)shm_offset2addr(shm_header_p->first_free_off);
  208.     scanner_p =    prev_p ;
  209.     
  210.     /* scan the free list to find a matching free space */
  211.     while ((scanner_p != EOList_Addr) && (scanner_p->size < num_cells)) {
  212.         prev_p = scanner_p;
  213.         scanner_p = (struct ShmBlockDesc *)shm_offset2addr(scanner_p->next);
  214.     }
  215.    
  216.     /* at this point scanner point to a block header or to the end of
  217.        the list */
  218.     if (scanner_p == EOList_Addr) {
  219.         DEBUG(0,("ERROR shm_alloc : alloc of %d bytes failed\n",size));
  220.         global_unlock();
  221.         return (0);
  222.     }
  223.    
  224.     /* going to modify shared mem */
  225.     shm_header_p->consistent = False;
  226.     
  227.     /* if we found a good one : scanner == the good one */
  228.     if (scanner_p->size > num_cells + 2) {
  229.         /* Make a new one */
  230.         new_p = scanner_p + 1 + num_cells;
  231.         new_p->size = scanner_p->size - (num_cells + 1);
  232.         new_p->next = scanner_p->next;
  233.         scanner_p->size = num_cells;
  234.         scanner_p->next = shm_addr2offset(new_p);
  235.  
  236.         shm_header_p->statistics.cells_free -= 1;
  237.         shm_header_p->statistics.cells_system += 1;
  238.     }
  239.  
  240.     /* take it from the free list */
  241.     if (prev_p == scanner_p) {
  242.         shm_header_p->first_free_off = scanner_p->next;
  243.     } else {
  244.         prev_p->next = scanner_p->next;
  245.     }
  246.     shm_header_p->statistics.cells_free -= scanner_p->size;
  247.     shm_header_p->statistics.cells_used += scanner_p->size;
  248.  
  249.     result_offset = shm_addr2offset(&(scanner_p[1]));
  250.     scanner_p->next = SHM_NOT_FREE_OFF;
  251.  
  252.     /* end modification of shared mem */
  253.     shm_header_p->consistent = True;
  254.  
  255.     global_unlock();
  256.     
  257.     DEBUG(6,("shm_alloc : allocated %d bytes at offset %d\n",
  258.          size,result_offset));
  259.  
  260.     return result_offset;
  261. }   
  262.  
  263. static void shm_solve_neighbors(struct ShmBlockDesc *head_p )
  264. {
  265.     struct ShmBlockDesc *next_p;
  266.    
  267.     /* Check if head_p and head_p->next are neighbors and if so
  268.            join them */
  269.     if ( head_p == EOList_Addr ) return ;
  270.     if ( head_p->next == EOList_Off ) return ;
  271.    
  272.     next_p = (struct ShmBlockDesc *)shm_offset2addr(head_p->next);
  273.     if ((head_p + head_p->size + 1) == next_p) {
  274.         head_p->size += next_p->size + 1; /* adapt size */
  275.         head_p->next = next_p->next; /* link out */
  276.       
  277.         shm_header_p->statistics.cells_free += 1;
  278.         shm_header_p->statistics.cells_system -= 1;
  279.     }
  280. }
  281.  
  282.  
  283. static BOOL shm_free(int offset)
  284. {
  285.     struct ShmBlockDesc *header_p; /* pointer to header of
  286.                       block to free */
  287.     struct ShmBlockDesc *scanner_p; /* used to scan the list */
  288.     struct ShmBlockDesc *prev_p; /* holds previous in the
  289.                     list */
  290.    
  291.     if (!shm_header_p) {
  292.         /* not mapped yet */
  293.         DEBUG(0,("ERROR shm_free : shmem not mapped\n"));
  294.         return False;
  295.     }
  296.     
  297.     global_lock();
  298.     
  299.     if (!shm_header_p->consistent) {
  300.         DEBUG(0,("ERROR shm_free : shmem not consistent\n"));
  301.         global_unlock();
  302.         return False;
  303.     }
  304.     
  305.     /* make pointer to header of block */
  306.     header_p = ((struct ShmBlockDesc *)shm_offset2addr(offset) - 1); 
  307.     
  308.     if (header_p->next != SHM_NOT_FREE_OFF) {
  309.         DEBUG(0,("ERROR shm_free : bad offset (%d)\n",offset));
  310.         global_unlock();
  311.         return False;
  312.     }
  313.     
  314.     /* find a place in the free_list to put the header in */
  315.     
  316.     /* set scanner and previous pointer to start of list */
  317.     prev_p = (struct ShmBlockDesc *)
  318.         shm_offset2addr(shm_header_p->first_free_off);
  319.     scanner_p = prev_p ;
  320.     
  321.     while ((scanner_p != EOList_Addr) && 
  322.            (scanner_p < header_p)) { 
  323.         /* while we didn't scan past its position */
  324.         prev_p = scanner_p ;
  325.         scanner_p = (struct ShmBlockDesc *)
  326.             shm_offset2addr(scanner_p->next);
  327.     }
  328.     
  329.     shm_header_p->consistent = False;
  330.     
  331.     DEBUG(6,("shm_free : freeing %d bytes at offset %d\n",
  332.          header_p->size*CellSize,offset));
  333.     
  334.     if (scanner_p == prev_p) {
  335.         shm_header_p->statistics.cells_free += header_p->size;
  336.         shm_header_p->statistics.cells_used -= header_p->size;
  337.         
  338.         /* we must free it at the beginning of the list */
  339.         shm_header_p->first_free_off = shm_addr2offset(header_p);
  340.         /* set the free_list_pointer to this block_header */
  341.         
  342.         /* scanner is the one that was first in the list */
  343.         header_p->next = shm_addr2offset(scanner_p);
  344.         shm_solve_neighbors(header_p); 
  345.         
  346.         shm_header_p->consistent = True;
  347.     } else {
  348.         shm_header_p->statistics.cells_free += header_p->size;
  349.         shm_header_p->statistics.cells_used -= header_p->size;
  350.         
  351.         prev_p->next = shm_addr2offset(header_p);
  352.         header_p->next = shm_addr2offset(scanner_p);
  353.         shm_solve_neighbors(header_p) ;
  354.         shm_solve_neighbors(prev_p) ;
  355.        
  356.         shm_header_p->consistent = True;
  357.     }
  358.  
  359.     global_unlock();
  360.     return True;
  361. }
  362.  
  363.  
  364. /* 
  365.  * Function to create the hash table for the share mode entries. Called
  366.  * when smb shared memory is global locked.
  367.  */
  368. static BOOL shm_create_hash_table(unsigned int hash_entries)
  369. {
  370.     int size = hash_entries * sizeof(int);
  371.  
  372.     global_lock();
  373.     shm_header_p->userdef_off = shm_alloc(size);
  374.  
  375.     if(shm_header_p->userdef_off == 0) {
  376.         DEBUG(0,("shm_create_hash_table: Failed to create hash table of size %d\n",
  377.              size));
  378.         global_unlock();
  379.         return False;
  380.     }
  381.  
  382.     /* Clear hash buckets. */
  383.     memset(shm_offset2addr(shm_header_p->userdef_off), '\0', size);
  384.     global_unlock();
  385.     return True;
  386. }
  387.  
  388.  
  389. static BOOL shm_validate_header(int size)
  390. {
  391.     if(!shm_header_p) {
  392.         /* not mapped yet */
  393.         DEBUG(0,("ERROR shm_validate_header : shmem not mapped\n"));
  394.         return False;
  395.     }
  396.    
  397.     if(shm_header_p->shm_magic != SHM_MAGIC) {
  398.         DEBUG(0,("ERROR shm_validate_header : bad magic\n"));
  399.         return False;
  400.     }
  401.  
  402.     if(shm_header_p->shm_version != SHM_VERSION) {
  403.         DEBUG(0,("ERROR shm_validate_header : bad version %X\n",
  404.              shm_header_p->shm_version));
  405.         return False;
  406.     }
  407.    
  408.     if(shm_header_p->total_size != size) {
  409.         DEBUG(0,("ERROR shmem size mismatch (old = %d, new = %d)\n",
  410.              shm_header_p->total_size,size));
  411.         return False;
  412.     }
  413.  
  414.     if(!shm_header_p->consistent) {
  415.         DEBUG(0,("ERROR shmem not consistent\n"));
  416.         return False;
  417.     }
  418.     return True;
  419. }
  420.  
  421.  
  422. static BOOL shm_initialize(int size)
  423. {
  424.     struct ShmBlockDesc * first_free_block_p;
  425.     
  426.     DEBUG(5,("shm_initialize : initializing shmem size %d\n",size));
  427.    
  428.     if( !shm_header_p ) {
  429.         /* not mapped yet */
  430.         DEBUG(0,("ERROR shm_initialize : shmem not mapped\n"));
  431.         return False;
  432.     }
  433.    
  434.     shm_header_p->shm_magic = SHM_MAGIC;
  435.     shm_header_p->shm_version = SHM_VERSION;
  436.     shm_header_p->total_size = size;
  437.     shm_header_p->first_free_off = AlignedHeaderSize;
  438.     shm_header_p->userdef_off = 0;
  439.     
  440.     first_free_block_p = (struct ShmBlockDesc *)
  441.         shm_offset2addr(shm_header_p->first_free_off);
  442.     first_free_block_p->next = EOList_Off;
  443.     first_free_block_p->size = 
  444.         (size - (AlignedHeaderSize+CellSize))/CellSize;   
  445.     shm_header_p->statistics.cells_free = first_free_block_p->size;
  446.     shm_header_p->statistics.cells_used = 0;
  447.     shm_header_p->statistics.cells_system = 1;
  448.    
  449.     shm_header_p->consistent = True;
  450.    
  451.     shm_initialize_called = True;
  452.  
  453.     return True;
  454. }
  455.    
  456. static BOOL shm_close( void )
  457. {
  458.     return True;
  459. }
  460.  
  461.  
  462. static int shm_get_userdef_off(void)
  463. {
  464.    if (!shm_header_p)
  465.       return 0;
  466.    else
  467.       return shm_header_p->userdef_off;
  468. }
  469.  
  470.  
  471. /*******************************************************************
  472.   Lock a particular hash bucket entry.
  473.   ******************************************************************/
  474. static BOOL shm_lock_hash_entry(unsigned int entry)
  475. {
  476.     return sem_change(entry+1, -1);
  477. }
  478.  
  479. /*******************************************************************
  480.   Unlock a particular hash bucket entry.
  481.   ******************************************************************/
  482. static BOOL shm_unlock_hash_entry(unsigned int entry)
  483. {
  484.     return sem_change(entry+1, 1);
  485. }
  486.  
  487.  
  488. /*******************************************************************
  489.   Gather statistics on shared memory usage.
  490.   ******************************************************************/
  491. static BOOL shm_get_usage(int *bytes_free,
  492.               int *bytes_used,
  493.               int *bytes_overhead)
  494. {
  495.     if(!shm_header_p) {
  496.         /* not mapped yet */
  497.         DEBUG(0,("ERROR shm_free : shmem not mapped\n"));
  498.         return False;
  499.     }
  500.  
  501.     *bytes_free = shm_header_p->statistics.cells_free * CellSize;
  502.     *bytes_used = shm_header_p->statistics.cells_used * CellSize;
  503.     *bytes_overhead = shm_header_p->statistics.cells_system * CellSize + 
  504.         AlignedHeaderSize;
  505.     
  506.     return True;
  507. }
  508.  
  509.  
  510. /*******************************************************************
  511. hash a number into a hash_entry
  512.   ******************************************************************/
  513. static unsigned shm_hash_size(void)
  514. {
  515.     return hash_size;
  516. }
  517.  
  518.  
  519. static struct shmem_ops shmops = {
  520.     shm_close,
  521.     shm_alloc,
  522.     shm_free,
  523.     shm_get_userdef_off,
  524.     shm_offset2addr,
  525.     shm_addr2offset,
  526.     shm_lock_hash_entry,
  527.     shm_unlock_hash_entry,
  528.     shm_get_usage,
  529.     shm_hash_size,
  530. };
  531.  
  532. /*******************************************************************
  533.   open the shared memory
  534.   ******************************************************************/
  535. struct shmem_ops *sysv_shm_open(int ronly)
  536. {
  537.     BOOL created_new = False;
  538.     BOOL other_processes;
  539.     struct shmid_ds shm_ds;
  540.     struct semid_ds sem_ds;
  541.     union semun su;
  542.     int i;
  543.     int pid;
  544.  
  545. #ifdef LINUX
  546.     if (sizeof(shm_ds) == 52) {
  547.         DEBUG(0,("WARNING: You probably have a broken set of glibc2 include files - disabling sysv shared memory\n"));
  548.         return NULL;
  549.     }
  550. #endif
  551.  
  552.     read_only = ronly;
  553.  
  554.     shm_size = lp_shmem_size();
  555.  
  556.     DEBUG(4,("Trying sysv shmem open of size %d\n", shm_size));
  557.  
  558.     /* first the semaphore */
  559.     sem_id = semget(SEMAPHORE_KEY, 0, 0);
  560.     if (sem_id == -1) {
  561.         if (read_only) return NULL;
  562.  
  563.         hash_size = SHMEM_HASH_SIZE;
  564.  
  565.         while (hash_size > 1) {
  566.             sem_id = semget(SEMAPHORE_KEY, hash_size+1, 
  567.                     IPC_CREAT|IPC_EXCL| SEMAPHORE_PERMS);
  568.             if (sem_id != -1 || 
  569.                 (errno != EINVAL && errno != ENOSPC)) break;
  570.             hash_size -= 5;
  571.         }
  572.  
  573.         if (sem_id == -1) {
  574.             DEBUG(0,("Can't create or use semaphore %s\n", 
  575.                  strerror(errno)));
  576.         }   
  577.  
  578.         if (sem_id != -1) {
  579.             su.val = 1;
  580.             for (i=0;i<hash_size+1;i++) {
  581.                 if (semctl(sem_id, i, SETVAL, su) != 0) {
  582.                     DEBUG(1,("Failed to init semaphore %d\n", i));
  583.                 }
  584.             }
  585.         }
  586.     }
  587.     if (shm_id == -1) {
  588.         sem_id = semget(SEMAPHORE_KEY, 0, 0);
  589.     }
  590.     if (sem_id == -1) {
  591.         DEBUG(0,("Can't create or use semaphore %s\n", 
  592.              strerror(errno)));
  593.         return NULL;
  594.     }   
  595.  
  596.     su.buf = &sem_ds;
  597.     if (semctl(sem_id, 0, IPC_STAT, su) != 0) {
  598.         DEBUG(0,("ERROR shm_open : can't IPC_STAT\n"));
  599.     }
  600.     hash_size = sem_ds.sem_nsems-1;
  601.  
  602.     if (!read_only) {
  603.         if (sem_ds.sem_perm.cuid != 0 || sem_ds.sem_perm.cgid != 0) {
  604.             DEBUG(0,("ERROR: root did not create the semaphore\n"));
  605.             return NULL;
  606.         }
  607.  
  608.         if (semctl(sem_id, 0, GETVAL, su) == 0 &&
  609.             !process_exists((pid=semctl(sem_id, 0, GETPID, su)))) {
  610.             DEBUG(0,("WARNING: clearing global IPC lock set by dead process %d\n",
  611.                  pid));
  612.             su.val = 1;
  613.             if (semctl(sem_id, 0, SETVAL, su) != 0) {
  614.                 DEBUG(0,("ERROR: Failed to clear global lock\n"));
  615.             }
  616.         }
  617.  
  618.         sem_ds.sem_perm.mode = SEMAPHORE_PERMS;
  619.         if (semctl(sem_id, 0, IPC_SET, su) != 0) {
  620.             DEBUG(0,("ERROR shm_open : can't IPC_SET\n"));
  621.         }
  622.     }
  623.  
  624.     
  625.     
  626.     if (!global_lock())
  627.         return NULL;
  628.  
  629.  
  630.     for (i=1;i<hash_size+1;i++) {
  631.         if (semctl(sem_id, i, GETVAL, su) == 0 && 
  632.             !process_exists((pid=semctl(sem_id, i, GETPID, su)))) {
  633.             DEBUG(1,("WARNING: clearing IPC lock %d set by dead process %d\n", 
  634.                  i, pid));
  635.             su.val = 1;
  636.             if (semctl(sem_id, i, SETVAL, su) != 0) {
  637.                 DEBUG(0,("ERROR: Failed to clear IPC lock %d\n", i));
  638.             }
  639.         }
  640.     }
  641.     
  642.     /* try to use an existing key */
  643.     shm_id = shmget(SHMEM_KEY, shm_size, 0);
  644.     
  645.     /* if that failed then create one */
  646.     if (shm_id == -1) {
  647.         if (read_only) return NULL;
  648.         while (shm_size > MIN_SHM_SIZE) {
  649.             shm_id = shmget(SHMEM_KEY, shm_size, 
  650.                     IPC_CREAT | IPC_EXCL | IPC_PERMS);
  651.             if (shm_id != -1 || 
  652.                 (errno != EINVAL && errno != ENOSPC)) break;
  653.             shm_size *= 0.8;
  654.         }
  655.         created_new = (shm_id != -1);
  656.     }
  657.     
  658.     if (shm_id == -1) {
  659.         DEBUG(0,("Can't create or use IPC area\n"));
  660.         global_unlock();
  661.         return NULL;
  662.     }   
  663.     
  664.     
  665.     shm_header_p = (struct ShmHeader *)shmat(shm_id, 0, 
  666.                          read_only?SHM_RDONLY:0);
  667.     if ((long)shm_header_p == -1) {
  668.         DEBUG(0,("Can't attach to IPC area\n"));
  669.         global_unlock();
  670.         return NULL;
  671.     }
  672.  
  673.     /* to find out if some other process is already mapping the file,
  674.        we use a registration file containing the processids of the file
  675.        mapping processes */
  676.     if (shmctl(shm_id, IPC_STAT, &shm_ds) != 0) {
  677.         DEBUG(0,("ERROR shm_open : can't IPC_STAT\n"));
  678.     }
  679.  
  680.     if (!read_only) {
  681.         if (shm_ds.shm_perm.cuid != 0 || shm_ds.shm_perm.cgid != 0) {
  682.             DEBUG(0,("ERROR: root did not create the shmem\n"));
  683.             global_unlock();
  684.             return NULL;
  685.         }
  686.     }
  687.  
  688.     shm_size = shm_ds.shm_segsz;
  689.  
  690.     other_processes = (shm_ds.shm_nattch > 1);
  691.  
  692.     if (!read_only && !other_processes) {
  693.         memset((char *)shm_header_p, 0, shm_size);
  694.         shm_initialize(shm_size);
  695.         shm_create_hash_table(hash_size);
  696.         DEBUG(3,("Initialised IPC area of size %d\n", shm_size));
  697.     } else if (!shm_validate_header(shm_size)) {
  698.         /* existing file is corrupt, samba admin should remove
  699.                    it by hand */
  700.         DEBUG(0,("ERROR shm_open : corrupt IPC area - remove it!\n"));
  701.         global_unlock();
  702.         return NULL;
  703.     }
  704.    
  705.     global_unlock();
  706.     return &shmops;
  707. }
  708.  
  709.  
  710.  
  711. #else 
  712.  int ipc_dummy_procedure(void)
  713. {return 0;}
  714. #endif 
  715.