From da01fb78dfa01266e60aa18d012e95d53547e00b Mon Sep 17 00:00:00 2001 From: paul Date: Fri, 13 Mar 2009 16:34:09 +0000 Subject: [PATCH] first pass at integrating sanity/system checks into jack1 git-svn-id: svn+ssh://jackaudio.org/trunk/jack@3434 0c269be4-1314-0410-8aa9-9f06e86f4224 --- Makefile.am | 2 +- config/os/gnu-linux/Makefile.am | 2 +- config/os/gnu-linux/sanitycheck.c | 73 +++++++ config/os/gnu-linux/systemtest.c | 313 ++++++++++++++++++++++++++++++ config/sysdeps/sanitycheck.c | 12 ++ config/sysdeps/systemtest.c | 12 ++ jack/sanitycheck.h | 21 ++ jack/systemtest.h | 97 +++++++++ jackd/Makefile.am | 10 +- jackd/jackd.c | 11 ++ libjack/sanitycheck.c | 1 + libjack/systemtest.c | 1 + 12 files changed, 550 insertions(+), 5 deletions(-) create mode 100644 config/os/gnu-linux/sanitycheck.c create mode 100644 config/os/gnu-linux/systemtest.c create mode 100644 config/sysdeps/sanitycheck.c create mode 100644 config/sysdeps/systemtest.c create mode 100644 jack/sanitycheck.h create mode 100644 jack/systemtest.h create mode 100644 libjack/sanitycheck.c create mode 100644 libjack/systemtest.c diff --git a/Makefile.am b/Makefile.am index e28a23d..d3f5288 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,7 +19,7 @@ DIST_SUBDIRS = config jack libjack jackd drivers example-clients tools doc man pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = jack.pc -EXTRA_DIST = COPYING COPYING.GPL COPYING.LGPL libjack/simd.c jack.spec +EXTRA_DIST = COPYING COPYING.GPL COPYING.LGPL libjack/simd.c jack.spec testing AUTOMAKE_OPTIONS = foreign diff --git a/config/os/gnu-linux/Makefile.am b/config/os/gnu-linux/Makefile.am index 56c5dca..eb4c557 100644 --- a/config/os/gnu-linux/Makefile.am +++ b/config/os/gnu-linux/Makefile.am @@ -1,3 +1,3 @@ MAINTAINERCLEANFILES = Makefile.in -noinst_HEADERS = time.c time.h +noinst_HEADERS = systemtest.c sanitycheck.c time.c time.h diff --git a/config/os/gnu-linux/sanitycheck.c b/config/os/gnu-linux/sanitycheck.c new file mode 100644 index 0000000..523fbbc --- /dev/null +++ b/config/os/gnu-linux/sanitycheck.c @@ -0,0 +1,73 @@ +/** + * GPL etc. + * + * @author Florian Faber + * + * @version 0.1 (2009-01-17) [FF] + * - initial version + **/ + +#include +#include +#include + +int sanitycheck() { + int errors = 0; + int relogin = 0; + + if (!system_user_can_rtprio()) { + errors++; + relogin++; + fprintf(stderr, "\nYou are not allowed to set realtime priority.\n"); + + if (!system_has_rtprio_limits_conf()) { + errors++; + relogin++; + fprintf (stderr, "Please check your /etc/security/limits.conf for the following lines\n"); + fprintf (stderr, "and correct/add them:\n\n"); + fprintf(stderr, " @audio - rtprio 100\n"); + fprintf(stderr, " @audio - nice -10\n"); + } else if (!system_has_audiogroup()) { + errors++; + relogin++; + fprintf(stderr, "\nYour system has no audio group. Please add it by executing (as root):\n"); + fprintf(stderr, " groupadd -r audio\n"); + fprintf(stderr, " usermod -a -G audio %s\n", system_get_username()); + } else if (!system_user_in_audiogroup()) { + errors++; + relogin++; + fprintf(stderr, "\nYour system has an audio group, but you are not a member of it.\n"); + fprintf(stderr, "Please add yourself to the audio group by executing (as root):\n"); + fprintf(stderr, " usermod -a -G audio %s\n", system_get_username()); + } + } + if (system_has_frequencyscaling() && system_uses_frequencyscaling()) { + errors++; + fprintf(stderr, "\nYour system seems to use frequency scaling. This can have a serious impact\n"); + fprintf(stderr, "on the audio latency. Please turn it off, e.g. by chosing the 'performance'\n"); + fprintf(stderr, "governor.\n"); + } + if (system_memlock_is_unlimited()) { + fprintf(stderr, "\nMemory locking is unlimited - this is dangerous. Please alter the line"); + fprintf(stderr, " @audio - memlock unlimited"); + fprintf(stderr, "in your /etc/limits.conf to"); + fprintf(stderr, " @audio - memlock %llu\n", (system_available_physical_mem()*3)/4096); + } else if (0==system_memlock_amount()) { + errors++; + relogin++; + fprintf(stderr, "\nYou are not allowed to lock memory. Please add a line\n"); + fprintf(stderr, " @audio - memlock %llu\n", (system_available_physical_mem()*3)/4096); + fprintf(stderr, "in your /etc/limits.conf.\n"); + } + + if (0 + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +/** + * This function checks for the existence of known frequency scaling mechanisms + * in this system by testing for the availability of scaling governors/ + * + * @returns 0 if the system has no frequency scaling capabilities non-0 otherwise. + **/ +int system_has_frequencyscaling() { + int fd; + + fd = open("/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors", O_RDONLY); + + if (-1==fd) { + return 0; + } + + (void) close(fd); + + return 1; +} + + +static int read_string(char* filename, char* buf, size_t buflen) { + int fd; + ssize_t r=-1; + + memset(buf, 0, buflen); + + fd = open(filename, O_RDONLY); + if (-1 scaling + return 1; + } + } + } + } + } else { + // couldn't open file -> no more cores + done = 1; + } + cpu++; + } + + // couldn't find anything that points to scaling + return 0; +} + + +static gid_t get_group_by_name(const char* name) { + struct group* grp; + gid_t res = 0; + + while ((0==res) && (NULL != (grp = getgrent()))) { + if (0==strcmp(name, grp->gr_name)) { + res = grp->gr_gid; + } + } + + endgrent(); + + return res; +} + +/*** + * Checks for a definition in /etc/security/limits.conf that looks + * as if it allows RT scheduling priority. + * + * @returns 1 if there appears to be such a line + **/ +int system_has_rtprio_limits_conf () +{ + const char* limits = "/etc/security/limits.conf"; + char cmd[100]; + + snprintf (cmd, sizeof (cmd), "grep -q 'rtprio *[0-9][0-9]*' %s", limits); + if (system (cmd) == 0) { + return 1; + } + return 0; +} + + +/** + * Checks for the existence of the 'audio' group on this system + * + * @returns 0 is there is no 'audio' group, the group id otherwise + **/ +int system_has_audiogroup() { + return get_group_by_name("audio") || get_group_by_name ("jackuser"); +} + + +/** + * Tests wether the owner of this process is in the 'audio' group. + * + * @returns 0 if the owner of this process is not in the audio group, non-0 otherwise + **/ +int system_user_in_audiogroup() { + gid_t* list = (gid_t*) malloc(MAX_GROUPS * sizeof(gid_t)); + int num_groups, i=0, found=0; + unsigned int gid; + + if (NULL==list) { + perror("Cannot allocate group list structure"); + exit(EXIT_FAILURE); + } + + gid = get_group_by_name("audio"); + if (0==gid) { + fprintf(stderr, "No audio group found\n"); + exit(EXIT_FAILURE); + } + + num_groups = getgroups(MAX_GROUPS, list); + + while (i +#elif defined(__MACH__) && defined(__APPLE__) +/* relax */ +#else +/* relax */ +#endif + +#endif /* _jack_sysdep_sanitycheck_c_ */ diff --git a/config/sysdeps/systemtest.c b/config/sysdeps/systemtest.c new file mode 100644 index 0000000..7afa3ec --- /dev/null +++ b/config/sysdeps/systemtest.c @@ -0,0 +1,12 @@ +#ifndef _jack_sysdep_systemtest_c_ +#define _jack_sysdep_systemtest_c_ + +#if defined(__gnu_linux__) +#include +#elif defined(__MACH__) && defined(__APPLE__) +/* relax */ +#else +/* relax */ +#endif + +#endif /* _jack_sysdep_systemtest_c_ */ diff --git a/jack/sanitycheck.h b/jack/sanitycheck.h new file mode 100644 index 0000000..ecf3738 --- /dev/null +++ b/jack/sanitycheck.h @@ -0,0 +1,21 @@ +#ifndef __jack_sanitycheck_h__ +#define __jack_sanitycheck_h__ + +/** + * GPL etc. + * + * @author Florian Faber + * + * @version 0.1 (2009-01-17) [FF] + * - initial version + **/ + +/** + * Performs a range of sanity checks on the system. The number of + * found problems is returned. + * + **/ + +int sanitycheck(); + +#endif /* __jack_sanitycheck_h__ */ diff --git a/jack/systemtest.h b/jack/systemtest.h new file mode 100644 index 0000000..27e0ae7 --- /dev/null +++ b/jack/systemtest.h @@ -0,0 +1,97 @@ +#ifndef __jack_systemtest_h__ +#define __jack_systemtest_h__ + +/** + * GPL, yabbadabba + * + * Set of functions to gather system information for the jack setup wizard. + * + * @author Florian Faber, faber@faberman.de + * + * @version 0.1 (2009-01-15) [FF] + * - initial version + * + **/ + + +/** + * This function checks for the existence of known frequency scaling mechanisms + * in this system. + * + * @returns 0 if the system has no frequency scaling capabilities non-0 otherwise. + **/ +int system_has_frequencyscaling(); + + +/** + * This function determines wether the CPU has a variable clock speed if frequency + * scaling is available. + * + * @returns 0 if system doesn't use frequency scaling at the moment, non-0 otherwise + **/ +int system_uses_frequencyscaling(); + + +/*** + * Checks for a definition in /etc/security/limits.conf that looks + * as if it allows RT scheduling priority. + * + * @returns 1 if there appears to be such a line + **/ +int system_has_rtprio_limits_conf (); + +/** + * Checks for the existence of the 'audio' group on this system + * + * @returns 0 is there is no 'audio' group, non-0 otherwise + **/ +int system_has_audiogroup(); + + +/** + * Tests wether the owner of this process is in the 'audio' group. + * + * @returns 0 if the owner of this process is not in the audio group, non-0 otherwise + **/ +int system_user_in_audiogroup(); + + +/** + * Determines wether the owner of this process can enable rt priority. + * + * @returns 0 if this process can not be switched to rt prio, non-0 otherwise + **/ +int system_user_can_rtprio(); + + +long long unsigned int system_memlock_amount(); + + +/** + * Checks wether the memlock limit is unlimited + * + * @returns 0 if the memlock limit is limited, non-0 otherwise + **/ +int system_memlock_is_unlimited(); + + +long long unsigned int system_available_physical_mem(); + + +/** + * Gets the version of the currently running kernel + * + * @returns String with the full version of the kernel + **/ +char* system_kernel_version(); + + +/** + * Returns the username. The caller is in charge of disposal of + * the returned name. + * + * @returns Pointer to a username or NULL + **/ +char* system_get_username(); + +#endif /* __jack_systemtest_h__ */ diff --git a/jackd/Makefile.am b/jackd/Makefile.am index cf6ecd0..adf5be5 100644 --- a/jackd/Makefile.am +++ b/jackd/Makefile.am @@ -44,9 +44,13 @@ lib_LTLIBRARIES = libjackserver.la libjackserver_la_CFLAGS = $(AM_CFLAGS) -libjackserver_la_SOURCES = engine.c clientengine.c transengine.c ../libjack/client.c ../libjack/driver.c ../libjack/intclient.c \ - ../libjack/messagebuffer.c ../libjack/pool.c ../libjack/port.c ../libjack/midiport.c ../libjack/ringbuffer.c ../libjack/shm.c \ - ../libjack/thread.c ../libjack/time.c ../libjack/transclient.c ../libjack/unlock.c +libjackserver_la_SOURCES = engine.c clientengine.c transengine.c \ + ../libjack/systemtest.c ../libjack/sanitycheck.c \ + ../libjack/client.c ../libjack/driver.c ../libjack/intclient.c \ + ../libjack/messagebuffer.c ../libjack/pool.c ../libjack/port.c \ + ../libjack/midiport.c ../libjack/ringbuffer.c ../libjack/shm.c \ + ../libjack/thread.c ../libjack/time.c ../libjack/transclient.c \ + ../libjack/unlock.c libjackserver_la_LIBADD = simd.lo @OS_LDFLAGS@ libjackserver_la_LDFLAGS = -export-dynamic -version-info @JACK_SO_VERSION@ diff --git a/jackd/jackd.c b/jackd/jackd.c index c38c1e5..d89d867 100644 --- a/jackd/jackd.c +++ b/jackd/jackd.c @@ -369,6 +369,7 @@ static void usage (FILE *file) " [ --timeout OR -t client-timeout-in-msecs ]\n" " [ --port-max OR -p maximum-number-of-ports]\n" " [ --debug-timer OR -D ]\n" +" [ --no-sanity-checks OR -N ]\n" " [ --verbose OR -v ]\n" " [ --clocksource OR -c [ c(ycle) | h(pet) | s(ystem) ]\n" " [ --replace-registry OR -r ]\n" @@ -519,6 +520,7 @@ main (int argc, char *argv[]) { "port-max", 1, 0, 'p' }, { "no-mlock", 0, 0, 'm' }, { "name", 1, 0, 'n' }, + { "no-sanity-checks", 1, 0, 'N' }, { "unlock", 0, 0, 'u' }, { "realtime", 0, 0, 'R' }, { "replace-registry", 0, 0, 'r' }, @@ -540,6 +542,7 @@ main (int argc, char *argv[]) int driver_nargs = 1; int show_version = 0; int replace_registry = 0; + int do_sanity_checks = 1; int i; int rc; @@ -588,6 +591,10 @@ main (int argc, char *argv[]) server_name = optarg; break; + case 'N': + do_sanity_checks = 0; + break; + case 'p': port_max = (unsigned int) atol (optarg); break; @@ -642,6 +649,10 @@ main (int argc, char *argv[]) } } + if (do_sanity_checks && (0 < sanitycheck())) { + return -1; + } + if (show_version) { printf ( "jackd version " VERSION " tmpdir " DEFAULT_TMP_DIR diff --git a/libjack/sanitycheck.c b/libjack/sanitycheck.c new file mode 100644 index 0000000..d0fc2da --- /dev/null +++ b/libjack/sanitycheck.c @@ -0,0 +1 @@ +#include diff --git a/libjack/systemtest.c b/libjack/systemtest.c new file mode 100644 index 0000000..e090432 --- /dev/null +++ b/libjack/systemtest.c @@ -0,0 +1 @@ +#include