sysfsgpio: give time to udev to change gpio permission

When a gpio is exported by writing in /sys/class/gpio/export, the
corresponding gpio control files appear immediately in sysfs but
with default access permission for root user only. The daemon udev
requires some time to get notified of the new files before it can
change the permissions to allow access to unprivileged users.
Due to this race condition, sysfsgpio can fail with EACCES error
if OpenOCD is executed by any unprivileged user.

Give 0.5 seconds to udev to identify the new files and change the
permission.

Tested with udev rules:
	SUBSYSTEM=="gpio*", PROGRAM="/bin/sh -c 'find -L /sys/class/gpio/ -maxdepth 2 -exec chown root:uucp {} \; -exec chmod g=u {} \; || true'"

Change-Id: I1316c66ff103ffe23e5e4720f33372dc272a3766
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: http://openocd.zylin.com/5302
Tested-by: jenkins
Reviewed-by: Tomas Vanek <vanekt@fbl.cz>
This commit is contained in:
Antonio Borneo 2019-09-05 10:48:12 +02:00 committed by Tomas Vanek
parent 964c4db9ce
commit 49d71d06d1
1 changed files with 23 additions and 2 deletions

View File

@ -52,6 +52,7 @@
#include "config.h"
#endif
#include <helper/time_support.h>
#include <jtag/interface.h>
#include "bitbang.h"
@ -112,6 +113,7 @@ static void unexport_sysfs_gpio(int gpio)
*/
static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
{
struct timeval timeout, now;
char buf[40];
char gpiostr[5];
int ret;
@ -131,8 +133,19 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
}
}
gettimeofday(&timeout, NULL);
timeval_add_time(&timeout, 0, 500000);
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/direction", gpio);
ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in");
for (;;) {
ret = open_write_close(buf, is_output ? (init_high ? "high" : "low") : "in");
if (ret >= 0 || errno != EACCES)
break;
gettimeofday(&now, NULL);
if (timeval_compare(&now, &timeout) >= 0)
break;
jtag_sleep(10000);
}
if (ret < 0) {
LOG_ERROR("Couldn't set direction for gpio %d", gpio);
perror("sysfsgpio: ");
@ -141,7 +154,15 @@ static int setup_sysfs_gpio(int gpio, int is_output, int init_high)
}
snprintf(buf, sizeof(buf), "/sys/class/gpio/gpio%d/value", gpio);
ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC);
for (;;) {
ret = open(buf, O_RDWR | O_NONBLOCK | O_SYNC);
if (ret >= 0 || errno != EACCES)
break;
gettimeofday(&now, NULL);
if (timeval_compare(&now, &timeout) >= 0)
break;
jtag_sleep(10000);
}
if (ret < 0) {
LOG_ERROR("Couldn't open value for gpio %d", gpio);
perror("sysfsgpio: ");