Test for device using udev sysname - c

I'm writing my first ever C program in Ubuntu and it involves detecting when the AC adapter or Battery on my laptop see events (through udev_monitor). So far, I'm able to log to the console when the power situation changes using something like this while snippet:
while (1) {
dev = udev_monitor_receive_device(mon);
if (dev) {
printf("\n[INFO] Got Device\n");
printf(" [INFO] Device Name: %s\n", udev_device_get_sysname(dev));
...
And that's great! When I plug or unplug my laptop I get that logged to the console. However, what I'm failing to grok is how to conditionally test using these same functions.
For instance, this is never true:
if (udev_device_get_sysname(dev) == "ADP1") { ... }
I'm unsure how to properly test this. Obviously it prints as a string (array of characters?) when printf() and %s are used.
EDIT: The values logged to the consle from the function called are ADP1 for the adapter and BAT0 for the battery - which correlates to their entries in the /sys/class/ directory.

In C you compare strings using one of the string comparison routines, such as strcmp or strncmp. If you compare them using == you're only comparing the values of the pointers, which will not be the same.
So for the code checking the sysname is incorrect, as the pointer comparison will never be true. It should be changed to something like:
if (strcmp(udev_device_get_sysname(dev), "ADP1") == 0) { … }
which causes it to compare the strings, rather than the pointer values.

Related

Function XOpenDisplay with and without parameter

I have little issue with XOpenDisplay function. In school I can run program and it works good when using XOpenDisplay("ip:0"), but on my local machine in home when I run program (changed ip on current) got "Segmentation fault (core dumped)", but with empy string XOpenDisplay("") it works fine. I need to be able to use ip. Used host +, but nothing changes.
My system is Kubuntu 14.04.1: 3.16.0-30-generic #40~14.04.1-Ubuntu SMP Thu Jan 15 17:43:14 UTC 2015
Here is code of program:
#include <X11/Xlib.h>
#include <X11/X.h>
#include <stdio.h>
Display *mydisplay;
Window mywindow;
XSetWindowAttributes mywindowattributes;
XGCValues mygcvalues;
GC mygc;
Visual *myvisual;
int mydepth;
int myscreen;
Colormap mycolormap;
XColor mycolor,mycolor1,dummy;
int i;
main()
{
mydisplay = XOpenDisplay("192.168.0.12:0");
myscreen = DefaultScreen(mydisplay);
myvisual = DefaultVisual(mydisplay,myscreen);
mydepth = DefaultDepth(mydisplay,myscreen);
mywindowattributes.background_pixel = XWhitePixel(mydisplay,myscreen);
mywindowattributes.override_redirect = True;
mywindow = XCreateWindow(mydisplay,XRootWindow(mydisplay,myscreen),
0,0,500,500,10,mydepth,InputOutput,
myvisual,CWBackPixel|CWOverrideRedirect,
&mywindowattributes);
mycolormap = DefaultColormap(mydisplay,myscreen);
XAllocNamedColor(mydisplay,mycolormap,"cyan",&mycolor,&dummy);
XAllocNamedColor(mydisplay,mycolormap,"red",&mycolor1,&dummy);
XMapWindow(mydisplay,mywindow);
mygc = DefaultGC(mydisplay,myscreen);
XSetForeground(mydisplay,mygc,mycolor.pixel);
XFillRectangle(mydisplay,mywindow,mygc,100,100,300,300);
XSetForeground(mydisplay,mygc,mycolor1.pixel);
XSetFunction(mydisplay,mygc,GXcopy);
XSetLineAttributes(mydisplay,mygc,10,LineSolid,CapProjecting,JoinMiter);
XDrawLine(mydisplay,mywindow,mygc,100,100,400,400);
XDrawLine(mydisplay,mywindow,mygc,100,400,400,100);
XFlush(mydisplay);
sleep(10);
XCloseDisplay(mydisplay);
exit(0);
}
I can only guess that need to set something, but have no idea where is that option.
You shall always check whether functions returned successfully, or not. It is not a Haskell, where all the checking done for you by monad, it is C. As for your particular case, the problem is that the function XOpenDisplay fails and returns null for you. In the next line you're trying to use DefaultScreen with the result. The DefaultScreen is defined as
#define DefaultScreen(dpy) ((dpy)->default_screen)
I.e. it just a macro, which using the first argument as a pointer. In your case it does ((0)->default_screen), i.e. it dereferencing the null pointer, and that leads to the segfault you see.
Also, about the XOpenDisplay("192.168.0.12:0"); — you didn't mentioned that you're trying to connect to another PC, so, if it's the same computer where the app running, try to call the function as XOpenDisplay("127.0.0.1:0");
UPD: okay, I tried to run the code at my PC, and the function doesn't work for me too. To find the reason I started the code under strace app, and saw
…
connect(3, {sa_family=AF_INET, sin_port=htons(6000), sin_addr=inet_addr("127.0.0.1")}, 16) = -1 ECONNREFUSED (Connection refused)
…
Aha! So, the app trying to connect to XServer, but Xserver refuses the connection. Actually, it have a security reason to disable it by default — so, that nobody would connect to your XServer from a network unless you specifically allowed it. For the function to work you need to launch your XServer with the option that allows such a connection. Right now DisplayManagers are the ones, who manages xsessions, so you need to set some option depending on your DM.
The solution for lightdm
Open the /etc/lightdm/lightdm.conf, and paste the line xserver-allow-tcp=true in the section [SeatDefaults](you will see it).
The solution for gdm
Edit the file /etc/gdm/gdm.schemas, you will find there something like
<schema>
<key>security/DisallowTCP</key>
<signature>b</signature>
<default>true</default>
</schema>
Change the true to false.

libmpdclient: detect lost connection to MPD daemon

I'm writing a plugin for my statusbar to print MPD state, currently using the libmpdclient library. It has to be robust to properly handle lost connections in case MPD is restarted, but simple checking with mpd_connection_get_error on existing mpd_connection object does not work – it can detect the error only when the initial mpd_connection_new fails.
This is a simplified code I'm working with:
#include <stdio.h>
#include <unistd.h>
#include <mpd/client.h>
int main(void) {
struct mpd_connection* m_connection = NULL;
struct mpd_status* m_status = NULL;
char* m_state_str;
m_connection = mpd_connection_new(NULL, 0, 30000);
while (1) {
// this check works only on start up (i.e. when mpd_connection_new failed),
// not when the connection is lost later
if (mpd_connection_get_error(m_connection) != MPD_ERROR_SUCCESS) {
fprintf(stderr, "Could not connect to MPD: %s\n", mpd_connection_get_error_message(m_connection));
mpd_connection_free(m_connection);
m_connection = NULL;
}
m_status = mpd_run_status(m_connection);
if (mpd_status_get_state(m_status) == MPD_STATE_PLAY) {
m_state_str = "playing";
} else if (mpd_status_get_state(m_status) == MPD_STATE_STOP) {
m_state_str = "stopped";
} else if (mpd_status_get_state(m_status) == MPD_STATE_PAUSE) {
m_state_str = "paused";
} else {
m_state_str = "unknown";
}
printf("MPD state: %s\n", m_state_str);
sleep(1);
}
}
When MPD is stopped during the execution of the above program, it segfaults with:
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00007fb2fd9557e0 in mpd_status_get_state () from /usr/lib/libmpdclient.so.2
The only way I can think of to make the program safe is to establish a new connection in every iteration, which I was hoping to avoid. But then what if the connection is lost between individual calls to libmpdclient functions? How often, and more importantly how exactly, should I check if the connection is still alive?
The only way I could find that really works (beyond reestablishing a connection with each run) is using the idle command. If mpd_recv_idle (or mpd_run_idle) returns 0, it is an error condition, and you can take that as a cue to free your connection and run from there.
It's not a perfect solution, but it does let you keep a live connection between runs, and it helps you avoid segfaults (though I don't think you can completely avoid them, because if you send a command and mpd is killed before you recv it, I'm pretty sure the library still segfaults). I'm not sure if there is a better solution. It would be fantastic if there was a reliable way to detect if your connection was still alive via the API, but I can't find anything of the sort. It doesn't seem like libmpdclient is well-built for very long-lived connections that have to deal with mpd instances that go up and down over time.
Another lower-level option is to use sockets to interact with MPD through its protocol directly, though in doing that you'd likely reimplement much of libmpdclient itself anyway.
EDIT: Unfortunately, the idle command does block until something happens, and can sit blocking for as long as a single audio track will last, so if you need your program to do other things in the interim, you have to find a way to implement it asynchronously or in another thread.
Assuming "conn" is a connection created with "mpd_connection_new":
if (mpd_connection_get_error(conn) == MPD_ERROR_CLOSED) {
// mpd_connection_get_error_message(conn)
// will return "Connection closed by the server"
}
You can run this check after almost any libmpdclient call, including "mpd_recv_idle" or (as per your example) "mpd_run_status".
I'm using libmpdclient 2.18, and this certainly works for me.

Using DHCP libraries results infinite loop

I have a code that uses DHCP libararies(package : 4.2.6) to get the hardware address of the DHCP client connected to the system. During this process after DHCP objects got initialized, i tried dhcp_connect() as follows which results into an infinte loop.
dhcpctl_initialize ();
status=dhcpctl_connect (&connection, "127.0.0.1", 7911, 0);
When i tried to debug the issue, i found a function "omapi_wait_for_completion"(in ompai/dispatch.c), has a do-while check for waiter object and its status, the object should change its state to ready to come out of the this loop, but this is never happened which results into an infinite loop.
Here i am just copying the loop as a reference.
do {
status = omapi_one_dispatch ((omapi_object_t *)waiter, t);
if (status != ISC_R_SUCCESS)
return status;
} while (!waiter || !waiter -> ready);
NOTE:
There is no issue when i run the binary generated from the code in system command line, but when i trigger the same command through an application we have this issue.
The application that triggers my binary doesn't uses DHCP libraries or files.
Please note that same binary with the same application is working
fine with older DHCP package (3.0.5).
Thanks in advance for your help.

Simulink SFunction Builder Bus input value

I'm trying to understand how to access and use the Bus system with custom S-Function Blocks. I built a very basic S-Function using the S-Function Builder which has no input and one Bus output. The Bus is a struct consisting only of one field of type double. This works just fine.
No I tried to connect its output to a newly created block (also with help of the S-Function Builder) which has one Bus input and no output. It should write the value of the only field inside the struct to the console using mexPrintf. But the value is always 0 (zero)
I set the output of the first block like that in the output wrapper function (works fine):
out0->data = 12;
and I try to get the input value inside the other block like this (prints always 0):
real_T insig = in0->data;
mexPrintf("Got a %d", insig);
Stupid error - I was using %d instead of %f for printing a double value...

How can I make the printer work in C in MS VC++ Express edition?

I am using VC++ 2008 express edition for C. When I try to run this:
/* Demonstrates printer output. */
#include <stdio.h>
main()
{
float f = 2.0134;
fprintf(stdprn, "This message is printed.\n\n");
fprintf(stdprn, "And now some numbers:\n\n");
fprintf(stdprn, "The square of %f is %f.", f, f*f);
/* Send a form feed */
fprintf(stdprn, "\f");
}
I get four of these errors: error C2065: 'stdprn' : undeclared identifier.
On this forum, they wrote that it works to define the printer as follows:
FILE *printer;
printer = fopen("PRN", "w");
EDIT
It builds with a warning that fopen is unsafe. When it runs the error appears:
Debug Assertion fails.
File: f:\dd\vctools\crt_bld\self_x86\crt\src\fprintf.c
Line: 55
Expression: (str != NULL)
The stdprn stream was an extension provided by Borland compilers - as far as I know, MS have never supported it. Regarding the use of fopen to open the printer device, I don't think this will work with any recent versions of Windows, but a couple of things to try:
use PRN: as the name instead of PRN (note the colon)
try opening the specific device using (for example) LPT1: (once again, note the colon). This will of course not work if you don't have a printer attached.
don't depend on a printer dialog coming up - you are not really using the WIndows printing system when you take this approach (and so it probably won't solve your problem, but is worth a try).
I do not have a printer attached, but I do have the Microsoft XPS document writer installed, s it shoulod at least bring up the standard Windows Print dialog from which one can choose the printer.
No. It wouldn't bring up a dialogue. This is because you are flushing data out to a file. And not going through the circuitous Win32 API.
The print doesn't work because the data is not proper PDL -- something that the printer could understand. For the print to work fine, you need to push in a PDL file, with language specific constructs. This varies from printer to printer, a PS printer will need you to push in a PostScript snippet, a PCL -- a PCL command-set and in case of MXDW you will have to write up XML based page description markup and create a zip file (with all resources embedded in it) i.e. an XPS file to get proper printout.
The PDL constructs are important because otherwise the printer doesn't know where to put the data, which color to print it on, what orientation to use, how many copies to print and so on and so forth.
Edit: I am curious why you are doing this. I understand portability is probably something you are trying to address. But apart from that, I'd like to know, there may be better alternatives available. Win32 Print Subsytem APIs are something that you ought to lookup if you are trying to print programmatically on Windows with any degree of fidelity.
Edit#2:
EDIT It builds with a warning that fopen is unsafe.
This is because MS suggests you use the safer versions nowadays fopen_s . See Security Enhancements in the CRT.
When it runs the error appears:
Debug Assertion fails. File: f:\dd\vctools\crt_bld\self_x86\crt\src\fprintf.c Line: 55
Expression: (str != NULL)
This is because fopen (whose return value you do not check) returns a NULL pointer. The file open failed. Also, if it did succeed a matching fclose call is called for.
There's no such thing as stdprn in ANSI C, it was a nonstandard extension provided by some compilers many years ago.
Today to print you have to use the specific APIs provided on your platform; to print on Windows you have to use the printing APIs to manage the printing of the document and obtain a DC to the printer and the GDI APIs to perform the actual drawing on the DC.
On UNIX-like OSes, instead, usually CUPS is used.
You can substitute the printer using this command with net use, see here on the MSDN kb
NET USE LPT1 \\server_name\printer_name
There is an excellent chapter on printing in DOS using the BIOS, ok, its a bit antiquated but interesting to read purely for nostalgic sake.
Onto your problem, you may need to use CreateFile to open the LPT1 port, see here for an example, I have it duplicated it here, for your benefit.
HANDLE hFile;
hFile = CreateFile("LPT1", GENERIC_WRITE, 0,NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
// handle error
}
OVERLAPPED ov = {};
ov.hEvent = CreateEvent(0, false, false, 0);
char szData[] = "1234567890";
DWORD p;
if (!WriteFile(hFile,szData, 10, &p, &ov))
{
if (GetLastError() != ERROR_IO_PENDING)
{
// handle error
}
}
// Wait for write op to complete (maximum 3 second)
DWORD dwWait = WaitForSingleObject(ov.hEvent, 3000);
if (dwWait == WAIT_TIMEOUT)
{
// it took more than 3 seconds
} else if (dwWait == WAIT_OBJECT_0)
{
// the write op completed,
// call GetOverlappedResult(...)
}
CloseHandle(ov.hEvent);
CloseHandle(hFile);
But if you insist on opening the LPT1 port directly, error checking is omitted...
FILE *prn = fopen("lpt1", "w");
fprintf(prn, "Hello World\n\f");
fclose(prn);
Hope this helps,
Best regards,
Tom.

Resources