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
6.6KB

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