|
|
1.1 root 1: /*
2: * File: shm1.c
3: *
4: * Purpose: System V Compatible Shared Memory Device Driver
5: *
6: * $Log: shm1.c,v $
7: * Revision 2.3 93/08/09 13:46:24 bin
8: * Kernel 82 changes
9: *
10: * Revision 2.2 93/07/26 15:32:18 nigel
11: * Nigel's R80
12: *
13: * Revision 1.3 93/04/14 10:23:10 root
14: * r75
15: *
16: */
17:
18: /*
19: * ----------------------------------------------------------------------
20: * Includes.
21: */
22: #include <sys/coherent.h>
23: #include <sys/types.h>
24: #include <sys/proc.h>
25: #include <sys/ipc.h>
26: #include <sys/shm.h>
27: #include <sys/errno.h>
28:
29: /*
30: * ----------------------------------------------------------------------
31: * Definitions.
32: * Constants.
33: * Macros with argument lists.
34: * Typedefs.
35: * Enums.
36: */
37: #define SHMBASE 0x80000000 /* Base shared memory address */
38: /* These macros should be somewhere in the headers ???*/
39: #define DATAST 0x400000 /* Start of the data virtual address */
40: #define DATAEND 0x7FFFFF /* End of the data virtual address */
41: #define STACKST 0x7C000000 /* Start of the stack */
42: #define STACKEN 0x7FFFFFFF /* End of the stack virtual address */
43:
44: /*
45: * ----------------------------------------------------------------------
46: * Functions.
47: * Import Functions.
48: * Export Functions.
49: * Local Functions.
50: */
51: extern SEG *shmAlloc(); /* shm0.c */
52: char *ushmat();
53: int ushmdt();
54: int ushmctl();
55: int ushmget();
56: int iShmPerm(); /* Check permissions */
57: caddr_t vCheckReqAdd(); /* Check attach address for shmat */
58: /*
59: * ----------------------------------------------------------------------
60: * Global Data.
61: * Import Variables.
62: * Export Variables.
63: * Local Variables.
64: */
65:
66: /* Configurable variables - see /etc/conf/mtune. */
67: extern int SHMMNI;
68: extern int SHMMAX;
69:
70: struct shmid_ds *shmids = NULL; /* Array of shared memory segments */
71: SEG **shmsegs; /* Array of pointers to segments */
72: /*
73: * ----------------------------------------------------------------------
74: * Code.
75: */
76:
77: /*
78: * Shmctl - Shared Memory Control Operations.
79: */
80: int
81: ushmctl(iShmId, iCmd, pstShmId)
82: int iShmId, /* Shared memory id */
83: iCmd; /* Command */
84: struct shmid_ds *pstShmId; /* User shmid_ds buffer */
85: {
86: register struct shmid_ds *rstIdp;
87: int iRet = 0;
88:
89: /* Check if id is in proper range. */
90: if (iShmId >= SHMMNI || iShmId < 0) {
91: u.u_error = EINVAL;
92: return;
93: }
94: /* Check we did alloc. All allocatable arrays are alloced after
95: * the first ~correct usage of shmget.
96: */
97: if (shmids == NULL) {
98: u.u_error = EINVAL;
99: return;
100: }
101: rstIdp = &shmids[iShmId]; /* Requested segment */
102:
103: /* Check if segment is in used */
104: if ((rstIdp->shm_perm.mode & IPC_ALLOC) == 0) {
105: u.u_error = EINVAL;
106: return;
107: }
108:
109: switch (iCmd) {
110: case IPC_STAT:
111: /* Check read permission for stat. */
112: if (iShmPerm((rstIdp), SHM_R)) {
113: u.u_error = EACCES;
114: return;
115: }
116: /* Check if user gives a valid buffer */
117: if (!useracc(pstShmId, sizeof(struct shmid_ds), 1)) {
118: u.u_error = EFAULT;
119: return;
120: }
121: /* kucopy will set u_error if error occurs */
122: kucopy(rstIdp, pstShmId, sizeof(struct shmid_ds));
123: break;
124:
125: case IPC_SET:
126: if ((u.u_uid != 0) && (u.u_uid != rstIdp->shm_perm.uid) &&
127: (u.u_uid != rstIdp->shm_perm.cuid)) {
128: u.u_error = EPERM;
129: iRet = -1;
130: break;
131: }
132: rstIdp->shm_perm.uid = getuwd(&(pstShmId->shm_perm.uid));
133: rstIdp->shm_perm.gid = getuwd(&(pstShmId->shm_perm.gid));
134: rstIdp->shm_perm.mode &= ~0777;
135: rstIdp->shm_perm.mode |= getuwd(&(pstShmId->shm_perm.mode))
136: & 0777;
137: break;
138:
139: case IPC_RMID:
140: if ((u.u_uid != 0) && (u.u_uid != rstIdp->shm_perm.uid) &&
141: (u.u_uid != rstIdp->shm_perm.cuid)) {
142: u.u_error = EPERM;
143: iRet = -1;
144: break;
145: }
146:
147: /* SVR3 allows removing an attached segment. Even worse, the
148: * process that has the segment attached can keep using it.
149: * Some buggy third party software uses this "feature".
150: * So, we have to make it available too;-(
151: */
152: rstIdp->shm_perm.seq = 0;
153: rstIdp->shm_perm.mode = 0;
154:
155: /* If segment is attached, set flag to be removed */
156: if (rstIdp->shm_nattch > 0)
157: shmsegs[iShmId]->s_flags |= SRFBERM;
158: else /* remove it otherwise */
159: shmFree(shmsegs[iShmId]);
160: shmsegs[iShmId] = NULL;
161: break;
162:
163: /* SHM_LOCK and SHM_UNLOCK: lock/unlock shared memory segement
164: * in core. Is not a part of iBCS2.
165: * Has no meaning for current 4.0.* release of COHERENT.
166: * Have been done for binary portability.
167: */
168: case SHM_LOCK:
169: if (!u.u_uid) {
170: u.u_error = EPERM;
171: return;
172: }
173: break;
174: case SHM_UNLOCK:
175: if (!u.u_uid) {
176: u.u_error = EPERM;
177: return;
178: }
179: break;
180:
181: default:
182: u.u_error = EINVAL;
183: iRet = -1;
184: }
185:
186: return iRet;
187: }
188:
189: /*
190: * Shmget - Get Shared Memory Segment
191: * Return shared memory id if succed, -1 and set u_error otheriwse.
192: */
193: int
194: ushmget(kShmKey, iShmSize, iShmFlg)
195: key_t kShmKey; /* Shared memory key */
196: int iShmSize; /* Shared memory segment size */
197: int iShmFlg; /* Flags */
198: {
199: register struct shmid_ds *rstShmId; /* Work pointer */
200: register struct shmid_ds *rstOldest = 0;/* Oldest free segment */
201: register int i; /* Loop index */
202: SEG *pstSeg;
203:
204: /* Check the requested segment size */
205: if (iShmSize < 0 || iShmSize > SHMMAX) {
206: u.u_error = EINVAL;
207: return;
208: }
209: /* Init the shared memory on the first shmget. */
210: if (shmids == NULL)
211: if (shminit()) {
212: u.u_error = ENOSPC;
213: return;
214: }
215:
216: /* Search for desire shared memory segment. */
217: for (rstShmId = shmids, i = 0; i < SHMMNI; i++, rstShmId++) {
218: /* If segment is not alloced, we will look for the oldest
219: * free segment. We will use it to create a new one.
220: * The "oldest" will increase (a little) system reliability.
221: */
222: if ((rstShmId->shm_perm.mode & IPC_ALLOC) == 0) {
223: if ((rstOldest == NULL) ||
224: (rstOldest->shm_ctime > rstShmId->shm_ctime))
225: rstOldest = rstShmId;
226: continue;
227: }
228: /* Do we need a new segment? */
229: if (kShmKey == IPC_PRIVATE)
230: continue;
231: /* Keep going if key is different. The key is an element
232: * number of shmids
233: */
234: if (kShmKey != rstShmId->shm_perm.key)
235: continue;
236:
237: /* We found the segment with requested key. */
238:
239: /* Request was for the exclusive segment should fail. */
240: if ((iShmFlg & IPC_CREAT) && (iShmFlg & IPC_EXCL)) {
241: u.u_error = EEXIST;
242: return;
243: }
244:
245: /* Check the requested size */
246: if (rstShmId->shm_segsz < iShmSize) {
247: u.u_error = EINVAL;
248: return;
249: }
250:
251: /* Check permissions */
252: if (iShmPerm(rstShmId, iShmFlg))
253: return;
254: return i;
255: }
256:
257: /* We need to create a new segment */
258: if (rstOldest == 0) { /* Check system limits */
259: u.u_error = ENOSPC;
260: return;
261: }
262: if (!(iShmFlg & IPC_CREAT)) {
263: u.u_error = ENOENT;
264: return;
265: }
266: rstShmId = rstOldest;
267: /* Allocate a new shared memory segment */
268: pstSeg = shmAlloc(iShmSize);
269: if (pstSeg == NULL) {
270: u.u_error = ENOSPC;
271: return;
272: }
273: /* Save it in shmsegs */
274: shmsegs[rstShmId - shmids] = pstSeg;
275:
276: rstShmId->shm_perm.seq = (unsigned short) (rstShmId - shmids);
277: rstShmId->shm_segsz = iShmSize;
278: rstShmId->shm_atime = 0;
279: rstShmId->shm_dtime = 0;
280: rstShmId->shm_ctime = timer.t_time;
281: rstShmId->shm_cpid = SELF->p_pid;
282: rstShmId->shm_perm.cuid = rstShmId->shm_perm.uid = u.u_uid;
283: rstShmId->shm_perm.cgid = rstShmId->shm_perm.gid = u.u_gid;
284: rstShmId->shm_perm.mode = (iShmFlg & 0777) | IPC_ALLOC;
285: rstShmId->shm_perm.key = kShmKey;
286:
287: if (kShmKey == IPC_PRIVATE)
288: rstShmId->shm_perm.mode |= SHM_DEST;
289:
290: return rstShmId - shmids;
291: }
292:
293: /*
294: * Allocate space for shared memory data structures.
295: */
296: int
297: shminit()
298: {
299: shmids = (struct shmid_ds *) kalloc(sizeof(struct shmid_ds) * SHMMNI);
300: if (shmids == NULL)
301: return -1;
302:
303: /* Allocate array of shared memory segments. We do not have to
304: * initalise it
305: */
306: shmsegs = (SEG *) kalloc(sizeof(SEG *) * SHMMNI);
307: if (shmsegs == NULL)
308: return -1;
309: return 0;
310: }
311:
312: /*
313: * Attach shared memory segment.
314: */
315: char *
316: ushmat(iSysId, pcShmAddr, iShmFlg)
317: int iSysId; /* System segment id */
318: char *pcShmAddr; /* Address to attach */
319: int iShmFlg; /* Flags */
320: {
321: register PROC *rpstProc; /* Current process */
322: register struct sr *rpstSr; /* Shared memory segments */
323: struct sr *pstSrTmp;
324: SEG *pstSegSh; /* Segment to attach */
325: struct shmid_ds *pstShmId; /* Pointer to a system segment*/
326: unsigned int uSegId; /* Segment id */
327: caddr_t vAttAddr; /* Address to attach */
328: int i; /* Loop index */
329: int iReadOnly = 0; /* 1 - read only, 0 - rw */
330:
331: /* Check if iSysId is a valid shared memory id. */
332: if (iSysId < 0 || iSysId > SHMMNI) {
333: u.u_error = EINVAL;
334: return;
335: }
336: /* Do we really have this segment? */
337: pstShmId = shmids + iSysId;
338: if (pstShmId->shm_perm.seq != iSysId) {
339: u.u_error = EINVAL;
340: return;
341: }
342: /* Check permissions. */
343: if (iShmFlg & SHM_RDONLY)
344: iReadOnly = 1;
345: if (iReadOnly) {
346: if (iShmPerm(pstShmId, 0444)) {
347: u.u_error = EACCES;
348: return;
349: }
350: } else {
351: if (iShmPerm(pstShmId, 0666)) {
352: u.u_error = EACCES;
353: return;
354: }
355: }
356: /* Check if process has free shm index. */
357: rpstProc = SELF;
358: /* We will go through all NSHMSEG segments to see if any is free. */
359: for (rpstSr = rpstProc->p_shmsr; rpstSr < rpstProc->p_shmsr + NSHMSEG;
360: rpstSr++)
361: if (rpstSr->sr_segp == NULL)
362: break;
363: /* The segment id is just an element number. */
364: uSegId = rpstSr - rpstProc->p_shmsr;
365: /* If segment id is >= NSHMSEG we cannot attach any new segment. */
366: if (uSegId >= NSHMSEG) {
367: u.u_error = EMFILE;
368: return;
369: }
370: /* Get the pointer to the shared memory segment */
371: pstSegSh = shmsegs[iSysId];
372:
373: /* Find an address to attach.
374: * There are two cases: process does not request the address,
375: * process requests the address.
376: * In the first case we have to take the first available free address.
377: * We will try to put a free page between the segments.
378: * In the second case we have to check if address is an available and
379: * attach to this address.
380: */
381: /* First case. We have to find a free address. */
382: if (pcShmAddr == NULL) {
383: /* Find a free space to attach. */
384: for (pstSrTmp = rpstProc->p_shmsr, i = 0; i < NSHMSEG;
385: i++, pstSrTmp++)
386: if (pstSrTmp->sr_base == NULL)
387: break;
388: /* Check limit of attaches per process */
389: if (i >= NSHMSEG) {
390: u.u_error = EINVAL;
391: return;
392: }
393: /* We will use the addresses starting from SHMBASE.
394: * Each new address can be SHMMAX + NBPC appart.
395: */
396: vAttAddr = (caddr_t) (SHMBASE + i * (SHMMAX + NBPC));
397: } else {
398: /* Requst attach to a specific address. This is none portable
399: * way to use a shared memory.
400: */
401: if ((vAttAddr = vCheckReqAdd(pcShmAddr, iReadOnly)) < 0) {
402: printf("%s: attempt attach to 0x%x\n",
403: u.u_comm, pcShmAddr);
404: u.u_error = EINVAL;
405: return;
406: }
407: }
408:
409: if (!shmAtt(uSegId, vAttAddr, pstSegSh, iReadOnly)) {
410: u.u_error = EINVAL;
411: return;
412: }
413: pstShmId->shm_lpid = SELF->p_pid;
414: pstShmId->shm_atime = timer.t_time;
415: pstShmId->shm_dtime = 0;
416: pstShmId->shm_nattch = pstSegSh->s_urefc - 1;
417: /* Keep all attached addresses. We will need them for detach */
418: return (char *) vAttAddr;
419: }
420:
421: /*
422: * Check requested address for attach.
423: * Just fail for the first release.
424: */
425: caddr_t
426: vCheckReqAdd(pcAdd, iFlg)
427: char *pcAdd; /* Address to atatch */
428: int iFlg; /* Mode flag */
429: {
430: return (caddr_t) -1;
431: }
432:
433: /*
434: * Check permissions of the shared memory segment.
435: * Return 0 on success, -1 and set errno on error.
436: */
437: int
438: iShmPerm(pstShmId, iShmFlg)
439: struct shmid_ds *pstShmId;
440: int iShmFlg;
441: {
442: int iShmMode;
443:
444: /* We need 9 lower order bits. There is a question what we have to do
445: * if someone sets an execute bits on. At this point we just ignore
446: * them.
447: */
448: iShmMode = iShmFlg & 0666;
449:
450: /* For superuser or if mode is 0 */
451: if (u.u_uid == 0 || !iShmMode)
452: return 0;
453: /* For owner or creator */
454: if (u.u_uid == pstShmId->shm_perm.uid || u.u_uid
455: == pstShmId->shm_perm.cuid) {
456: if ((iShmMode & pstShmId->shm_perm.mode) & 0600)
457: return 0;
458: else {
459: u.u_error = EACCES;
460: return -1;
461: }
462: }
463: /* For group */
464: if (u.u_gid == pstShmId->shm_perm.gid
465: || u.u_gid == pstShmId->shm_perm.cgid) {
466: if ((iShmMode & pstShmId->shm_perm.mode) & 060)
467: return 0;
468: else {
469: u.u_error = EACCES;
470: return -1;
471: }
472: }
473: /* For the rest of the world */
474: if ((iShmMode & pstShmId->shm_perm.mode) & 06)
475: return 0;
476: else {
477: u.u_error = EACCES;
478: return -1;
479: }
480: /* We should never come here */
481: u.u_error = EACCES;
482: return -1;
483: }
484:
485: /*
486: * ushmdt() - Detach shared memory segment.
487: * Find segment number and call shmDetach() (shm0.c).
488: */
489: int
490: ushmdt(cpShmAddr)
491: char *cpShmAddr; /* Pointer to a segment */
492: {
493: register PROC *rpstProc; /* Current process */
494: register struct sr *rpstSr; /* Shared memory segments */
495: int i; /* Loop indexe */
496:
497: rpstProc = SELF; /* Get pointer to our process */
498:
499: /* Go through all segments. */
500: for (rpstSr = rpstProc->p_shmsr, i = 0; i < NSHMSEG; i++, rpstSr++) {
501: if (rpstSr->sr_base == (caddr_t) cpShmAddr) {
502: shmDetach(i);
503: return 0;
504: }
505: }
506:
507: /* We can come here only if we have invalid address */
508: u.u_error = EINVAL;
509: return;
510: }
511:
512: /*
513: * shmSetDs(). Called from shm0.c.
514: *
515: * Given a pointer to shared memory segment, set shmid_ds.
516: */
517: void
518: shmSetDs(rpstSeg)
519: register SEG *rpstSeg;
520: {
521: struct shmid_ds *pstShmId; /* Shared memory structure */
522: int iShmId; /* Shared memory id */
523: int j; /* Loop indexe */
524:
525: for (j = 0; j < SHMMNI; j++)
526: if (shmsegs[j] == rpstSeg)
527: break;
528:
529: /* We should have this segment. */
530: if (j >= SHMMNI) {
531: u.u_error = EINVAL;
532: return;
533: }
534:
535: iShmId = j;
536: pstShmId = shmids + iShmId;
537:
538: /* Set proper values */
539: pstShmId->shm_lpid = SELF->p_pid;
540: pstShmId->shm_dtime = timer.t_time;
541: pstShmId->shm_nattch = rpstSeg->s_urefc - 1;
542: return;
543: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.