0

我刚刚从 POSIX 切换到 SysV,因为 SysV 的限制要高得多(1024 对 10)。但我仍然需要更高的限制。该限制应在运行时更改,因为它取决于用户选择的数据。

使用 POSIX,可以增加限制,但每次都必须以 root 身份运行代码,而我不能这样做。

有没有办法增加 SysV 的限制?

4

1 回答 1

3

由于 SYSV IPC 被认为已弃用,很遗憾使用那些老式服务设计全新的应用程序。

POSIX 消息队列基于文件系统。它通常安装在/dev/mqueue上:

$ ls -la /dev/mqueue
total 0
drwxrwxrwt  2 root root   40 dec.  25 21:02 .
drwxr-xr-x 20 root root 4600 dec.  25 20:51 ..

使用mq_open()创建消息队列。attr参数提供了设置一些属性的能力:

struct mq_attr {
  long mq_flags;       /* Flags (ignored for mq_open()) */
  long mq_maxmsg;      /* Max. # of messages on queue */
  long mq_msgsize;     /* Max. message size (bytes) */
  long mq_curmsgs;     /* # of messages currently in queue (ignored for mq_open()) */
};

根据文档/proc/sys/fs/mqueue/msg_max文件定义了队列中最大消息数的上限。在 Linux 5.4 中,其默认值为DFLT_MSGMAX (10),其上限为HARD_MSGMAX (65536)。

默认值在 Linux 源代码中定义(参见/include/linux/ipc_namespace.h):

#define DFLT_QUEUESMAX      256
#define MIN_MSGMAX          1
#define DFLT_MSG            10U
#define DFLT_MSGMAX         10
#define HARD_MSGMAX         65536
#define MIN_MSGSIZEMAX      128
#define DFLT_MSGSIZE        8192U
#define DFLT_MSGSIZEMAX     8192
#define HARD_MSGSIZEMAX     (16*1024*1024)

这是一个创建消息队列的示例程序。它接收消息队列名称和队列中的最大消息数作为参数:

#include <errno.h>
#include <pthread.h>
#include <mqueue.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
  mqd_t mqdes;
  struct mq_attr attr;

  if (argc != 3) {
    fprintf(stderr, "Usage: %s <mq-name> <msg_max>\n", argv[0]);
    exit(EXIT_FAILURE);
  }

  attr.mq_flags = 0;
  attr.mq_maxmsg = atoi(argv[2]);
  attr.mq_msgsize = 2048;
  attr.mq_curmsgs = 0;

  mqdes = mq_open(argv[1], O_CREAT | O_RDWR, 0777, &attr);
  if (mqdes == (mqd_t) -1) {
    perror("mq_open");
    return 1;
  }

  return 0;
}

在执行时,我们可以验证,默认情况下,队列的消息不能超过 10 条:

$ gcc mq.c -o mq -lrt
$ ./mq 
Usage: ./mq <mq-name> <msg_max>
$ ./mq /q0 5
$ ls -la /dev/mqueue/
total 0
drwxrwxrwt  2 root   root     60 dec.  25 21:09 .
drwxr-xr-x 20 root   root   4600 dec.  25 20:51 ..
-rwxrwxr-x  1 xxxx   xxxx     80 dec.  25 21:09 q0
$ ./mq /q1 9
$ ./mq /q2 10
$ ./mq /q3 11
mq_open: Invalid argument
$ ls -la /dev/mqueue/
total 0
drwxrwxrwt  2 root   root    100 dec.  25 21:10 .
drwxr-xr-x 20 root   root   4600 dec.  25 20:51 ..
-rwxrwxr-x  1 xxxx   xxxx     80 dec.  25 21:09 q0
-rwxrwxr-x  1 xxxx   xxxx     80 dec.  25 21:10 q1
-rwxrwxr-x  1 xxxx   xxxx     80 dec.  25 21:10 q2

让我们将msg_max的上限从 10 更改为 256 :

$ cat /proc/sys/fs/mqueue/msg_max
10
$ sudo sh -c "echo 256 > /proc/sys/fs/mqueue/msg_max"
$ cat /proc/sys/fs/mqueue/msg_max
256

现在可以创建最多包含 256 条消息的消息队列:

$ ./mq /q3 11
$ ./mq /q4 256
$ ./mq /q5 257
mq_open: Invalid argument
$ ls -la /dev/mqueue/
total 0
drwxrwxrwt  2 root   root    140 dec.  25 21:16 .
drwxr-xr-x 20 root   root   4600 dec.  25 20:51 ..
-rwxrwxr-x  1 xxxx   xxxx     80 dec.  25 21:09 q0
-rwxrwxr-x  1 xxxx   xxxx     80 dec.  25 21:10 q1
-rwxrwxr-x  1 xxxx   xxxx     80 dec.  25 21:10 q2
-rwxrwxr-x  1 xxxx   xxxx     80 dec.  25 21:15 q3
-rwxrwxr-x  1 xxxx   xxxx     80 dec.  25 21:16 q4

但正如你所说,提高上限需要超级用户权限。可以创建一个“setuid helper”来增加上限。例如,以下程序设置作为参数传递的上限值:

#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char *argv[])
{
int fd;
int rc;
int msg_max;

  if (argc != 2) {
    fprintf(stderr, "Usage: %s <msg_max>\n", argv[0]);
    return 1;
  }

  fd = open("/proc/sys/fs/mqueue/msg_max", O_RDWR);
  if (fd < 0) {
    perror("open()");
    return 1;
  }

  rc = write(fd, argv[1], strlen(argv[1]));
  if (rc != strlen(argv[1])) {
    if (rc >= 0) {
      errno = EIO;
    }
    perror("write()");
    return 1;
  }

  close(fd);

  return 0;
}

我们可以构建它,将其所有者/组更改为 root 并添加 setuid 位:

$ gcc mq_helper.c -o mq_helper
$ sudo chown root mq_helper
$ sudo chgrp root mq_helper
$ sudo chmod 4555 mq_helper
$ ls -l mq_helper
-r-sr-xr-x 1 root root 17016 dec.  25 21:45 mq_helper

然后,可以从非超级用户帐户运行此程序以更改msg_max的上限:

$ cat /proc/sys/fs/mqueue/msg_max
256
$ ./mq_helper 98
$ cat /proc/sys/fs/mqueue/msg_max
98
于 2020-12-25T20:20:48.643 回答