diff options
author | Corey Minyard <minyard@acm.org> | 2005-09-06 18:18:46 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-07 19:57:49 -0400 |
commit | 8c702e16207c70119d03df924de35f8c3629a5c4 (patch) | |
tree | f2d8ae84df7fd510f135a8074e0da67592372138 | |
parent | 877197ef89aa486c8eea369a9357af34381d11e0 (diff) |
[PATCH] ipmi poweroff: fix chassis control
The IPMI power control function proc_write_chassctrl was badly written, it
directly used userspace pointers, it assumed that strings were NULL
terminated, and it used the evil sscanf function. This converts over to
using the sysctl interface for this data and changes the semantics to be a
little more logical.
Signed-off-by: Corey Minyard <minyard@acm.org>
Cc: <viro@parcelfarce.linux.theplanet.co.uk>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | Documentation/IPMI.txt | 13 | ||||
-rw-r--r-- | drivers/char/ipmi/ipmi_poweroff.c | 132 | ||||
-rw-r--r-- | include/linux/sysctl.h | 6 |
3 files changed, 71 insertions, 80 deletions
diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt index 84d3d4d10c17..bf1cf98d2a27 100644 --- a/Documentation/IPMI.txt +++ b/Documentation/IPMI.txt | |||
@@ -605,12 +605,13 @@ is in the ipmi_poweroff module. When the system requests a powerdown, | |||
605 | it will send the proper IPMI commands to do this. This is supported on | 605 | it will send the proper IPMI commands to do this. This is supported on |
606 | several platforms. | 606 | several platforms. |
607 | 607 | ||
608 | There is a module parameter named "poweroff_control" that may either be zero | 608 | There is a module parameter named "poweroff_powercycle" that may |
609 | (do a power down) or 2 (do a power cycle, power the system off, then power | 609 | either be zero (do a power down) or non-zero (do a power cycle, power |
610 | it on in a few seconds). Setting ipmi_poweroff.poweroff_control=x will do | 610 | the system off, then power it on in a few seconds). Setting |
611 | the same thing on the kernel command line. The parameter is also available | 611 | ipmi_poweroff.poweroff_control=x will do the same thing on the kernel |
612 | via the proc filesystem in /proc/ipmi/poweroff_control. Note that if the | 612 | command line. The parameter is also available via the proc filesystem |
613 | system does not support power cycling, it will always to the power off. | 613 | in /proc/sys/dev/ipmi/poweroff_powercycle. Note that if the system |
614 | does not support power cycling, it will always do the power off. | ||
614 | 615 | ||
615 | Note that if you have ACPI enabled, the system will prefer using ACPI to | 616 | Note that if you have ACPI enabled, the system will prefer using ACPI to |
616 | power off. | 617 | power off. |
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index 42ea9843b394..e82a96ba396b 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c | |||
@@ -52,11 +52,11 @@ extern void (*pm_power_off)(void); | |||
52 | #define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */ | 52 | #define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */ |
53 | 53 | ||
54 | /* the IPMI data command */ | 54 | /* the IPMI data command */ |
55 | static int poweroff_control = IPMI_CHASSIS_POWER_DOWN; | 55 | static int poweroff_powercycle; |
56 | 56 | ||
57 | /* parameter definition to allow user to flag power cycle */ | 57 | /* parameter definition to allow user to flag power cycle */ |
58 | module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN); | 58 | module_param(poweroff_powercycle, int, 0); |
59 | MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); | 59 | MODULE_PARM_DESC(poweroff_powercycles, " Set to non-zero to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); |
60 | 60 | ||
61 | /* Stuff from the get device id command. */ | 61 | /* Stuff from the get device id command. */ |
62 | static unsigned int mfg_id; | 62 | static unsigned int mfg_id; |
@@ -385,37 +385,34 @@ static void ipmi_poweroff_chassis (ipmi_user_t user) | |||
385 | 385 | ||
386 | powercyclefailed: | 386 | powercyclefailed: |
387 | printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", | 387 | printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", |
388 | ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle")); | 388 | (poweroff_powercycle ? "cycle" : "down")); |
389 | 389 | ||
390 | /* | 390 | /* |
391 | * Power down | 391 | * Power down |
392 | */ | 392 | */ |
393 | send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; | 393 | send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; |
394 | send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; | 394 | send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; |
395 | data[0] = poweroff_control; | 395 | if (poweroff_powercycle) |
396 | data[0] = IPMI_CHASSIS_POWER_CYCLE; | ||
397 | else | ||
398 | data[0] = IPMI_CHASSIS_POWER_DOWN; | ||
396 | send_msg.data = data; | 399 | send_msg.data = data; |
397 | send_msg.data_len = sizeof(data); | 400 | send_msg.data_len = sizeof(data); |
398 | rv = ipmi_request_in_rc_mode(user, | 401 | rv = ipmi_request_in_rc_mode(user, |
399 | (struct ipmi_addr *) &smi_addr, | 402 | (struct ipmi_addr *) &smi_addr, |
400 | &send_msg); | 403 | &send_msg); |
401 | if (rv) { | 404 | if (rv) { |
402 | switch (poweroff_control) { | 405 | if (poweroff_powercycle) { |
403 | case IPMI_CHASSIS_POWER_CYCLE: | 406 | /* power cycle failed, default to power down */ |
404 | /* power cycle failed, default to power down */ | 407 | printk(KERN_ERR PFX "Unable to send chassis power " \ |
405 | printk(KERN_ERR PFX "Unable to send chassis power " \ | 408 | "cycle message, IPMI error 0x%x\n", rv); |
406 | "cycle message, IPMI error 0x%x\n", rv); | 409 | poweroff_powercycle = 0; |
407 | poweroff_control = IPMI_CHASSIS_POWER_DOWN; | 410 | goto powercyclefailed; |
408 | goto powercyclefailed; | ||
409 | |||
410 | case IPMI_CHASSIS_POWER_DOWN: | ||
411 | default: | ||
412 | printk(KERN_ERR PFX "Unable to send chassis power " \ | ||
413 | "down message, IPMI error 0x%x\n", rv); | ||
414 | break; | ||
415 | } | 411 | } |
416 | } | ||
417 | 412 | ||
418 | return; | 413 | printk(KERN_ERR PFX "Unable to send chassis power " \ |
414 | "down message, IPMI error 0x%x\n", rv); | ||
415 | } | ||
419 | } | 416 | } |
420 | 417 | ||
421 | 418 | ||
@@ -561,39 +558,35 @@ static struct ipmi_smi_watcher smi_watcher = | |||
561 | 558 | ||
562 | 559 | ||
563 | #ifdef CONFIG_PROC_FS | 560 | #ifdef CONFIG_PROC_FS |
564 | /* displays properties to proc */ | 561 | #include <linux/sysctl.h> |
565 | static int proc_read_chassctrl(char *page, char **start, off_t off, int count, | 562 | |
566 | int *eof, void *data) | 563 | static ctl_table ipmi_table[] = { |
567 | { | 564 | { .ctl_name = DEV_IPMI_POWEROFF_POWERCYCLE, |
568 | return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n", | 565 | .procname = "poweroff_powercycle", |
569 | poweroff_control); | 566 | .data = &poweroff_powercycle, |
570 | } | 567 | .maxlen = sizeof(poweroff_powercycle), |
568 | .mode = 0644, | ||
569 | .proc_handler = &proc_dointvec }, | ||
570 | { } | ||
571 | }; | ||
571 | 572 | ||
572 | /* process property writes from proc */ | 573 | static ctl_table ipmi_dir_table[] = { |
573 | static int proc_write_chassctrl(struct file *file, const char *buffer, | 574 | { .ctl_name = DEV_IPMI, |
574 | unsigned long count, void *data) | 575 | .procname = "ipmi", |
575 | { | 576 | .mode = 0555, |
576 | int rv = count; | 577 | .child = ipmi_table }, |
577 | unsigned int newval = 0; | 578 | { } |
578 | 579 | }; | |
579 | sscanf(buffer, "%d", &newval); | ||
580 | switch (newval) { | ||
581 | case IPMI_CHASSIS_POWER_CYCLE: | ||
582 | printk(KERN_INFO PFX "power cycle is now enabled\n"); | ||
583 | poweroff_control = newval; | ||
584 | break; | ||
585 | |||
586 | case IPMI_CHASSIS_POWER_DOWN: | ||
587 | poweroff_control = IPMI_CHASSIS_POWER_DOWN; | ||
588 | break; | ||
589 | |||
590 | default: | ||
591 | rv = -EINVAL; | ||
592 | break; | ||
593 | } | ||
594 | 580 | ||
595 | return rv; | 581 | static ctl_table ipmi_root_table[] = { |
596 | } | 582 | { .ctl_name = CTL_DEV, |
583 | .procname = "dev", | ||
584 | .mode = 0555, | ||
585 | .child = ipmi_dir_table }, | ||
586 | { } | ||
587 | }; | ||
588 | |||
589 | static struct ctl_table_header *ipmi_table_header; | ||
597 | #endif /* CONFIG_PROC_FS */ | 590 | #endif /* CONFIG_PROC_FS */ |
598 | 591 | ||
599 | /* | 592 | /* |
@@ -601,41 +594,32 @@ static int proc_write_chassctrl(struct file *file, const char *buffer, | |||
601 | */ | 594 | */ |
602 | static int ipmi_poweroff_init (void) | 595 | static int ipmi_poweroff_init (void) |
603 | { | 596 | { |
604 | int rv; | 597 | int rv; |
605 | struct proc_dir_entry *file; | ||
606 | 598 | ||
607 | printk ("Copyright (C) 2004 MontaVista Software -" | 599 | printk ("Copyright (C) 2004 MontaVista Software -" |
608 | " IPMI Powerdown via sys_reboot.\n"); | 600 | " IPMI Powerdown via sys_reboot.\n"); |
609 | 601 | ||
610 | switch (poweroff_control) { | 602 | if (poweroff_powercycle) |
611 | case IPMI_CHASSIS_POWER_CYCLE: | 603 | printk(KERN_INFO PFX "Power cycle is enabled.\n"); |
612 | printk(KERN_INFO PFX "Power cycle is enabled.\n"); | ||
613 | break; | ||
614 | 604 | ||
615 | case IPMI_CHASSIS_POWER_DOWN: | 605 | #ifdef CONFIG_PROC_FS |
616 | default: | 606 | ipmi_table_header = register_sysctl_table(ipmi_root_table, 1); |
617 | poweroff_control = IPMI_CHASSIS_POWER_DOWN; | 607 | if (!ipmi_table_header) { |
618 | break; | 608 | printk(KERN_ERR PFX "Unable to register powercycle sysctl\n"); |
609 | rv = -ENOMEM; | ||
610 | goto out_err; | ||
619 | } | 611 | } |
612 | #endif | ||
620 | 613 | ||
614 | #ifdef CONFIG_PROC_FS | ||
621 | rv = ipmi_smi_watcher_register(&smi_watcher); | 615 | rv = ipmi_smi_watcher_register(&smi_watcher); |
616 | #endif | ||
622 | if (rv) { | 617 | if (rv) { |
618 | unregister_sysctl_table(ipmi_table_header); | ||
623 | printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); | 619 | printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); |
624 | goto out_err; | 620 | goto out_err; |
625 | } | 621 | } |
626 | 622 | ||
627 | #ifdef CONFIG_PROC_FS | ||
628 | file = create_proc_entry("poweroff_control", 0, proc_ipmi_root); | ||
629 | if (!file) { | ||
630 | printk(KERN_ERR PFX "Unable to create proc power control\n"); | ||
631 | } else { | ||
632 | file->nlink = 1; | ||
633 | file->read_proc = proc_read_chassctrl; | ||
634 | file->write_proc = proc_write_chassctrl; | ||
635 | file->owner = THIS_MODULE; | ||
636 | } | ||
637 | #endif | ||
638 | |||
639 | out_err: | 623 | out_err: |
640 | return rv; | 624 | return rv; |
641 | } | 625 | } |
@@ -646,7 +630,7 @@ static __exit void ipmi_poweroff_cleanup(void) | |||
646 | int rv; | 630 | int rv; |
647 | 631 | ||
648 | #ifdef CONFIG_PROC_FS | 632 | #ifdef CONFIG_PROC_FS |
649 | remove_proc_entry("poweroff_control", proc_ipmi_root); | 633 | unregister_sysctl_table(ipmi_table_header); |
650 | #endif | 634 | #endif |
651 | 635 | ||
652 | ipmi_smi_watcher_unregister(&smi_watcher); | 636 | ipmi_smi_watcher_unregister(&smi_watcher); |
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index e82be96d4906..532a6c5c24e9 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h | |||
@@ -711,6 +711,7 @@ enum { | |||
711 | DEV_RAID=4, | 711 | DEV_RAID=4, |
712 | DEV_MAC_HID=5, | 712 | DEV_MAC_HID=5, |
713 | DEV_SCSI=6, | 713 | DEV_SCSI=6, |
714 | DEV_IPMI=7, | ||
714 | }; | 715 | }; |
715 | 716 | ||
716 | /* /proc/sys/dev/cdrom */ | 717 | /* /proc/sys/dev/cdrom */ |
@@ -776,6 +777,11 @@ enum { | |||
776 | DEV_SCSI_LOGGING_LEVEL=1, | 777 | DEV_SCSI_LOGGING_LEVEL=1, |
777 | }; | 778 | }; |
778 | 779 | ||
780 | /* /proc/sys/dev/ipmi */ | ||
781 | enum { | ||
782 | DEV_IPMI_POWEROFF_POWERCYCLE=1, | ||
783 | }; | ||
784 | |||
779 | /* /proc/sys/abi */ | 785 | /* /proc/sys/abi */ |
780 | enum | 786 | enum |
781 | { | 787 | { |