jack1 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

327 lines
7.0KB

  1. /**
  2. * This program is free software; you can redistribute it and/or modify
  3. * it under the terms of the GNU General Public License as published by
  4. * the Free Software Foundation; either version 2 of the License, or
  5. * (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program; if not, write to the Free Software
  14. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15. *
  16. * Set of functions to gather system information for the jack setup wizard.
  17. *
  18. * TODO: Test for rt prio availability
  19. *
  20. * @author Florian Faber, faber@faberman.de
  21. *
  22. **/
  23. /** maximum number of groups a user can be a member of **/
  24. #define MAX_GROUPS 100
  25. #include <fcntl.h>
  26. #include <stdlib.h>
  27. #include <sys/types.h>
  28. #include <unistd.h>
  29. #include <grp.h>
  30. #include <sched.h>
  31. #include <string.h>
  32. #include <sys/time.h>
  33. #include <sys/resource.h>
  34. #include <stdio.h>
  35. #include <errno.h>
  36. #include "systemtest.h"
  37. /**
  38. * This function checks for the existence of known frequency scaling mechanisms
  39. * in this system by testing for the availability of scaling governors/
  40. *
  41. * @returns 0 if the system has no frequency scaling capabilities non-0 otherwise.
  42. **/
  43. int system_has_frequencyscaling ()
  44. {
  45. int fd;
  46. fd = open ("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors", O_RDONLY);
  47. if (-1 == fd) {
  48. return 0;
  49. }
  50. (void)close (fd);
  51. return 1;
  52. }
  53. static int read_string (char* filename, char* buf, size_t buflen)
  54. {
  55. int fd;
  56. ssize_t r = -1;
  57. memset (buf, 0, buflen);
  58. fd = open (filename, O_RDONLY);
  59. if (-1 < fd) {
  60. r = read (fd, buf, buflen - 1);
  61. (void)close (fd);
  62. if (-1 == r) {
  63. fprintf (stderr, "Error while reading \"%s\": %s\n", filename, strerror (errno));
  64. exit (EXIT_FAILURE);
  65. }
  66. }
  67. return (int)r;
  68. }
  69. static int read_int (char* filename, int* value)
  70. {
  71. char buf[20];
  72. if (0 < read_string (filename, buf, 20)) {
  73. return 1 == sscanf (buf, "%d", value);
  74. }
  75. return 0;
  76. }
  77. /**
  78. * This function determines wether any CPU core uses a variable clock speed if frequency
  79. * scaling is available. If the governor for all cores is either "powersave" or
  80. * "performance", the CPU frequency can be assumed to be static. This is also the case
  81. * if scaling_min_freq and scaling_max_freq are set to the same value.
  82. *
  83. * @returns 0 if system doesn't use frequency scaling at the moment, non-0 otherwise
  84. **/
  85. int system_uses_frequencyscaling ()
  86. {
  87. int cpu = 0, done = 0, min, max;
  88. char filename[256], buf[256];
  89. while (!done) {
  90. (void)snprintf (filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpu);
  91. if (0 < read_string (filename, buf, 256)) {
  92. if ((0 != strncmp ("performance", buf, 11)) &&
  93. (0 != strncmp ("powersafe", buf, 9))) {
  94. // So it's neither the "performance" nor the "powersafe" governor
  95. (void)snprintf (filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
  96. if (read_int (filename, &min)) {
  97. (void)snprintf (filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
  98. if (read_int (filename, &max)) {
  99. if (min != max) {
  100. // wrong governor AND different frequency limits -> scaling
  101. return 1;
  102. }
  103. }
  104. }
  105. }
  106. } else {
  107. // couldn't open file -> no more cores
  108. done = 1;
  109. }
  110. cpu++;
  111. }
  112. // couldn't find anything that points to scaling
  113. return 0;
  114. }
  115. static gid_t get_group_by_name (const char* name)
  116. {
  117. struct group* grp;
  118. gid_t res = 0;
  119. while ((0 == res) && (NULL != (grp = getgrent ()))) {
  120. if (0 == strcmp (name, grp->gr_name)) {
  121. res = grp->gr_gid;
  122. }
  123. }
  124. endgrent ();
  125. return res;
  126. }
  127. /***
  128. * Checks for a definition in /etc/security/limits.conf that looks
  129. * as if it allows RT scheduling priority.
  130. *
  131. * @returns 1 if there appears to be such a line
  132. **/
  133. int system_has_rtprio_limits_conf ()
  134. {
  135. const char* limits = "/etc/security/limits.conf";
  136. char cmd[100];
  137. snprintf (cmd, sizeof(cmd), "grep -q 'rtprio *[0-9][0-9]*' %s", limits);
  138. if (system (cmd) == 0) {
  139. return 1;
  140. }
  141. return 0;
  142. }
  143. /**
  144. * Checks for the existence of the 'audio' group on this system
  145. *
  146. * @returns 0 is there is no 'audio' group, the group id otherwise
  147. **/
  148. int system_has_audiogroup ()
  149. {
  150. return get_group_by_name ("audio") || get_group_by_name ("jackuser");
  151. }
  152. /**
  153. * Tests wether the owner of this process is in the 'audio' group.
  154. *
  155. * @returns 0 if the owner of this process is not in the audio group, non-0 otherwise
  156. **/
  157. int system_user_in_audiogroup ()
  158. {
  159. gid_t* list = (gid_t*)malloc (MAX_GROUPS * sizeof(gid_t));
  160. int num_groups, i = 0, found = 0;
  161. unsigned int gid;
  162. if (NULL == list) {
  163. perror ("Cannot allocate group list structure");
  164. exit (EXIT_FAILURE);
  165. }
  166. gid = get_group_by_name ("audio");
  167. if (0 == gid) {
  168. fprintf (stderr, "No audio group found\n");
  169. exit (EXIT_FAILURE);
  170. }
  171. num_groups = getgroups (MAX_GROUPS, list);
  172. while (i < num_groups) {
  173. if (list[i] == gid) {
  174. found = 1;
  175. i = num_groups;
  176. }
  177. i++;
  178. }
  179. free (list);
  180. return found;
  181. }
  182. /**
  183. * Determines wether the owner of this process can enable rt priority.
  184. *
  185. * @returns 0 if this process can not be switched to rt prio, non-0 otherwise
  186. **/
  187. int system_user_can_rtprio ()
  188. {
  189. int min_prio;
  190. struct sched_param schparam;
  191. memset (&schparam, 0, sizeof(struct sched_param));
  192. if (-1 == (min_prio = sched_get_priority_min (SCHED_FIFO))) {
  193. perror ("sched_get_priority");
  194. exit (EXIT_FAILURE);
  195. }
  196. schparam.sched_priority = min_prio;
  197. if (0 == sched_setscheduler (0, SCHED_FIFO, &schparam)) {
  198. // TODO: restore previous state
  199. schparam.sched_priority = 0;
  200. if (0 != sched_setscheduler (0, SCHED_OTHER, &schparam)) {
  201. perror ("sched_setscheduler");
  202. exit (EXIT_FAILURE);
  203. }
  204. return 1;
  205. }
  206. return 0;
  207. }
  208. long long unsigned int system_memlock_amount ()
  209. {
  210. struct rlimit limits;
  211. if (-1 == getrlimit (RLIMIT_MEMLOCK, &limits)) {
  212. perror ("getrlimit on RLIMIT_MEMLOCK");
  213. exit (EXIT_FAILURE);
  214. }
  215. return limits.rlim_max;
  216. }
  217. /**
  218. * Checks wether the memlock limit is unlimited
  219. *
  220. * @returns - 0 if the memlock limit is limited, non-0 otherwise
  221. **/
  222. int system_memlock_is_unlimited ()
  223. {
  224. return (RLIM_INFINITY == system_memlock_amount ()) ? 1 : 0;
  225. }
  226. long long unsigned int system_available_physical_mem ()
  227. {
  228. char buf[256];
  229. long long unsigned int res = 0;
  230. if (0 < read_string ("/proc/meminfo", buf, sizeof(buf))) {
  231. if (strncmp (buf, "MemTotal:", 9) == 0) {
  232. if (sscanf (buf, "%*s %llu", &res) != 1) {
  233. perror ("parse error in /proc/meminfo");
  234. }
  235. }
  236. } else {
  237. perror ("read from /proc/meminfo");
  238. }
  239. return res * 1024;
  240. }
  241. /**
  242. * Gets the version of the currently running kernel. The string
  243. * returned has to be freed by the caller.
  244. *
  245. * @returns String with the full version of the kernel
  246. **/
  247. char* system_kernel_version ()
  248. {
  249. return NULL;
  250. }
  251. char* system_get_username ()
  252. {
  253. char* res = NULL;
  254. char* name = NULL;
  255. if ((name = getlogin ())) {
  256. res = strdup (name);
  257. }
  258. return res;
  259. }