I'm trying to replicate the behavior of a Windows app on Linux. Specifically, to control the backlighting on a keyboard.
Using Wireshark (on the linux host) to observer what the Windows tool does (when run on a Windows guest), I see a pair of URB_INTERRUPT out messages followed by a pair of URB_INTERRUPT in messages (one of each in each direction).
I've never used libusb before, but reading docs and examples, I've put together the code below. When run, libusb_interrupt_transfer() returns LIBUSB_ERROR_IO. Maybe I'm passing the wrong parameters, maybe I missed some initialization step, this is where my lack of experience with libusb really shines.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libusb-1.0/libusb.h>
int main(int argc, char *argv[]) {
unsigned int interface = 2;
int bSent = 0;
int retval = 0;
unsigned char msg[64];
unsigned char bytes[] = "\x51\x2c\x00\x00\xff\x64\x00\xff\xff\x72\x67\x62";
bzero(msg, sizeof(msg));
memcpy(msg, bytes, sizeof(bytes));
libusb_device_handle *devh;
libusb_init(NULL);
devh = libusb_open_device_with_vid_pid(NULL, 0x0b05, 0x1875);
if (devh) {
printf("Found device\n");
} else {
printf("ERROR: can't find device\n");
exit(1);
}
retval = libusb_set_auto_detach_kernel_driver(devh, interface);
if (!retval) {
printf("Set auto detach kernel driver\n");
} else {
printf("ERROR: failed to set auto detach kernel driver: %s\n", libusb_strerror(retval));
exit(1);
}
retval = libusb_claim_interface(devh, interface);
if (retval < 0) {
printf("ERROR: failed to claim interface %d: %s\n", interface, libusb_strerror(retval));
exit(1);
} else {
printf("Claimed interface %d\n", interface);
}
retval = libusb_interrupt_transfer(devh, interface, msg, sizeof(msg), &bSent, 1000);
if (retval < 0) {
printf("ERROR: libusb_interrupt_transfer() returned %d: %s\n", retval, libusb_strerror(retval));
} else {
printf("libusb_interrupt_transfer() sent %d bytes\n", bSent);
}
libusb_release_interface(devh, interface);
libusb_close(devh);
libusb_exit(NULL);
return(0);
}
Output:
Found device
Set auto detach kernel driver
Claimed interface 2
ERROR: libusb_interrupt_transfer() returned -1: Input/Output Error
Related
I am working on Debian GNU/Hurd with Mach. I have been asked to write a program that, given a PID and an address, executes vm_read over the address and prints the result.
This is the code I have written:
#include <mach_error.h>
#include <mach/mig_errors.h>
#include <mach/thread_status.h>
#include <mach/processor_info.h>
#include <mach/i386/vm_param.h>
#include <stdio.h>
#include <stdlib.h>
#include <hurd.h>
#include <string.h>
int main(int argc, char * argv[]) {
if(argc != 3) {
printf ("Wrong arguments: ./vm_read PID address\n");
exit(1);
}
int res;
mach_port_t target_task = pid2task(atoi(argv[1]));
vm_address_t addr = atoi(argv[2]);
vm_offset_t *data;
mach_msg_type_number_t data_count;
res = vm_read (target_task, addr, sizeof(int), &data, &data_count);
if (res != KERN_SUCCESS) {
printf ("Error reading virtual mem (0x%x), %s \n", res,
mach_error_string(res));
exit(1);
}
printf("done\n");
for (int i=0; i<data_count; ++i){
printf("byte %d : %x\n",i,((char*)data)[i]);
}
}
It works correctly, but now I'm asked if it is possible to write a version for Unix/Linux and another for Windows that do the same thing.
I've been searching and it looks like it shouldn't be any problem because both use virtual memory in their procceses, but I'm not sure if there could be complications with permissions or anything else.
For Windows, if you need to read memory from a process, you'll need to request the PROCESS_VM_READ when you get your handle to the process (ReadProcessMemory is the appropriate call). In order to get that Handle, it's usually easier to start the process yourself with OpenProcess.
There's no standard way to access the memory of another process on UNIX, but on Linux, you can do it by reading the special file /proc/pid/mem:
char memfile[32];
snprintf(memfile, sizeof(memfile), "/proc/%s/mem", argv[1]);
int mfd = open(memfile, O_RDONLY);
if (mfd < 0) {
perror("Can't open pid/mem file");
exit(1); }
if (lseek(mfd, (off_t)strtoull(argv[2], 0, 0), SEEK_SET) {
perror("Can't seek to address");
exit(1); }
if (read(mfd, &data, sizeof(data)) <= 0) {
fprintf(stderr, "No data at address %s\n", argv[2]);
exit(1); }
I've been following the official documentation on creating a TUN device. There's very little documentation, but what even is there does not seem to work. Here's what I have so far:
#include <linux/if.h>
#include <linux/if_tun.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
int tun_alloc(char *dev)
{
struct ifreq ifr;
int fd, err;
if( (fd = open("/dev/net/tun", O_RDWR)) < 0 )
return 7; // tun_alloc_old(dev); // this does not happen, linux docs don't say what tun_alloc_old is anyway
memset(&ifr, 0, sizeof(ifr));
/* Flags: IFF_TUN - TUN device (no Ethernet headers)
* IFF_TAP - TAP device
*
* IFF_NO_PI - Do not provide packet information
*/
ifr.ifr_flags = IFF_TUN;
if( *dev ) {
printf("setting ifr.ifr_name to \"%s\"\n", dev);
strncpy(ifr.ifr_name, dev, IFNAMSIZ);
}
printf("ifr.ifr_name is \"%s\"\n", ifr.ifr_name);
if( (err = ioctl(fd, TUNSETIFF, (void *) &ifr)) < 0 ){
perror("ERR");
close(fd);
printf("GOT ERROR: %d\n", err);
return err;
}
printf("past TUNSETIFF error checking\n");
strcpy(dev, ifr.ifr_name);
return fd;
}
int main() {
char name[128];
strcpy(&name, "tun23");
int tun = tun_alloc(name);
printf("tun_alloc: %s id: %d\n", name, tun);
if(tun == -1) return -1;
while(1) {
printf("in loop\n");
char buf[128];
ssize_t readAmount = read(tun, buf, 128);
printf("finished read\n");
if(readAmount == -1) {
printf("read 0 bytes\n");
continue;
}
printf("Read %d: ", readAmount);
for(int i = 0; i < 128; i++) {
printf("%hhx", buf[i]);
}
printf("\n");
}
return tun;
}
Compiler step is gcc -g3 test.c && a.out.
When ran as non-root, I get this output
setting ifr.ifr_name to "tun23"
ifr.ifr_name is "tun23"
ERR: Operation not permitted
GOT ERROR: -1
tun_alloc: tun23 id: -1
And as root, it successfully gets into the loop, but then the call to read seems to block.
setting ifr.ifr_name to "tun23"
ifr.ifr_name is "tun23"
past TUNSETIFF error checking
tun_alloc: tun23 id: 3
in loop
(In the event of an XY problem, the reason I'm doing this is to try and make a very simple vpn-like application)
The issue is that while it's blocking in this loop, no TUN devices are created. I am looking in /dev/. I'm not sure how I would give it any bytes to read.
Edit: added a proper perror call and the respective output Operation not permitted, valgrind output, and a couple print statements. Going to try and debug the strcpy error.
Edit: fixed the strcpy error, was pretty simple. Seems to fail in non-root due to a lack of permission to create TUN devices.
My goal: Is to monitor the state of my network interface (mainly wireless) from my firmware (in C) by monitoring the wpa_supplicant through the D-Bus interfaces. I would like to stick with C and low-level API of D-bus.
What I have so far
I've written a small program in C, copied most of the code as is from this SO user.
I've gone through all possible tutorials on D-Bus and wpa_supplicant
My program compiles and works properly. However it does not produce the expected output.
Here's my code:
#include <stdio.h>
#include <dbus/dbus.h>
#define WPAS_DBUS_SERVICE "fi.epitest.hostap.WPASupplicant"
#define WPAS_DBUS_PATH "/fi/epitest/hostap/WPASupplicant"
#define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicantAAA"
#define WPAS_DBUS_PATH_INTERFACES WPAS_DBUS_PATH "/Interfaces"
#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interfaces"
#define WPAS_DBUS_NETWORKS_PART "Networks"
#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network"
#define WPAS_DBUS_BSSIDS_PART "BSSIDs"
#define WPAS_DBUS_IFACE_BSSID WPAS_DBUS_INTERFACE ".BSSID"
int ret;
char signalDesc[1024]; // Signal description as string
// Signal handling
signal(SIGKILL, stopLoop);
signal(SIGTERM, stopLoop);
void loop(DBusConnection* conn)
{
DBusMessage* msg;
DBusMessageIter args;
DBusMessageIter subArgs;
int argType;
int i;
int buffSize = 1024;
char strValue[buffSize];
const char* member = 0;
while (1)
{
// non blocking read of the next available message
dbus_connection_read_write(conn, 0);
msg = dbus_connection_pop_message(conn);
// loop again if we haven't read a message
if (!msg)
{
printf("No message received, waiting a little ...\n");
sleep(1);
continue;
}
else printf("Got a message, will analyze it ...\n");
// Print the message member
printf("Got message for interface %s\n",
dbus_message_get_interface(msg));
member = dbus_message_get_member(msg);
if(member) printf("Got message member %s\n", member);
// Check has argument
if (!dbus_message_iter_init(msg, &args))
{
printf("Message has no argument\n");
continue;
}
else
{
// Go through arguments
while(1)
{
argType = dbus_message_iter_get_arg_type(&args);
if (argType == DBUS_TYPE_STRING)
{
printf("Got string argument, extracting ...\n");
char* str = NULL;
dbus_message_iter_get_basic(&args, &str);
printf("Received string: \n %s \n",str);
}
else
printf("Arg type not implemented yet !\n");
if(dbus_message_iter_has_next(&args))
dbus_message_iter_next(&args);
else break;
}
printf("No more arguments!\n");
}
// free the message
dbus_message_unref(msg);
}
}
int main()
{
DBusConnection *connection;
DBusError error;
char *name = "org.share.linux";
dbus_error_init(&error);
connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
if ( dbus_error_is_set(&error) )
{
printf("Error connecting to the daemon bus: %s",error.message);
dbus_error_free(&error);
return 1;
}
// request a name on the bus
ret = dbus_bus_request_name(connection, WPAS_DBUS_SERVICE, 0, &error);
if (dbus_error_is_set(&error))
{
printf(stderr, "Name Error (%s)\n", error.message);
dbus_error_free(&error);
}
/* Connect to signal */
// Interface signal ..
printf(signalDesc, "type='signal',interface='%s'",WPAS_DBUS_IFACE_INTERFACE);
dbus_bus_add_match(connection, signalDesc, &error);
dbus_connection_flush(connection);
if (dbus_error_is_set(&error))
{
fprintf(stderr, "Match Error (%s)\n", error.message);
return 1;
}
// Do main loop
loop(connection);
dbus_connection_close(connection);
return 0;
}
List of D-bus services on my BBB
Output
Some pointers
I would like to catch the signals as shown in the D-Bus API of wpa_supplicant.
Some things I would like to do -- see when a wireless interface say wlan0 is enabled, connects to access point etc. Also capability to set AP and stuff.
Its catching signal from other interfaces for which no match has been added.
I run this program and change the state of the networking interfaces but I dont get any signals. Also, I dont know if requesting name on the bus is necessary as I'm just listening.
What's the possible issue here? Any pointers will be really helpful.
I am actually trying to write a small program to catch global keyboard inputs from specific USB keyboards under linux.
I am testing with this piece of code :
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/input.h>
#include <string.h>
#include <stdio.h>
static const char *const evval[3] = {
"RELEASED",
"PRESSED ",
"REPEATED"
};
int main(void)
{
const char *dev = "/dev/input/event2";
struct input_event ev;
ssize_t n;
int fd;
char name[256]= "Unknown";
// int codes[2];
// codes[0] = 58; /* M keycap */
// codes[1] = 49; /* assign to N */
fd = open(dev, O_RDONLY);
if (fd == -1) {
fprintf(stderr, "Cannot open %s: %s.\n", dev, strerror(errno));
return EXIT_FAILURE;
}
if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) > 0)
{
printf("The device on %s says its name is '%s'\n", dev, name);
}
/*
int err = ioctl(fd, EVIOCSKEYCODE, codes);
if (err) {
perror("evdev ioctl");
}*/
while (1) {
n = read(fd, &ev, sizeof ev);
if (n == (ssize_t)-1) {
if (errno == EINTR)
continue;
else
break;
} else
if (n != sizeof ev) {
errno = EIO;
break;
}
if (ev.type == EV_KEY && ev.value >= 0 && ev.value <= 2)
printf("%s 0x%04x (%d)\n", evval[ev.value], (int)ev.code, (int)ev.code);
}
fflush(stdout);
fprintf(stderr, "%s.\n", strerror(errno));
return EXIT_FAILURE;
}
Ths point is that I don't know how to change some input key by other. I tried by calling write() on currently red event by changing the event code, sent key was still previous one, and I tried to used ioctl with EVIOCSKEYCODE, but the call failed with an "invalid argument" error (and I'm not sure to call it correctly).
How can I change outputed key correctly ?
Use the EVIOCGRAB ioctl to grab the input device, so that by reading the events you consume them. Normally (not-grabbed) the events are not consumed when you read them. The ioctl takes an additional parameter, (int)1 for grabbing, (int)0 for releasing.
To re-inject any events, just write them to the uinput device. See eg. a mouse example here. (The event structures are the same type, you only need to write a struct uinput_user_dev structure to the uinput device first, to describe your new input device (which provides the mapped events).)
In other words, you don't remap: you consume and forward.
I'm having a requirement to create a file in the externally mounted hard disk .created file should contain the serial no of the harddisk and that file can be used by other process.
I tried to use the following code
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/hdreg.h>
int main(int argc, char *argv[])
{
static struct hd_driveid hd;
int fd;
if (geteuid() > 0) {
printf("ERROR: Must be root to use\n");
exit(1);
}
if ((fd = open(argv[1], O_RDONLY|O_NONBLOCK)) < 0) {
printf("ERROR: Cannot open device %s\n", argv[1]);
exit(1);
}
if (!ioctl(fd, HDIO_GET_IDENTITY, &hd)) {
printf("Hard Disk Model: %.40s\n", hd.model);
printf(" Serial Number: %.20s\n", hd.serial_no);
} else if (errno == -ENOMSG) {
printf("No hard disk identification information available\n");
} else {
perror("ERROR: HDIO_GET_IDENTITY");
exit(1);
}
exit(0);
}
this is working fine for internal hard disk but when i do this for external hard disk(usb) it is giving me the following error
ERROR: HDIO_GET_IDENTITY: Invalid argument
Because the device is connected to a USB bridge, you can't send the HDIO_GET_IDENTITY command.
You can try hdparm to query the identity of the device. With the default options, hdparm fails to identify the device so you have to specify the type of the device with -d (see USB devices and smartmontools).
Without the -d option, I get:
$ sudo smartctl /dev/sdc
/dev/sdc: Unknown USB bridge [0x059f:0x1011 (0x000)]
Please specify device type with the -d option.
With -d sat,auto, hdparm manages to display some information about the device:
$ sudo smartctl -d sat,auto -i /dev/sdc
/dev/sdc [SCSI]: Device open changed type from 'sat,auto' to 'scsi'
=== START OF INFORMATION SECTION ===
Vendor: ST2000VN
Product: 000-1H3164
User Capacity: 2 000 398 934 016 bytes [2,00 TB]
Logical block size: 512 bytes
Device type: disk
Local Time is: Thu Mar 13 09:41:32 2014 CET
SMART support is: Unavailable - device lacks SMART capability.
You can try to do the same thing as smartctl in your C program, but it's probably easier to write a script that invokes smartctl.
Thanks for the explanation and i got the below to identify the serial no of a external hardisk
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <scsi/scsi.h>
#include <scsi/sg.h>
#include <sys/ioctl.h>
int scsi_get_serial(int fd, void *buf, size_t buf_len) {
// we shall retrieve page 0x80 as per http://en.wikipedia.org/wiki/SCSI_Inquiry_Command
unsigned char inq_cmd[] = {INQUIRY, 1, 0x80, 0, buf_len, 0};
unsigned char sense[32];
struct sg_io_hdr io_hdr;
int result;
memset(&io_hdr, 0, sizeof (io_hdr));
io_hdr.interface_id = 'S';
io_hdr.cmdp = inq_cmd;
io_hdr.cmd_len = sizeof (inq_cmd);
io_hdr.dxferp = buf;
io_hdr.dxfer_len = buf_len;
io_hdr.dxfer_direction = SG_DXFER_FROM_DEV;
io_hdr.sbp = sense;
io_hdr.mx_sb_len = sizeof (sense);
io_hdr.timeout = 5000;
result = ioctl(fd, SG_IO, &io_hdr);
if (result < 0)
return result;
if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK)
return 1;
return 0;
}
void trim(char * s) {
char * p = s;
int l = strlen(p);
while(isspace(p[l - 1])) p[--l] = 0;
while(* p && isspace(* p)) ++p, --l;
memmove(s, p, l + 1);
}
int storeData (char *filepath, char *data) {
int rc = 0;
FILE *fOut = fopen (filepath, "a");
if (fOut != NULL) {
if (fputs (data, fOut) != EOF) {
rc = 1;
}
fclose (fOut); // or for the paranoid: if (fclose (fOut) == EOF) rc = 0;
}
return rc;
}
int main(int argc, char** argv) {
if(argc>1){
char *dev = (char *)argv[1];
char outStr[1024];
printf("\nEntered Serial no : %s\n",argv[1]);
char scsi_serial[255];
int rc;
int fd;
fd = open(dev, O_RDONLY | O_NONBLOCK);
if (fd < 0) {
perror(dev);
}
memset(scsi_serial, 0, sizeof (scsi_serial));
rc = scsi_get_serial(fd, scsi_serial, 255);
// scsi_serial[3] is the length of the serial number
// scsi_serial[4] is serial number (raw, NOT null terminated)
if (rc < 0) {
printf("FAIL, rc=%d, errno=%d\n", rc, errno);
} else
if (rc == 1) {
printf("FAIL, rc=%d, drive doesn't report serial number\n", rc);
} else {
if (!scsi_serial[3]) {
printf("Failed to retrieve serial for %s\n", dev);
return -1;
}
printf("Serial Number: %.*s\n", (size_t) scsi_serial[3], (char *) & scsi_serial[4]);
scsi_serial[4+scsi_serial[3]]='\0';
trim(&scsi_serial[4]);
sprintf(outStr,"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?> \n<!DOCTYPE properties SYSTEM \"http://java.sun.com/dtd/properties.dtd\"> \n<properties>\n<comment/>\n<entry key=\"SerialNo\">%s</entry>\n</properties>\n", (char *) & scsi_serial[4]);
//strcat((char *)argv[2],(char *)"/hdd.xml");
printf("\n%s",outStr);
// printf("\n%s",(char *)argv[2]);
//storeData((char *)argv[1],(char *) outStr);
}
close(fd);
}else{
printf("\nInsufficient no of arguments \n");
}
return (EXIT_SUCCESS);
}