diff --git a/SOURCES/i2c-tools-3.1.0-load-i2cdev.patch b/SOURCES/i2c-tools-3.1.0-load-i2cdev.patch new file mode 100644 index 0000000..24901d2 --- /dev/null +++ b/SOURCES/i2c-tools-3.1.0-load-i2cdev.patch @@ -0,0 +1,277 @@ +diff -up i2c-tools-3.1.0/tools/i2cbusses.c.load-i2cdev i2c-tools-3.1.0/tools/i2cbusses.c +--- i2c-tools-3.1.0/tools/i2cbusses.c.load-i2cdev 2010-11-26 11:25:32.000000000 +0100 ++++ i2c-tools-3.1.0/tools/i2cbusses.c 2017-04-05 08:43:08.135938481 +0200 +@@ -37,9 +37,16 @@ + #include + #include + #include ++#ifdef USE_LIBKMOD ++ #include ++#endif + #include "i2cbusses.h" + #include + ++#define BUFLEN (NAME_MAX > 512 ? NAME_MAX : 512) ++#define I2C_DEV_MOD_NAME "i2c_dev" ++#define I2C_DEV_SUBPATH "/class/i2c-dev" ++ + enum adt { adt_dummy, adt_isa, adt_i2c, adt_smbus, adt_unknown }; + + struct adap_type { +@@ -60,6 +67,145 @@ static struct adap_type adap_types[5] = + .algo = "N/A", }, + }; + ++/* Get and cache sysfs mount point. */ ++static const char *get_sysfs_mount_point(void) { ++ static const char *mp = NULL; ++ ++ if (mp == NULL) { ++ char sysfs[NAME_MAX]; ++ char fstype[NAME_MAX]; ++ char line[BUFLEN]; ++ FILE *f; ++ ++ if ((f = fopen("/proc/mounts", "r")) == NULL) { ++ perror("failed to read /proc/mounts: "); ++ goto done; ++ } ++ while (fgets(line, BUFLEN, f)) { ++ sscanf(line, "%*[^ ] %[^ ] %[^ ] %*s\n", sysfs, fstype); ++ if (strcasecmp(fstype, "sysfs") == 0) { ++ mp = strdup(sysfs); ++ if (mp == NULL) ++ perror("strdup: "); ++ break; ++ } ++ } ++ fclose(f); ++ } ++done: ++ return mp; ++} ++ ++/* Get an absolute path of i2c device directory. Free the result when not ++ * needed. */ ++static char *get_i2c_dev_path(void) { ++ char *path = NULL; ++ int mplen, splen; ++ const char *mp = get_sysfs_mount_point(); ++ ++ if (mp != NULL) { ++ mplen = strlen(mp); ++ splen = strlen(I2C_DEV_SUBPATH); ++ path = malloc(mplen + splen + 1); ++ if (path == NULL) { ++ perror("malloc: "); ++ } else { ++ strncpy(path, mp, mplen); ++ strncpy(path + mplen, I2C_DEV_SUBPATH, splen); ++ path[mplen+splen] = '\0'; ++ } ++ } ++ return path; ++} ++ ++/** ++ * Try to load i2c_dev kernel mode. Do nothing if module is already loaded. ++ * Returns 1 on success, 0 otherwise. ++ */ ++static int try_load_i2c_dev_mod(void) { ++ int err = 0, loaded = 0; ++ char errbuf[BUFLEN] = { 0 }; ++#ifdef USE_LIBKMOD ++ int flags = 0; ++ struct kmod_ctx *ctx; ++ struct kmod_list *l, *list = NULL; ++ ++ ctx = kmod_new(NULL, NULL); ++ if (!ctx) { ++ snprintf(errbuf, BUFLEN, "kmod_new() failed!"); ++ goto done; ++ } ++ if (kmod_module_new_from_lookup(ctx, I2C_DEV_MOD_NAME, &list) < 0 || list == NULL) { ++ snprintf(errbuf, BUFLEN, I2C_DEV_MOD_NAME " module lookup failed"); ++ goto ctx_unref; ++ } ++ ++ flags |= KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY; ++ kmod_list_foreach(l, list) { ++ struct kmod_module *mod = kmod_module_get_module(l); ++ err = kmod_module_probe_insert_module(mod, flags, NULL, NULL, NULL, NULL); ++ if (err == -ENOENT) { ++ snprintf(errbuf, BUFLEN, ++ "unknown symbol in module \"%s\", or unknown parameter (see dmesg)", ++ kmod_module_get_name(mod)); ++ } else if (err < 0) { ++ snprintf(errbuf, BUFLEN, "(module %s): %s", ++ kmod_module_get_name(mod), strerror(-err)); ++ } else { ++ kmod_module_unref(mod); ++ ++loaded; ++ break; ++ } ++ kmod_module_unref(mod); ++ } ++ ++ kmod_module_unref_list(list); ++ctx_unref: ++ kmod_unref(ctx); ++#else /* Try to load the module with modprobe. */ ++ struct stat st; ++ char *dev_path = get_i2c_dev_path(); ++ ++ /* First check whether the module is already loaded or built-in. */ ++ if (dev_path == NULL) ++ goto done; ++ err = stat(dev_path, &st); ++ if (err < 0) { ++ if (errno != ENOENT) { ++ snprintf(errbuf, BUFLEN, "can not stat \"%s\": %s", dev_path, ++ strerror(errno)); ++ goto err; ++ } else { ++ err = 0; ++ } ++ } else { ++ ++loaded; ++ goto done; ++ } ++ ++ err = system("modprobe " I2C_DEV_MOD_NAME); ++ if (err < 0) { ++ snprintf(errbuf, BUFLEN, "failed to execute modprobe command"); ++ } else if (err > 0) { ++ snprintf(errbuf, BUFLEN, "modprobe command exited with code %d", ++ WEXITSTATUS(err)); ++ } else { ++ ++loaded; ++ goto done; ++ } ++ ++err: ++#endif ++ if (errbuf[0]) ++ fprintf(stderr, "Failed to load required " I2C_DEV_MOD_NAME ++ " kernel module: %s\n", errbuf); ++done: ++#ifndef USE_LIBKMOD ++ free(dev_path); ++#endif ++ return loaded; ++} ++ + static enum adt i2c_get_funcs(int i2cbus) + { + unsigned long funcs; +@@ -132,8 +278,7 @@ struct i2c_adap *gather_i2c_busses(void) + struct dirent *de, *dde; + DIR *dir, *ddir; + FILE *f; +- char fstype[NAME_MAX], sysfs[NAME_MAX], n[NAME_MAX]; +- int foundsysfs = 0; ++ char *sysfs = NULL, n[NAME_MAX]; + int count=0; + struct i2c_adap *adapters; + +@@ -185,29 +330,19 @@ struct i2c_adap *gather_i2c_busses(void) + goto done; + } + +- /* look in sysfs */ +- /* First figure out where sysfs was mounted */ +- if ((f = fopen("/proc/mounts", "r")) == NULL) { ++ sysfs = get_i2c_dev_path(); ++ if (sysfs == NULL) + goto done; +- } +- while (fgets(n, NAME_MAX, f)) { +- sscanf(n, "%*[^ ] %[^ ] %[^ ] %*s\n", sysfs, fstype); +- if (strcasecmp(fstype, "sysfs") == 0) { +- foundsysfs++; +- break; +- } +- } +- fclose(f); +- if (! foundsysfs) { +- goto done; +- } + + /* Bus numbers in i2c-adapter don't necessarily match those in + i2c-dev and what we really care about are the i2c-dev numbers. + Unfortunately the names are harder to get in i2c-dev */ +- strcat(sysfs, "/class/i2c-dev"); +- if(!(dir = opendir(sysfs))) +- goto done; ++ if(!(dir = opendir(sysfs))) { ++ if (!try_load_i2c_dev_mod()) ++ goto done; ++ if ((!(dir = opendir(sysfs)))) ++ goto done; ++ } + /* go through the busses */ + while ((de = readdir(dir)) != NULL) { + if (!strcmp(de->d_name, ".")) +@@ -272,14 +407,15 @@ found: + /* We need more space */ + adapters = more_adapters(adapters, count + 1); + if (!adapters) +- return NULL; ++ goto done; + } + + adapters[count].nr = i2cbus; + adapters[count].name = strdup(s); + if (adapters[count].name == NULL) { + free_adapters(adapters); +- return NULL; ++ adapters = NULL; ++ goto done; + } + adapters[count].funcs = adap_types[type].funcs; + adapters[count].algo = adap_types[type].algo; +@@ -289,6 +425,7 @@ found: + closedir(dir); + + done: ++ free(sysfs); + return adapters; + } + +@@ -380,8 +517,21 @@ int open_i2c_dev(int i2cbus, char *filen + file = open(filename, O_RDWR); + + if (file < 0 && (errno == ENOENT || errno == ENOTDIR)) { ++ if (!(try_load_i2c_dev_mod())) ++ fprintf(stderr, "Cannot load i2c-dev module.\n"); ++ else ++ file = open(filename, O_RDWR); ++ } ++ ++ if (file < 0 && (errno == ENOENT || errno == ENOTDIR)) { + sprintf(filename, "/dev/i2c-%d", i2cbus); + file = open(filename, O_RDWR); ++ if (file < 0 && (errno == ENOENT || errno == ENOTDIR)) { ++ if (!(try_load_i2c_dev_mod())) ++ fprintf(stderr, "Cannot load i2c-dev module.\n"); ++ else ++ file = open(filename, O_RDWR); ++ } + } + + if (file < 0 && !quiet) { +diff -up i2c-tools-3.1.0/tools/Module.mk.load-i2cdev i2c-tools-3.1.0/tools/Module.mk +--- i2c-tools-3.1.0/tools/Module.mk.load-i2cdev 2009-01-19 16:11:33.000000000 +0100 ++++ i2c-tools-3.1.0/tools/Module.mk 2017-04-05 08:41:10.554057368 +0200 +@@ -15,6 +15,11 @@ TOOLS_CFLAGS := -Wstrict-prototypes -Wsh + + TOOLS_TARGETS := i2cdetect i2cdump i2cset i2cget + ++ifeq ($(shell pkg-config --exists libkmod && echo 1), 1) ++ TOOLS_CFLAGS += $(shell pkg-config --cflags libkmod) -DUSE_LIBKMOD ++ LDFLAGS += $(shell pkg-config --libs libkmod) ++endif ++ + # + # Programs + # diff --git a/SPECS/i2c-tools.spec b/SPECS/i2c-tools.spec index a599aed..5f51883 100644 --- a/SPECS/i2c-tools.spec +++ b/SPECS/i2c-tools.spec @@ -4,9 +4,11 @@ # This file and all modifications and additions to the pristine # package are under the same license as the package itself. +%global _i2c_tools_libdir /usr/lib + Name: i2c-tools Version: 3.1.0 -Release: 10%{?dist} +Release: 13%{?dist} Summary: A heterogeneous set of I2C tools for Linux Group: Applications/System License: GPLv2+ @@ -18,6 +20,8 @@ Source0: http://dl.lm-sensors.org/i2c-tools/releases/%{name}-%{version}.t Patch0: i2c-tools-3.1-man-eeproX.patch # Introducing man pages for decode-* binaries Patch1: i2c-tools-3.1-man-decodeX.patch +# Load i2c-dev module when i2cdetect is executed (bug #1071397) +Patch2: i2c-tools-3.1.0-load-i2cdev.patch # for /etc/udev/makedev.d resp /etc/modprobe.d ownership Requires: udev module-init-tools @@ -53,6 +57,7 @@ Group: Applications/System %patch0 -p1 %patch1 -p1 +%patch2 -p1 -b .load-i2cdev %build make CFLAGS="$RPM_OPT_FLAGS" @@ -84,9 +89,9 @@ rm -rf $RPM_BUILD_ROOT%{_includedir}/linux # and edid-decode is a more complete tool than decode-edid. rm -f $RPM_BUILD_ROOT%{_bindir}/{ddcmon,decode-edid} # for i2c-dev ondemand loading through kmod -mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/modprobe.d +mkdir -p $RPM_BUILD_ROOT%{_i2c_tools_libdir}/modprobe.d echo "alias char-major-89-* i2c-dev" > \ - $RPM_BUILD_ROOT%{_sysconfdir}/modprobe.d/i2c-dev.conf + $RPM_BUILD_ROOT%{_i2c_tools_libdir}/modprobe.d/i2c-dev.conf # for /dev/i2c-# creation (which are needed for kmod i2c-dev autoloading) mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/udev/makedev.d for (( i = 0 ; i < 8 ; i++ )) do @@ -96,7 +101,7 @@ done %files %doc CHANGES COPYING README -%config(noreplace) %{_sysconfdir}/modprobe.d/i2c-dev.conf +%config(noreplace) %{_i2c_tools_libdir}/modprobe.d/i2c-dev.conf %config(noreplace) %{_sysconfdir}/udev/makedev.d/99-i2c-dev.nodes %{_bindir}/* %{_sbindir}/* @@ -119,6 +124,16 @@ done %changelog +* Wed Apr 05 2017 Zdenek Dohnal - 3.1.0-13 +- added #ifndef for freeing dev_path in try_load_i2c_dev_mod function (rhbz#1071397) + +* Wed Mar 29 2017 Zdenek Dohnal - 3.1.0-12 +- fixing covscan errors for rhbz#1071397 + +* Wed Mar 29 2017 Zdenek Dohnal - 3.1.0-11 +- 1071397 - Load i2c-dev module when i2cdetect is executed +- 1195285 - Ship modprobe.d files in /usr/lib/modprobe.d + * Fri Dec 27 2013 Daniel Mach - 3.1.0-10 - Mass rebuild 2013-12-27