udev/firmware_helper.c
Harald Hoyer 44e34d2079 - improved error msg for firmware_helper (bug #206944)
- added xpram symlink to slram device nodes (bug #135733)
- removed infiniband rules (bug #206224)
- use newest path_id script (bug #207139)
2006-09-25 15:02:11 +00:00

142 lines
2.6 KiB
C

/*
* A simple firmware helper program.
*
* Copyright 2005 Red Hat, Inc.
*
* This software may be freely redistributed under the terms of the GNU
* public license.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <sys/stat.h>
#define FIRMWARE_PATH "/lib/firmware"
void log_err(char *firmware, int err) {
char *driver;
driver = getenv("PHYSDEVDRIVER");
if (!driver)
driver = "(unknown)";
openlog("firmware_helper",LOG_PID,LOG_USER);
syslog(LOG_ERR,"Loading of %s for %s driver failed: %s",firmware, driver, strerror(err));
closelog();
}
/* Set the 'loading' attribute for a firmware device.
* 1 == currently loading
* 0 == done loading
* -1 == error
*/
int set_loading(char *device, int value) {
char *path;
int rc;
FILE *f;
path = alloca(strlen(device)+15);
sprintf(path,"/sys/%s/loading", device);
f = fopen(path, "w");
if (!f)
return 1;
rc = fprintf(f, "%d", value);
fclose(f);
if (rc < 0)
return rc;
return 0;
}
int main(int argc, char **argv) {
char *devpath, *firmware, *action;
struct stat sbuf;
int fw_fd, count;
int rc;
char *fw_path, *data_path;
char *fw_buffer;
devpath = getenv("DEVPATH");
if (!devpath) return 0;
firmware = getenv("FIRMWARE");
if (!firmware) return 0;
action = getenv("ACTION");
if (strcmp(action,"add"))
return 0;
set_loading(devpath, 1);
fw_path = malloc(strlen(FIRMWARE_PATH) + strlen(firmware) + 2);
if (!fw_path) {
rc = errno;
goto out_err;
}
sprintf(fw_path,"%s/%s", FIRMWARE_PATH, firmware);
fw_fd = open(fw_path, O_RDONLY);
if (fw_fd == -1) {
rc = errno;
goto out_err;
}
fstat(fw_fd, &sbuf);
fw_buffer = malloc(sbuf.st_size);
if (!fw_buffer) {
rc = errno;
goto out_err;
}
if (read(fw_fd, fw_buffer, sbuf.st_size) != sbuf.st_size) {
rc = errno;
goto out_err;
}
close(fw_fd);
data_path = malloc(strlen(devpath) + 12);
if (!data_path) {
rc = errno;
goto out_err;
}
sprintf(data_path,"/sys/%s/data", devpath);
fw_fd = open(data_path, O_RDWR);
if (fw_fd == -1) {
rc = errno;
fw_path = data_path;
goto out_err;
}
count = 0;
while (count < sbuf.st_size) {
int c;
c = write(fw_fd,fw_buffer+count,sbuf.st_size-count);
if (c <= 0) {
rc = errno;
goto out_err;
}
count += c;
}
close(fw_fd);
set_loading(devpath, 0);
return 0;
out_err:
if (fw_fd >= 0)
close(fw_fd);
set_loading(devpath, -1);
log_err(fw_path, rc);
return rc;
}