Files
QNX/services/mqueue/io_open.c
2025-08-20 19:02:58 +08:00

164 lines
4.4 KiB
C

/*
* $QNXLicenseC:
* Copyright 2007, QNX Software Systems. All Rights Reserved.
*
* You must obtain a written license from and pay applicable license fees to QNX
* Software Systems before you may reproduce, modify or distribute this software,
* or any work that includes all or part of this software. Free development
* licenses are available for evaluation and non-commercial purposes. For more
* information visit http://licensing.qnx.com or email licensing@qnx.com.
*
* This file may contain contributions from others. Please review this entire
* file for other proprietary rights or license notices, as well as the QNX
* Development Suite License Guide at http://licensing.qnx.com/license-guide/
* for other information.
* $
*/
#include "externs.h"
#ifndef PATH_MAX
#define PATH_MAX _POSIX_PATH_MAX
#endif
static int
create_device(char *name, enum _file_type type, MQDEV *dev) {
char path[PATH_MAX];
unsigned *count, limit;
int id;
if (type == _FTYPE_MQUEUE)
count = &num_mq, limit = max_num_mq;
else
count = &num_sem, limit = max_num_sem;
if (*count >= limit)
errno = ENFILE, id = -1;
else if ((id = resmgr_attach(dpp, NULL, strcat(strcpy(path, "/"), name), type, 0, &mq_connect_funcs, &mq_io_funcs, dev)) != -1)
++*count;
return(id);
}
static MQDEV *
check_duplicate(char *name, MQDEV *head) {
while(head != NULL && strcmp(name, head->name)) {
head = head->link;
}
return head;
}
int
io_open(resmgr_context_t *ctp, io_open_t *msg, MQDEV *dev, void *extra) {
struct mq_attr *mqp = extra;
uint32_t *smp = extra;
iofunc_attr_t *attr = &dev->attr;
MQDEV **head;
struct mq_attr mq_attr;
int status;
dev_t rdev;
if(S_ISDIR(dev->attr.mode)) {
// Open on a new/non-existent queue.
if((msg->connect.ioflag & O_CREAT) == 0) {
return ENOENT;
}
// It must have a file_type of _FTYPE_MQUEUE or _FTYPE_SEM
memset(&mq_attr, 0, sizeof(mq_attr));
switch(msg->connect.file_type) {
case _FTYPE_MQUEUE:
rdev = S_INMQ;
head = &mq_dir_attr.link;
if(msg->connect.extra_type == _IO_CONNECT_EXTRA_MQUEUE) {
if (msg->connect.extra_len != sizeof(struct mq_attr))
return(ENOSYS);
if (ctp->info.flags & _NTO_MI_ENDIAN_DIFF) {
ENDIAN_SWAP32(&mqp->mq_maxmsg);
ENDIAN_SWAP32(&mqp->mq_msgsize);
}
if((mq_attr.mq_maxmsg = mqp->mq_maxmsg) <= 0 ||
(mq_attr.mq_msgsize = mqp->mq_msgsize) <= 0) {
return EINVAL;
}
} else {
mq_attr.mq_maxmsg = 1024;
mq_attr.mq_msgsize = 4096;
}
break;
case _FTYPE_SEM:
rdev = S_INSEM;
head = &sem_dir_attr.link;
mq_attr.mq_maxmsg = _POSIX_SEM_VALUE_MAX;
mq_attr.mq_flags = MQ_SEMAPHORE;
if(msg->connect.extra_type == _IO_CONNECT_EXTRA_SEM) {
if (msg->connect.extra_len != sizeof(uint32_t))
return(ENOSYS);
if (ctp->info.flags & _NTO_MI_ENDIAN_DIFF) {
ENDIAN_SWAP32(smp);
}
mq_attr.mq_curmsgs = *smp;
}
break;
default:
return ENOSYS;
}
// Check for O_CREAT race condition (PR-11060)
if ((dev = check_duplicate(msg->connect.path, *head)) != NULL) {
// Re-target open to the already created device.
ctp->id = dev->id;
goto race; // In case non-trivial open verification code
}
// Get a device entry and the input/output buffers for it.
if((dev = MemchunkCalloc(memchunk, 1, sizeof(*dev) + msg->connect.path_len - sizeof(char))) == NULL) {
return ENOSPC;
}
msg->connect.mode = (msg->connect.mode & ~S_IFMT) | S_IFNAM;
if((status = iofunc_open(ctp, msg, &dev->attr, attr, 0)) != EOK) {
MemchunkFree(memchunk, dev);
return status;
}
dev->mq_attr = mq_attr;
dev->attr.rdev = rdev;
IOFUNC_NOTIFY_INIT(dev->notify);
// Add the new queue to the pathname space
if((dev->id = create_device(msg->connect.path, msg->connect.file_type, dev)) == -1) {
if ((status = errno) == EMFILE) { //We have created too many connections, this is the system limit
status = ENFILE; //Tell the client the system is full.
}
MemchunkFree(memchunk, dev);
return status;
}
strcpy(dev->name, msg->connect.path);
dev->link = *head, *head = dev;
// Re-target open to the newly created device.
ctp->id = dev->id;
} else {
race:
// Open on an existing queue.
if((status = iofunc_open(ctp, msg, &dev->attr, 0, 0)) != EOK) {
return status;
}
}
// Attach the ocb to the device
if((status = iofunc_ocb_attach(ctp, msg, NULL, &dev->attr, NULL)) == -1) {
return status;
}
return EOK;
}
__SRCVERSION("io_open.c $Rev: 153052 $");