Make Piped work better
[matches/MCTX3420.git] / server / sensors / piped.c
1 /**
2  * @file piped.h
3  * @brief Sensor run by an external process and sent to this one through a pipe
4  * PURELY INCLUDED FOR TESTING PURPOSES
5  *      This will work with any sensor that can unbuffer stdout
6  * ... So, although it's not recommended, you could write a sensor purely in something like python
7  *         The FastCGI process will handle all the time stamps and stuff
8  */
9
10 #include "../log.h"
11 #include "../common.h"
12
13 #include "piped.h"
14
15 #include <sys/types.h>
16 #include <sys/socket.h>
17 #include <sys/signal.h>
18 #include <ctype.h>
19
20 #include <float.h> // Defines DBL_MAX_10_EXP
21
22
23 typedef struct
24 {
25         int pid;
26         int sv[2];
27         FILE * stream;
28         
29 } Piped;
30
31 static Piped g_piped[PIPED_MAX];
32 static int g_num_piped = 0;
33
34 bool Piped_Init(const char * name, int id)
35 {
36         if (++g_num_piped > PIPED_MAX)
37         {
38                 Fatal("Too many sensors; Increase PIPED_MAX from %d in piped.h and recompile", PIPED_MAX);
39         }
40
41         if (socketpair(AF_UNIX, SOCK_STREAM, 0, g_piped[id].sv) != 0)
42                         Fatal("socketpair failed - %s", strerror(errno));
43
44         g_piped[id].pid = fork();
45         if (g_piped[id].pid == 0)
46         {
47                 dup2(g_piped[id].sv[0], fileno(stdin));
48                 dup2(g_piped[id].sv[0], fileno(stdout));
49
50                 if (access(name, X_OK) == 0) //Check we STILL have permissions to start the file
51                 {
52                         execl(name, name, (char*)(NULL)); ///Replace process with desired executable
53                         //execv(executablePath,arguments); ///Replace process with desired executable
54                 }
55                 else
56                 {
57                         Fatal("Can't execute file %s", name);
58                 }
59                 Fatal("execl error - %s", strerror(errno));
60         }
61         else
62         {
63                 g_piped[id].stream = fdopen(g_piped[id].sv[1], "r");
64                 setbuf(g_piped[id].stream, NULL);
65         }
66         return true;
67         
68 }
69 /**
70  * This function looks evil, but I swear it's legit
71  * @param id - The Piped process to read from
72  * @param value - Stores the value read (if successful)
73  * @returns true on success, false on failure
74  */
75 bool Piped_Read(int id, double * value)
76 {
77         if (g_piped[id].stream == NULL)
78                 return false;
79
80         // So need a buffer size big enough to fit all doubles but not too much bigger
81         static char buf[DBL_MAX_10_EXP+1]; 
82
83         // Using BUFSIZ is a bad idea, since we want to read near the end of the file
84
85         // Seek back from the end of the file
86         fseek(g_piped[id].stream, -DBL_MAX_10_EXP, SEEK_END);   
87         int len = fread(buf, 1, DBL_MAX_10_EXP, g_piped[id].stream); // Fill the buffer, note the length count
88         int count = 0;
89         int i = len-1;
90         for (i = len-1; i >= 0; --i) // Search for the last non-empty line in the buffer
91         {
92                 if (buf[i] == '\n')
93                 {
94                         if (count++ > 1)
95                         {
96                                 ++i;
97                                 break;
98                         }
99                         else
100                                 buf[i] = '\0';
101                 }
102         }
103         // Now sscanf a double from the string
104         if (sscanf(buf+i, "%lf", value) != 1)
105         {
106                 Log(LOGDEBUG, "Can't interpret %s as double", buf);
107                 return false;
108         }
109         return true;
110 }
111
112 bool Piped_Cleanup(int id)
113 {
114         fclose(g_piped[id].stream);
115         if (kill(g_piped[id].pid, 15) != 0)
116         {
117                 Log(LOGWARN, "Couldn't kill piped %d - %s", g_piped[id].pid, strerror(errno));
118                 return false;
119         }
120         return true;
121 }

UCC git Repository :: git.ucc.asn.au