Merge branch 't/uptime_cleanup'
[paraslash.git] / ipc.c
diff --git a/ipc.c b/ipc.c
index c64cc89..674d1cb 100644 (file)
--- a/ipc.c
+++ b/ipc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2009 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2006-2011 Andre Noll <maan@systemlinux.org>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
@@ -9,6 +9,10 @@
 #include "para.h"
 #include "error.h"
 #include "ipc.h"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+
 #include <sys/ipc.h>
 #include <sys/shm.h>
 #include <sys/sem.h>
@@ -171,3 +175,45 @@ int shm_detach(void *addr)
        int ret = shmdt(addr);
        return ret < 0? -ERRNO_TO_PARA_ERROR(errno) : 1;
 }
+
+# if defined __FreeBSD__ || defined __NetBSD__
+#      define SYSCTL_SHMMAX_VARIABLE "kern.ipc.shmmax"
+# elif defined __APPLE__
+#      define SYSCTL_SHMMAX_VARIABLE "kern.sysv.shmmax"
+# else
+#      undef SYSCTL_SHMMAX_VARIABLE
+# endif
+
+size_t shm_get_shmmax(void)
+{
+       static size_t shmmax;
+
+       if (shmmax > 0) /* only dance once */
+               return shmmax;
+#ifdef __linux__ /* get it from proc fs */
+       {
+               int fd = open("/proc/sys/kernel/shmmax", O_RDONLY);
+               if (fd >= 0) {
+                       char buf[100] = "";
+                       int ret = read(fd, buf, sizeof(buf) - 1);
+                       if (ret > 0) {
+                               buf[ret] = '\0';
+                               shmmax = strtoul(buf, NULL, 10);
+                       }
+               }
+       }
+#elif defined SYSCTL_SHMMAX_VARIABLE
+       {
+               size_t len = sizeof(shmmax);
+               sysctlbyname(SYSCTL_SHMMAX_VARIABLE, &shmmax, &len, NULL, 0);
+       }
+#elif defined SHMMAX
+       shmmax = SHMMAX;
+#endif
+       if (shmmax == 0) {
+               PARA_WARNING_LOG("unable to determine shmmax\n");
+               shmmax = 65535; /* last ressort */
+       }
+       PARA_INFO_LOG("shmmax: %zu\n", shmmax);
+       return shmmax;
+}