int main(int argc, char *argv[]) { static const char *matchfmt = "type='signal'," "interface='org.freedesktop.DBus.Properties'," "member='PropertiesChanged'," "arg0='org.openbmc.control.Power'," "path='%s'," "sender='%s'"; static const char *usage = "Usage: %s OBJECTPATH on|off\n"; static const size_t LEN = 256; sd_bus *conn = NULL; sd_event *loop = NULL; sd_bus_slot *slot = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; char *service = NULL; int r, dest = -1, state; char match[LEN]; if(argc < 3) { fprintf(stderr, usage, argv[0]); exit(EXIT_FAILURE); } if(!strcmp(argv[2], "on")) dest = 1; if(!strcmp(argv[2], "off")) dest = 0; if(dest != 0 && dest != 1) { fprintf(stderr, usage, argv[0]); exit(EXIT_FAILURE); } r = sd_bus_default_system(&conn); if(r < 0) { fprintf(stderr, "Error connecting to system bus: %s\n", strerror(-r)); goto finish; } r = mapper_get_service(conn, argv[1], &service); if (r < 0) { fprintf(stderr, "Error obtaining host service: %s\n", strerror(-r)); goto finish; } r = sd_event_default(&loop); if (r < 0) { fprintf(stderr, "Error obtaining event loop: %s\n", strerror(-r)); goto finish; } r = sd_bus_attach_event(conn, loop, SD_EVENT_PRIORITY_NORMAL); if (r < 0) { fprintf(stderr, "Failed to attach system " "bus to event loop: %s\n", strerror(-r)); goto finish; } if(strlen(matchfmt) + strnlen(argv[1], LEN) > LEN) { r = -E2BIG; fprintf(stderr, "Error adding match rule: %s\n", strerror(-r)); goto finish; } sprintf(match, matchfmt, argv[1], service); r = sd_bus_add_match(conn, &slot, match, callback, loop); if(r < 0) { fprintf(stderr, "Error adding match rule: %s\n", strerror(-r)); goto finish; } r = sd_bus_get_property_trivial(conn, service, argv[1], "org.openbmc.control.Power", "pgood", &error, 'i', &state); if(r < 0) { fprintf(stderr, "Error getting property: %s\n", strerror(-r)); goto finish; } if(dest == state) goto finish; r = sd_event_loop(loop); if(r < 0) { fprintf(stderr, "Error starting event loop: %s\n", strerror(-r)); goto finish; } finish: exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); }
//------------------------------------------------------------------- // Gets called by PowerOff handler when a Soft Power off is requested //------------------------------------------------------------------- static int soft_power_off(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { int64_t bt_resp = -1; int rc = 0; char *bus_name = NULL; // Steps to be taken when we get this. // 1: Send a SMS_ATN to the Host // 2: Host receives it and sends a GetMsgFlags IPMI command // 3: IPMID app handler will respond to that with a MSgFlag with bit:0x2 // set indicating we have a message for Host // 4: Host sends a GetMsgBuffer command and app handler will respond to // that with a OEM-SEL with certain fields packed indicating to the // host that it do a shutdown of the partitions. // 5: Host does the partition shutdown and calls Chassis Power off command // 6: App handler handles the command by making a call to ChassisManager // Dbus // Now the job is to send the SMS_ATTN. // Req message contains the specifics about which method etc that we want to // access on which bus, object sd_bus_message *response = NULL; // Error return mechanism sd_bus_error bus_error = SD_BUS_ERROR_NULL; // Gets a hook onto either a SYSTEM or SESSION bus sd_bus *bus = ipmid_get_sd_bus_connection(); rc = mapper_get_service(bus, object_name, &bus_name); if (rc < 0) { fprintf(stderr, "Failed to get %s bus name: %s\n", object_name, strerror(-rc)); goto finish; } rc = sd_bus_call_method(bus, // In the System Bus bus_name, // Service to contact object_name, // Object path intf_name, // Interface name "setAttention", // Method to be called &bus_error, // object to return error &response, // Response buffer if any NULL); // No input arguments if(rc < 0) { fprintf(stderr,"ERROR initiating Power Off:[%s]\n",bus_error.message); goto finish; } // See if we were able to successfully raise SMS_ATN rc = sd_bus_message_read(response, "x", &bt_resp); if (rc < 0) { fprintf(stderr, "Failed to get a rc from BT for SMS_ATN: %s\n", strerror(-rc)); goto finish; } finish: sd_bus_error_free(&bus_error); response = sd_bus_message_unref(response); free(bus_name); if(rc < 0) { return sd_bus_reply_method_return(m, "x", rc); } else { return sd_bus_reply_method_return(m, "x", bt_resp); } }