patch-2.4.25 linux-2.4.25/arch/ppc64/kernel/rtas-proc.c

Next file: linux-2.4.25/arch/ppc64/kernel/rtas.c
Previous file: linux-2.4.25/arch/ppc64/kernel/ras.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.24/arch/ppc64/kernel/rtas-proc.c linux-2.4.25/arch/ppc64/kernel/rtas-proc.c
@@ -124,6 +124,11 @@
 static unsigned long rtas_tone_volume = 0;
 static unsigned int open_token = 0;
 
+static int set_time_for_power_on = RTAS_UNKNOWN_SERVICE;
+static int set_time_of_day = RTAS_UNKNOWN_SERVICE;
+static int get_sensor_state = RTAS_UNKNOWN_SERVICE;
+static int set_indicator = RTAS_UNKNOWN_SERVICE;
+
 extern struct proc_dir_entry *proc_ppc64_root;
 extern struct proc_dir_entry *rtas_proc_dir;
 extern spinlock_t proc_ppc64_lock;
@@ -215,6 +220,8 @@
 void proc_rtas_init(void)
 {
 	struct proc_dir_entry *entry;
+	int display_character;
+	int errinjct_token;
 
 	rtas_node = find_devices("rtas");
 	if ((rtas_node == NULL) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) {
@@ -240,29 +247,51 @@
 		return;
 	}
 
-	/* /proc/rtas entries */
+	/*
+	 * /proc/rtas entries
+	 * only create entries if rtas token exists for desired function
+	 */
+
+	set_time_of_day = rtas_token("set-time-of-day");
+	if (set_time_of_day != RTAS_UNKNOWN_SERVICE) {
+		entry=create_proc_entry("clock",S_IRUGO|S_IWUSR,rtas_proc_dir);
+		if (entry) entry->proc_fops = &ppc_rtas_clock_operations;
+	}
 
-	entry = create_proc_entry("progress", S_IRUGO|S_IWUSR, rtas_proc_dir);
-	if (entry) entry->proc_fops = &ppc_rtas_progress_operations;
+	set_time_for_power_on = rtas_token("set-time-for-power-on");
+	if (set_time_for_power_on != RTAS_UNKNOWN_SERVICE) {
+		entry=create_proc_entry("poweron",S_IWUSR|S_IRUGO,rtas_proc_dir);
+		if (entry) entry->proc_fops = &ppc_rtas_poweron_operations;
+	}
 
-	entry = create_proc_entry("clock", S_IRUGO|S_IWUSR, rtas_proc_dir); 
-	if (entry) entry->proc_fops = &ppc_rtas_clock_operations;
+	get_sensor_state = rtas_token("get-sensor-state");
+	if (get_sensor_state != RTAS_UNKNOWN_SERVICE) {
+		create_proc_read_entry("sensors", S_IRUGO, rtas_proc_dir,
+				       ppc_rtas_sensor_read, NULL);
+	}
 
-	entry = create_proc_entry("poweron", S_IWUSR|S_IRUGO, rtas_proc_dir); 
-	if (entry) entry->proc_fops = &ppc_rtas_poweron_operations;
+	set_indicator = rtas_token("set-indicator");
+	if (set_indicator != RTAS_UNKNOWN_SERVICE) {
+		entry=create_proc_entry("frequency",S_IWUSR|S_IRUGO,rtas_proc_dir);
+		if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations;
 
-	create_proc_read_entry("sensors", S_IRUGO, rtas_proc_dir, 
-			ppc_rtas_sensor_read, NULL);
-	
-	entry = create_proc_entry("frequency", S_IWUSR|S_IRUGO, rtas_proc_dir); 
-	if (entry) entry->proc_fops = &ppc_rtas_tone_freq_operations;
+		entry=create_proc_entry("volume",S_IWUSR|S_IRUGO,rtas_proc_dir);
+		if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations;
+	}
 
-	entry = create_proc_entry("volume", S_IWUSR|S_IRUGO, rtas_proc_dir); 
-	if (entry) entry->proc_fops = &ppc_rtas_tone_volume_operations;
+	display_character = rtas_token("display-character");
+	if ((display_character != RTAS_UNKNOWN_SERVICE) ||
+	    (set_indicator != RTAS_UNKNOWN_SERVICE)) {
+		entry=create_proc_entry("progress",S_IRUGO|S_IWUSR,rtas_proc_dir);
+		if (entry) entry->proc_fops = &ppc_rtas_progress_operations;
+	}
 
 #ifdef CONFIG_RTAS_ERRINJCT
-	entry = create_proc_entry("errinjct", S_IWUSR|S_IRUGO, rtas_proc_dir);
-	if (entry) entry->proc_fops = &ppc_rtas_errinjct_operations;
+	errinjct_token = rtas_token("ibm,errinjct");
+	if (errinjct_token != RTAS_UNKNOWN_SERVICE) {
+		entry=create_proc_entry("errinjct",S_IWUSR|S_IRUGO,rtas_proc_dir);
+		if (entry) entry->proc_fops = &ppc_rtas_errinjct_operations;
+	}
 #endif
 
 }
@@ -273,12 +302,19 @@
 static ssize_t ppc_rtas_poweron_write(struct file * file, const char * buf,
 		size_t count, loff_t *ppos)
 {
+	char stkbuf[40];  /* its small, its on stack */
 	struct rtc_time tm;
 	unsigned long nowtime;
 	char *dest;
 	int error;
 
-	nowtime = simple_strtoul(buf, &dest, 10);
+	if (39 < count)
+		count = 39;
+	if (copy_from_user(stkbuf, buf, count))
+		return -EFAULT;
+
+	stkbuf[count] = 0;
+	nowtime = simple_strtoul(stkbuf, &dest, 10);
 	if (*dest != '\0' && *dest != '\n') {
 		printk("ppc_rtas_poweron_write: Invalid time\n");
 		return count;
@@ -287,11 +323,11 @@
 
 	to_tm(nowtime, &tm);
 
-	error = rtas_call(rtas_token("set-time-for-power-on"), 7, 1, NULL, 
-			tm.tm_year, tm.tm_mon, tm.tm_mday, 
+	error = rtas_call(set_time_for_power_on, 7, 1, NULL,
+			tm.tm_year, tm.tm_mon, tm.tm_mday,
 			tm.tm_hour, tm.tm_min, tm.tm_sec, 0 /* nano */);
 	if (error != 0)
-		printk(KERN_WARNING "error: setting poweron time returned: %s\n", 
+		printk(KERN_WARNING "error: setting poweron time returned: %s\n",
 				ppc_rtas_process_error(error));
 	return count;
 }
@@ -299,18 +335,23 @@
 static ssize_t ppc_rtas_poweron_read(struct file * file, char * buf,
 		size_t count, loff_t *ppos)
 {
+	char stkbuf[40];  /* its small, its on stack */
 	int n;
+
 	if (power_on_time == 0)
-		n = sprintf(buf, "Power on time not set\n");
+		n = snprintf(stkbuf, 40, "Power on time not set\n");
 	else
-		n = sprintf(buf, "%lu\n", power_on_time);
+		n = snprintf(stkbuf, 40, "%lu\n", power_on_time);
 
-	if (*ppos >= strlen(buf))
+	int sn = strlen(stkbuf) +1;
+	if (*ppos >= sn)
 		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
+	if (n > sn - *ppos)
+		n = sn - *ppos;
 	if (n > count)
 		n = count;
+	if (copy_to_user(buf, stkbuf + (*ppos), n))
+		return -EFAULT;
 	*ppos += n;
 	return n;
 }
@@ -323,11 +364,17 @@
 {
 	unsigned long hex;
 
-	strcpy(progress_led, buf); /* save the string */
+	if (count >= MAX_LINELENGTH)
+		count = MAX_LINELENGTH -1;
+	if (copy_from_user(progress_led, buf, count))
+		return -EFAULT;
+
+	progress_led[count] = 0;
+
 	/* Lets see if the user passed hexdigits */
-	hex = simple_strtoul(buf, NULL, 10);
-	
-	ppc_md.progress ((char *)buf, hex);
+	hex = simple_strtoul(progress_led, NULL, 10);
+
+	ppc_md.progress((char *)progress_led, hex);
 	return count;
 
 	/* clear the line */ /* ppc_md.progress("                   ", 0xffff);*/
@@ -336,15 +383,32 @@
 static ssize_t ppc_rtas_progress_read(struct file * file, char * buf,
 		size_t count, loff_t *ppos)
 {
-	int n = 0;
-	if (progress_led != NULL)
-		n = sprintf (buf, "%s\n", progress_led);
-	if (*ppos >= strlen(buf))
+	int n = 0, sn;
+	
+	if (progress_led == NULL)
+		return 0;
+
+	char * tmpbuf = kmalloc(MAX_LINELENGTH, GFP_KERNEL);
+	if (!tmpbuf) {
+		printk(KERN_ERR "error: kmalloc failed\n");
+		return -ENOMEM;
+	}
+	n = sprintf (tmpbuf, "%s\n", progress_led);
+
+	sn = strlen (tmpbuf) +1;
+	if (*ppos >= sn) {
+		kfree(tmpbuf);
 		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
+	}
+	if (n > sn - *ppos)
+		n = sn - *ppos;
 	if (n > count)
 		n = count;
+	if (copy_to_user(buf, tmpbuf + (*ppos), n)) {
+		kfree(tmpbuf);
+		return -EFAULT;
+	}
+	kfree(tmpbuf);
 	*ppos += n;
 	return n;
 }
@@ -355,12 +419,19 @@
 static ssize_t ppc_rtas_clock_write(struct file * file, const char * buf, 
 		size_t count, loff_t *ppos)
 {
+	char stkbuf[40];  /* its small, its on stack */
 	struct rtc_time tm;
 	unsigned long nowtime;
 	char *dest;
 	int error;
 
-	nowtime = simple_strtoul(buf, &dest, 10);
+	if (39 < count)
+		count = 39;
+	if (copy_from_user(stkbuf, buf, count))
+		return -EFAULT;
+
+	stkbuf[count] = 0;
+	nowtime = simple_strtoul(stkbuf, &dest, 10);
 	if (*dest != '\0' && *dest != '\n') {
 		printk("ppc_rtas_clock_write: Invalid time\n");
 		return count;
@@ -388,21 +459,27 @@
 	year = ret[0]; mon  = ret[1]; day  = ret[2];
 	hour = ret[3]; min  = ret[4]; sec  = ret[5];
 
+	char stkbuf[40];  /* its small, its on stack */
+
 	if (error != 0){
 		printk(KERN_WARNING "error: reading the clock returned: %s\n", 
 				ppc_rtas_process_error(error));
-		n = sprintf (buf, "0");
+		n = snprintf(stkbuf, 40, "0");
 	} else { 
-		n = sprintf (buf, "%lu\n", mktime(year, mon, day, hour, min, sec));
+		n = snprintf(stkbuf, 40, "%lu\n", mktime(year, mon, day, hour, min, sec));
 	}
 	kfree(ret);
 
-	if (*ppos >= strlen(buf))
+	int sn = strlen(stkbuf) +1;
+	if (*ppos >= sn)
 		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
+	if (n > sn - *ppos)
+		n = sn - *ppos;
 	if (n > count)
 		n = count;
+	if (copy_to_user(buf, stkbuf + (*ppos), n))
+		return -EFAULT;
+
 	*ppos += n;
 	return n;
 }
@@ -417,7 +494,6 @@
 	unsigned long ret;
 	int state, error;
 	char *buffer;
-	int get_sensor_state = rtas_token("get-sensor-state");
 
 	if (count < 0)
 		return -EINVAL;
@@ -431,8 +507,8 @@
 	memset(buffer, 0, MAX_LINELENGTH*MAX_SENSORS);
 
 	n  = sprintf ( buffer  , "RTAS (RunTime Abstraction Services) Sensor Information\n");
-	n += sprintf ( buffer+n, "Sensor\t\tValue\t\tCondition\tLocation\n");
-	n += sprintf ( buffer+n, "********************************************************\n");
+	n += sprintf ( buffer+n, "%-17s\t%-15s\t%-15s\tLocation\n", "Sensor", "Value", "Condition");
+	n += sprintf ( buffer+n, "***************************************************************************\n");
 
 	if (ppc_rtas_find_all_sensors() != 0) {
 		n += sprintf ( buffer+n, "\nNo sensors are available\n");
@@ -538,10 +614,10 @@
 		int error, char * buf) 
 {
 	/* Defined return vales */
-	const char * key_switch[]        = { "Off\t", "Normal\t", "Secure\t", "Mainenance" };
+	const char * key_switch[]        = { "Off", "Normal", "Secure", "Maintenance" };
 	const char * enclosure_switch[]  = { "Closed", "Open" };
 	const char * lid_status[]        = { " ", "Open", "Closed" };
-	const char * power_source[]      = { "AC\t", "Battery", "AC & Battery" };
+	const char * power_source[]      = { "AC", "Battery", "AC & Battery" };
 	const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" };
 	const char * epow_sensor[]       = { 
 		"EPOW Reset", "Cooling warning", "Power warning",
@@ -552,101 +628,108 @@
 	const char * ibm_drconnector[]     = { "Empty", "Present" };
 	const char * ibm_intqueue[]        = { "Disabled", "Enabled" };
 
-	int have_strings = 0;
 	int temperature = 0;
 	int unknown = 0;
 	int n = 0;
+	char *label_string = NULL;
+	const char **value_arr = NULL;
+	int value_arrsize = 0;
 
 	/* What kind of sensor do we have here? */
 	
 	switch (s.token) {
 		case KEY_SWITCH:
-			n += sprintf(buf+n, "Key switch:\t");
-			n += sprintf(buf+n, "%s\t", key_switch[state]);
-			have_strings = 1;
+			label_string = "Key switch:";
+			value_arrsize = sizeof(key_switch)/sizeof(char *);
+			value_arr = key_switch;
 			break;
 		case ENCLOSURE_SWITCH:
-			n += sprintf(buf+n, "Enclosure switch:\t");
-			n += sprintf(buf+n, "%s\t", enclosure_switch[state]);
-			have_strings = 1;
+			label_string = "Enclosure switch:";
+			value_arrsize = sizeof(enclosure_switch)/sizeof(char *);
+			value_arr = enclosure_switch;
 			break;
 		case THERMAL_SENSOR:
-			n += sprintf(buf+n, "Temp. (°C/°F):\t");
+			label_string = "Temp. (°C/°F):";
 			temperature = 1;
 			break;
 		case LID_STATUS:
-			n += sprintf(buf+n, "Lid status:\t");
-			n += sprintf(buf+n, "%s\t", lid_status[state]);
-			have_strings = 1;
+			label_string = "Lid status:";
+			value_arrsize = sizeof(lid_status)/sizeof(char *);
+			value_arr = lid_status;
 			break;
 		case POWER_SOURCE:
-			n += sprintf(buf+n, "Power source:\t");
-			n += sprintf(buf+n, "%s\t", power_source[state]);
-			have_strings = 1;
+			label_string = "Power source:";
+			value_arrsize = sizeof(power_source)/sizeof(char *);
+			value_arr = power_source;
 			break;
 		case BATTERY_VOLTAGE:
-			n += sprintf(buf+n, "Battery voltage:\t");
+			label_string = "Battery voltage:";
 			break;
 		case BATTERY_REMAINING:
-			n += sprintf(buf+n, "Battery remaining:\t");
-			n += sprintf(buf+n, "%s\t", battery_remaining[state]);
-			have_strings = 1;
+			label_string = "Battery remaining:";
+			value_arrsize = sizeof(battery_remaining)/sizeof(char *);
+			value_arr = battery_remaining;
 			break;
 		case BATTERY_PERCENTAGE:
-			n += sprintf(buf+n, "Battery percentage:\t");
+			label_string = "Battery percentage:";
 			break;
 		case EPOW_SENSOR:
-			n += sprintf(buf+n, "EPOW Sensor:\t");
-			n += sprintf(buf+n, "%s\t", epow_sensor[state]);
-			have_strings = 1;
+			label_string = "EPOW Sensor:";
+			value_arrsize = sizeof(epow_sensor)/sizeof(char *);
+			value_arr = epow_sensor;
 			break;
 		case BATTERY_CYCLESTATE:
-			n += sprintf(buf+n, "Battery cyclestate:\t");
-			n += sprintf(buf+n, "%s\t", battery_cyclestate[state]);
-			have_strings = 1;
+			label_string = "Battery cyclestate:";
+			value_arrsize = sizeof(battery_cyclestate)/sizeof(char *);
+			value_arr = battery_cyclestate;
 			break;
 		case BATTERY_CHARGING:
-			n += sprintf(buf+n, "Battery Charging:\t");
-			n += sprintf(buf+n, "%s\t", battery_charging[state]);
-			have_strings = 1;
+			label_string = "Battery Charging:";
+			value_arrsize = sizeof(battery_charging)/sizeof(char *);
+			value_arr = battery_charging;
 			break;
 		case IBM_SURVEILLANCE:
-			n += sprintf(buf+n, "Surveillance:\t");
+			label_string = "Surveillance:";
 			break;
 		case IBM_FANRPM:
-			n += sprintf(buf+n, "Fan (rpm):\t");
+			label_string = "Fan (rpm):";
 			break;
 		case IBM_VOLTAGE:
-			n += sprintf(buf+n, "Voltage (mv):\t");
+			label_string = "Voltage (mv):";
 			break;
 		case IBM_DRCONNECTOR:
-			n += sprintf(buf+n, "DR connector:\t");
-			n += sprintf(buf+n, "%s\t", ibm_drconnector[state]);
-			have_strings = 1;
+			label_string = "DR connector:";
+			value_arrsize = sizeof(ibm_drconnector)/sizeof(char *);
+			value_arr = ibm_drconnector;
 			break;
 		case IBM_POWERSUPPLY:
-			n += sprintf(buf+n, "Powersupply:\t");
+			label_string = "Powersupply:";
 			break;
 		case IBM_INTQUEUE:
-			n += sprintf(buf+n, "Interrupt queue:\t");
-			n += sprintf(buf+n, "%s\t", ibm_intqueue[state]);
-			have_strings = 1;
+			label_string = "Interrupt queue:";
+			value_arrsize = sizeof(ibm_intqueue)/sizeof(char *);
+			value_arr = ibm_intqueue;
 			break;
 		default:
 			n += sprintf(buf+n,  "Unkown sensor (type %d), ignoring it\n",
 					s.token);
 			unknown = 1;
-			have_strings = 1;
 			break;
 	}
-	if (have_strings == 0) {
+
+	if (label_string)
+		n += sprintf(buf+n, "%-17s\t", label_string);
+
+	if (value_arr && state >= 0 && state < value_arrsize) {
+		n += sprintf(buf+n, "%-15s\t", value_arr[state]);
+	} else {
 		if (temperature) {
-			n += sprintf(buf+n, "%4d /%4d\t", state, cel_to_fahr(state));
+			n += sprintf(buf+n, "%2d / %2d  \t", state, cel_to_fahr(state));
 		} else
-			n += sprintf(buf+n, "%10d\t", state);
+			n += sprintf(buf+n, "%-10d\t", state);
 	}
 	if (unknown == 0) {
-		n += sprintf ( buf+n, "%s\t", ppc_rtas_process_error(error));
+		n += sprintf ( buf+n, "%-15s\t", ppc_rtas_process_error(error));
 		n += get_location_code(s, buf+n);
 	}
 	return n;
@@ -751,7 +834,7 @@
 		n += check_location_string(ret, buffer + n);
 		n += sprintf ( buffer+n, " ");
 		/* see how many characters we have printed */
-		sprintf ( t, "%s ", ret);
+		snprintf( t, 50, "%s ", ret);
 
 		pos += strlen(t);
 		if (pos >= llen) pos=0;
@@ -764,17 +847,25 @@
 static ssize_t ppc_rtas_tone_freq_write(struct file * file, const char * buf,
 		size_t count, loff_t *ppos)
 {
+	char stkbuf[40];  /* its small, its on stack */
 	unsigned long freq;
 	char *dest;
 	int error;
-	freq = simple_strtoul(buf, &dest, 10);
+
+	if (39 < count)
+		count = 39;
+	if (copy_from_user(stkbuf, buf, count))
+		return -EFAULT;
+
+	stkbuf[count] = 0;
+	freq = simple_strtoul(stkbuf, &dest, 10);
 	if (*dest != '\0' && *dest != '\n') {
 		printk("ppc_rtas_tone_freq_write: Invalid tone freqency\n");
 		return count;
 	}
 	if (freq < 0) freq = 0;
 	rtas_tone_frequency = freq; /* save it for later */
-	error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
+	error = rtas_call(set_indicator, 3, 1, NULL,
 			TONE_FREQUENCY, 0, freq);
 	if (error != 0)
 		printk(KERN_WARNING "error: setting tone frequency returned: %s\n", 
@@ -785,15 +876,21 @@
 static ssize_t ppc_rtas_tone_freq_read(struct file * file, char * buf,
 		size_t count, loff_t *ppos)
 {
-	int n;
-	n = sprintf(buf, "%lu\n", rtas_tone_frequency);
+	int n, sn;
+	char stkbuf[40];  /* its small, its on stack */
+
+	n = snprintf(stkbuf, 40, "%lu\n", rtas_tone_frequency);
 
-	if (*ppos >= strlen(buf))
+	sn = strlen(stkbuf) +1;
+	if (*ppos >= sn)
 		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
+	if (n > sn - *ppos)
+		n = sn - *ppos;
 	if (n > count)
 		n = count;
+	if (copy_to_user(buf, stkbuf + (*ppos), n))
+		return -EFAULT;
+
 	*ppos += n;
 	return n;
 }
@@ -803,10 +900,18 @@
 static ssize_t ppc_rtas_tone_volume_write(struct file * file, const char * buf,
 		size_t count, loff_t *ppos)
 {
+	char stkbuf[40];  /* its small, its on stack */
 	unsigned long volume;
 	char *dest;
 	int error;
-	volume = simple_strtoul(buf, &dest, 10);
+
+	if (39 < count)
+		count = 39;
+	if (copy_from_user(stkbuf, buf, count))
+		return -EFAULT;
+
+	stkbuf[count] = 0;
+	volume = simple_strtoul(stkbuf, &dest, 10);
 	if (*dest != '\0' && *dest != '\n') {
 		printk("ppc_rtas_tone_volume_write: Invalid tone volume\n");
 		return count;
@@ -815,7 +920,7 @@
 	if (volume > 100) volume = 100;
 	
         rtas_tone_volume = volume; /* save it for later */
-	error = rtas_call(rtas_token("set-indicator"), 3, 1, NULL,
+	error = rtas_call(set_indicator, 3, 1, NULL,
 			TONE_VOLUME, 0, volume);
 	if (error != 0)
 		printk(KERN_WARNING "error: setting tone volume returned: %s\n", 
@@ -826,15 +931,20 @@
 static ssize_t ppc_rtas_tone_volume_read(struct file * file, char * buf,
 		size_t count, loff_t *ppos)
 {
-	int n;
-	n = sprintf(buf, "%lu\n", rtas_tone_volume);
+	int n, sn;
+	char stkbuf[40];  /* its small, its on stack */
 
-	if (*ppos >= strlen(buf))
+	n = snprintf(stkbuf, 40, "%lu\n", rtas_tone_volume);
+	sn = strlen(stkbuf) +1;
+	if (*ppos >= sn)
 		return 0;
-	if (n > strlen(buf) - *ppos)
-		n = strlen(buf) - *ppos;
+	if (n > sn - *ppos)
+		n = sn - *ppos;
 	if (n > count)
 		n = count;
+	if (copy_to_user(buf, stkbuf + (*ppos), n))
+		return -EFAULT;
+
 	*ppos += n;
 	return n;
 }
@@ -864,7 +974,7 @@
 static ssize_t ppc_rtas_errinjct_write(struct file * file, const char * buf,
 				       size_t count, loff_t *ppos)
 {
- 
+ 	char * tmpbuf;
 	char * ei_token;
 	char * workspace = NULL;
 	size_t max_len;
@@ -878,16 +988,26 @@
 		max_len = ERRINJCT_TOKEN_LEN;
 	}
 
-	token_len = strnlen(buf, max_len);
+	tmpbuf = (char *) kmalloc(max_len, GFP_KERNEL);
+	if (!tmpbuf) {
+		printk(KERN_WARNING "error: kmalloc failed\n");
+		return -ENOMEM;
+	}
+	if (copy_from_user (tmpbuf, buf, max_len)) {
+		kfree(tmpbuf);
+		return -EFAULT;
+	}
+	token_len = strnlen(tmpbuf, max_len);
 	token_len++; /* Add one for the null termination */
     
 	ei_token = (char *)kmalloc(token_len, GFP_KERNEL);
 	if (!ei_token) {
 		printk(KERN_WARNING "error: kmalloc failed\n");
+		kfree(tmpbuf);
 		return -ENOMEM;
 	}
 
-	strncpy(ei_token, buf, token_len);
+	strncpy(ei_token, tmpbuf, token_len);
     
 	if (count > token_len + WORKSPACE_SIZE) {
 		count = token_len + WORKSPACE_SIZE;
@@ -907,11 +1027,12 @@
 		workspace = (char *)kmalloc(max_len, GFP_KERNEL);
 		if (!workspace) {
 			printk(KERN_WARNING "error: failed kmalloc\n");
+			kfree(tmpbuf);
 			kfree(ei_token);
 			return -ENOMEM;
 		}
 	
-		memcpy(workspace, buf, max_len);
+		memcpy(workspace, tmpbuf, max_len);
 	}
 
 	rc = rtas_errinjct(open_token, ei_token, workspace);
@@ -920,6 +1041,7 @@
 		kfree(workspace);
 	}
 	kfree(ei_token);
+	kfree(tmpbuf);
 
 	return rc < 0 ? rc : count;
 }
@@ -940,32 +1062,36 @@
 				      size_t count, loff_t *ppos) 
 {
 	char * buffer;
-	int i;
+	int i, sn;
 	int n = 0;
 
-	buffer = (char *)kmalloc(MAX_ERRINJCT_TOKENS * (ERRINJCT_TOKEN_LEN+1),
-				 GFP_KERNEL);
+	int m = MAX_ERRINJCT_TOKENS * (ERRINJCT_TOKEN_LEN+1);
+	buffer = (char *)kmalloc(m, GFP_KERNEL);
 	if (!buffer) {
 		printk(KERN_ERR "error: kmalloc failed\n");
 		return -ENOMEM;
 	}
 
 	for (i = 0; i < MAX_ERRINJCT_TOKENS && ei_token_list[i].value; i++) {
-		n += sprintf(buffer+n, ei_token_list[i].name);
-		n += sprintf(buffer+n, "\n");
+		n += snprintf(buffer+n, m-n, ei_token_list[i].name);
+		n += snprintf(buffer+n, m-n, "\n");
 	}
 
-	if (*ppos >= strlen(buffer)) {
+	sn = strlen(buffer) +1;
+	if (*ppos >= sn) {
 		kfree(buffer);
 		return 0;
 	}
-	if (n > strlen(buffer) - *ppos)
-		n = strlen(buffer) - *ppos;
+	if (n > sn - *ppos)
+		n = sn - *ppos;
 
 	if (n > count)
 		n = count;
 
-	memcpy(buf, buffer + *ppos, n);
+	if (copy_to_user(buf, buffer + *ppos, n)) {
+		kfree(buffer);
+		return -EFAULT;
+	}
 
 	*ppos += n;
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)