avoid to use cpp macros
[psensor.git] / src / lib / hdd_hddtemp.c
1 /*
2  * Copyright (C) 2010-2014 jeanfi@gmail.com
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301 USA
18  */
19 #include <locale.h>
20 #include <libintl.h>
21 #define _(str) gettext(str)
22
23 /*
24  * Following code is based on GNOME sensors applet code
25  * hddtemp-plugin.c see http://sensors-applet.sourceforge.net/
26  */
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <unistd.h>
35
36 #include <hdd.h>
37 #include <psensor.h>
38
39 static const char *PROVIDER_NAME = "hddtemp";
40
41 static const char *HDDTEMP_SERVER_IP_ADDRESS = "127.0.0.1";
42 static const int HDDTEMP_PORT_NUMBER = 7634;
43 static const int HDDTEMP_OUTPUT_BUFFER_LENGTH = 4048;
44
45 struct hdd_info {
46         char *name;
47         int temp;
48 };
49
50 static char *fetch()
51 {
52         int sockfd;
53         ssize_t n = 1;
54         int output_length = 0;
55         char *pc;
56         char *buffer;
57         struct sockaddr_in address;
58
59         sockfd = socket(AF_INET, SOCK_STREAM, 0);
60         if (sockfd == -1) {
61                 log_err(_("hddtemp: failed to open socket."));
62                 return NULL;
63         }
64
65         address.sin_family = AF_INET;
66         address.sin_addr.s_addr = inet_addr(HDDTEMP_SERVER_IP_ADDRESS);
67         address.sin_port = htons(HDDTEMP_PORT_NUMBER);
68
69         buffer = NULL;
70
71         if (connect(sockfd,
72                     (struct sockaddr *)&address,
73                     (socklen_t) sizeof(address)) == -1) {
74                 log_err(_("hddtemp: failed to open connection."));
75         } else {
76                 buffer = malloc(HDDTEMP_OUTPUT_BUFFER_LENGTH);
77
78                 pc = buffer;
79                 while ((n = read(sockfd,
80                                  pc,
81                                  HDDTEMP_OUTPUT_BUFFER_LENGTH -
82                                  output_length)) > 0) {
83
84                         output_length += n;
85                         pc = &pc[n];
86                 }
87
88                 buffer[output_length] = '\0';
89         }
90
91         close(sockfd);
92
93         return buffer;
94 }
95
96 static int str_index(char *str, char d)
97 {
98         char *c;
99         int i;
100
101         if (!str || *str == '\0')
102                 return -1;
103
104         c = str;
105
106         i = 0;
107         while (*c) {
108                 if (*c == d)
109                         return i;
110                 i++;
111                 c++;
112         }
113
114         return -1;
115 }
116
117 static struct psensor *
118 create_sensor(char *id, char *name, int values_max_length)
119 {
120         int t;
121
122         t = SENSOR_TYPE_HDD | SENSOR_TYPE_HDDTEMP | SENSOR_TYPE_TEMP;
123
124         return psensor_create(id, name, strdup(_("Disk")),
125                               t,
126                               values_max_length);
127 }
128
129 static char *next_hdd_info(char *string, struct hdd_info *info)
130 {
131         char *c;
132         int idx_name_n, i, temp;
133
134         if (!string || strlen(string) <= 5      /* at least 5 pipes */
135             || string[0] != '|')
136                 return NULL;
137
138         /* skip first pipe */
139         c = string + 1;
140
141         /* name */
142         idx_name_n = str_index(c, '|');
143
144         if (idx_name_n == -1)
145                 return NULL;
146         c = c + idx_name_n + 1;
147
148         /* skip label */
149         i = str_index(c, '|');
150         if (i == -1)
151                 return NULL;
152         c = c + i + 1;
153
154         /* temp */
155         i = str_index(c, '|');
156         if (i == -1)
157                 return NULL;
158         temp = atoi(c);
159         c = c + i + 1;
160
161         /* skip unit  */
162         i = str_index(c, '|');
163         if (i == -1)
164                 return NULL;
165         c = c + i + 1;
166
167         info->name = malloc(idx_name_n + 1);
168         strncpy(info->name, string + 1, idx_name_n);
169         info->name[idx_name_n] = '\0';
170
171         info->temp = temp;
172
173         return c;
174 }
175
176 struct psensor **hddtemp_psensor_list_add(struct psensor **sensors,
177                                           int values_max_length)
178 {
179         char *hddtemp_output, *c;
180         struct hdd_info info;
181         struct psensor **result;
182
183         hddtemp_output = fetch();
184
185         if (!hddtemp_output)
186                 return sensors;
187
188         if (hddtemp_output[0] != '|') {
189                 log_err(_("hddtemp: wrong string: %s."), hddtemp_output);
190
191                 free(hddtemp_output);
192
193                 return sensors;
194         }
195
196         c = hddtemp_output;
197
198         result = sensors;
199
200         while (c && (c = next_hdd_info(c, &info))) {
201                 struct psensor *sensor;
202                 struct psensor **tmp_sensors;
203                 char *id;
204
205                 id = malloc(strlen(PROVIDER_NAME) + 1 + strlen(info.name) + 1);
206                 sprintf(id, "%s %s", PROVIDER_NAME, info.name);
207
208                 sensor = create_sensor(id, info.name, values_max_length);
209
210                 tmp_sensors = psensor_list_add(result, sensor);
211
212                 if (result != sensors)
213                         free(result);
214
215                 result = tmp_sensors;
216         }
217
218         free(hddtemp_output);
219
220         return result;
221 }
222
223 static void update(struct psensor **sensors, struct hdd_info *info)
224 {
225         struct psensor **sensor_cur = sensors;
226
227         while (*sensor_cur) {
228                 if (!((*sensor_cur)->type & SENSOR_TYPE_REMOTE)
229                     && (*sensor_cur)->type & SENSOR_TYPE_HDDTEMP
230                     && !strcmp((*sensor_cur)->id + 8, info->name))
231                         psensor_set_current_value(*sensor_cur,
232                                                   (float)info->temp);
233
234                 sensor_cur++;
235         }
236 }
237
238 void hddtemp_psensor_list_update(struct psensor **sensors)
239 {
240         char *hddtemp_output;
241
242         hddtemp_output = fetch();
243
244         if (!hddtemp_output)
245                 return;
246
247         if (hddtemp_output[0] == '|') {
248                 char *c = hddtemp_output;
249                 struct hdd_info info;
250
251                 info.name = NULL;
252                 info.temp = 0;
253
254                 while (c && (c = next_hdd_info(c, &info))) {
255
256                         update(sensors, &info);
257
258                         free(info.name);
259                 }
260         } else {
261                 log_err(_("hddtemp: wrong string: %s."), hddtemp_output);
262         }
263
264         free(hddtemp_output);
265 }