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.

314 lines
7.1KB

  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 <jack/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. int fd;
  45. fd = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors", O_RDONLY);
  46. if (-1==fd) {
  47. return 0;
  48. }
  49. (void) close(fd);
  50. return 1;
  51. }
  52. static int read_string(char* filename, char* buf, size_t buflen) {
  53. int fd;
  54. ssize_t r=-1;
  55. memset (buf, 0, buflen);
  56. fd = open (filename, O_RDONLY);
  57. if (-1<fd) {
  58. r = read (fd, buf, buflen-1);
  59. (void) close(fd);
  60. if (-1==r) {
  61. fprintf(stderr, "Error while reading \"%s\": %s\n", filename, strerror(errno));
  62. exit(EXIT_FAILURE);
  63. }
  64. }
  65. return (int) r;
  66. }
  67. static int read_int(char* filename, int* value) {
  68. char buf[20];
  69. if (0<read_string(filename, buf, 20)) {
  70. return (1==sscanf(buf, "%d", value));
  71. }
  72. return 0;
  73. }
  74. /**
  75. * This function determines wether any CPU core uses a variable clock speed if frequency
  76. * scaling is available. If the governor for all cores is either "powersave" or
  77. * "performance", the CPU frequency can be assumed to be static. This is also the case
  78. * if scaling_min_freq and scaling_max_freq are set to the same value.
  79. *
  80. * @returns 0 if system doesn't use frequency scaling at the moment, non-0 otherwise
  81. **/
  82. int system_uses_frequencyscaling() {
  83. int cpu=0, done=0, min, max;
  84. char filename[256], buf[256];
  85. while (!done) {
  86. (void) snprintf(filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpu);
  87. if (0<read_string(filename, buf, 256)) {
  88. if ((0!=strcmp("performance", buf)) &&
  89. (0!=strcmp("powersafe", buf))) {
  90. // So it's neither the "performance" nor the "powersafe" governor
  91. (void) snprintf(filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_min_freq", cpu);
  92. if (read_int(filename, &min)) {
  93. (void) snprintf(filename, 256, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
  94. if (read_int(filename, &max)) {
  95. if (min!=max) {
  96. // wrong governor AND different frequency limits -> scaling
  97. return 1;
  98. }
  99. }
  100. }
  101. }
  102. } else {
  103. // couldn't open file -> no more cores
  104. done = 1;
  105. }
  106. cpu++;
  107. }
  108. // couldn't find anything that points to scaling
  109. return 0;
  110. }
  111. static gid_t get_group_by_name(const char* name) {
  112. struct group* grp;
  113. gid_t res = 0;
  114. while ((0==res) && (NULL != (grp = getgrent()))) {
  115. if (0==strcmp(name, grp->gr_name)) {
  116. res = grp->gr_gid;
  117. }
  118. }
  119. endgrent();
  120. return res;
  121. }
  122. /***
  123. * Checks for a definition in /etc/security/limits.conf that looks
  124. * as if it allows RT scheduling priority.
  125. *
  126. * @returns 1 if there appears to be such a line
  127. **/
  128. int system_has_rtprio_limits_conf ()
  129. {
  130. const char* limits = "/etc/security/limits.conf";
  131. char cmd[100];
  132. snprintf (cmd, sizeof (cmd), "grep -q 'rtprio *[0-9][0-9]*' %s", limits);
  133. if (system (cmd) == 0) {
  134. return 1;
  135. }
  136. return 0;
  137. }
  138. /**
  139. * Checks for the existence of the 'audio' group on this system
  140. *
  141. * @returns 0 is there is no 'audio' group, the group id otherwise
  142. **/
  143. int system_has_audiogroup() {
  144. return get_group_by_name("audio") || get_group_by_name ("jackuser");
  145. }
  146. /**
  147. * Tests wether the owner of this process is in the 'audio' group.
  148. *
  149. * @returns 0 if the owner of this process is not in the audio group, non-0 otherwise
  150. **/
  151. int system_user_in_audiogroup() {
  152. gid_t* list = (gid_t*) malloc(MAX_GROUPS * sizeof(gid_t));
  153. int num_groups, i=0, found=0;
  154. unsigned int gid;
  155. if (NULL==list) {
  156. perror("Cannot allocate group list structure");
  157. exit(EXIT_FAILURE);
  158. }
  159. gid = get_group_by_name("audio");
  160. if (0==gid) {
  161. fprintf(stderr, "No audio group found\n");
  162. exit(EXIT_FAILURE);
  163. }
  164. num_groups = getgroups(MAX_GROUPS, list);
  165. while (i<num_groups) {
  166. if (list[i]==gid) {
  167. found = 1;
  168. i = num_groups;
  169. }
  170. i++;
  171. }
  172. free(list);
  173. return found;
  174. }
  175. /**
  176. * Determines wether the owner of this process can enable rt priority.
  177. *
  178. * @returns 0 if this process can not be switched to rt prio, non-0 otherwise
  179. **/
  180. int system_user_can_rtprio() {
  181. int min_prio;
  182. struct sched_param schparam;
  183. memset(&schparam, 0, sizeof(struct sched_param));
  184. if (-1 == (min_prio = sched_get_priority_min(SCHED_RR))) {
  185. perror("sched_get_priority");
  186. exit(EXIT_FAILURE);
  187. }
  188. schparam.sched_priority = min_prio;
  189. if (0 == sched_setscheduler(0, SCHED_RR, &schparam)) {
  190. // TODO: restore previous state
  191. schparam.sched_priority = 0;
  192. if (0 != sched_setscheduler(0, SCHED_OTHER, &schparam)) {
  193. perror("sched_setscheduler");
  194. exit(EXIT_FAILURE);
  195. }
  196. return 1;
  197. }
  198. return 0;
  199. }
  200. long long unsigned int system_memlock_amount() {
  201. struct rlimit limits;
  202. if (-1==getrlimit(RLIMIT_MEMLOCK, &limits)) {
  203. perror("getrlimit on RLIMIT_MEMLOCK");
  204. exit(EXIT_FAILURE);
  205. }
  206. return limits.rlim_max;
  207. }
  208. /**
  209. * Checks wether the memlock limit is unlimited
  210. *
  211. * @returns - 0 if the memlock limit is limited, non-0 otherwise
  212. **/
  213. int system_memlock_is_unlimited() {
  214. return ((RLIM_INFINITY==system_memlock_amount())?1:0);
  215. }
  216. long long unsigned int system_available_physical_mem() {
  217. char buf[256];
  218. long long unsigned int res = 0;
  219. if (0<read_string("/proc/meminfo", buf, sizeof (buf))) {
  220. if (strncmp (buf, "MemTotal:", 9) == 0) {
  221. if (sscanf (buf, "%*s %llu", &res) != 1) {
  222. perror ("parse error in /proc/meminfo");
  223. }
  224. }
  225. } else {
  226. perror("read from /proc/meminfo");
  227. }
  228. return res*1024;
  229. }
  230. /**
  231. * Gets the version of the currently running kernel. The string
  232. * returned has to be freed by the caller.
  233. *
  234. * @returns String with the full version of the kernel
  235. **/
  236. char* system_kernel_version() {
  237. return NULL;
  238. }
  239. char* system_get_username() {
  240. char* res = NULL;
  241. char* name = NULL;
  242. if ((name = getlogin())) {
  243. res = strdup(name);
  244. }
  245. return res;
  246. }