31aafa8ec5057fbe65ebffb36978165fe4c0a066
[routeros-api.git] / src / ros.c
1 /**
2  * libmikrotik - src/ros.c
3  * Copyright (C) 2009  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
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 along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Florian octo Forster <octo at verplant.org>
20  **/
21
22 #ifndef _ISOC99_SOURCE
23 # define _ISOC99_SOURCE
24 #endif
25
26 #ifndef _POSIX_C_SOURCE
27 # define _POSIX_C_SOURCE 200112L
28 #endif
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <termios.h>
35 #include <getopt.h>
36
37 #include "routeros_api.h"
38
39 #if !__GNUC__
40 # define __attribute__(x) /**/
41 #endif
42
43 static const char *opt_username = "admin";
44
45 static int result_handler (ros_connection_t *c, const ros_reply_t *r, /* {{{ */
46                 void *user_data)
47 {
48         unsigned int i;
49
50         if (r == NULL)
51                 return (0);
52
53         printf ("Status: %s\n", ros_reply_status (r));
54
55         for (i = 0; /* true */; i++)
56         {
57                 const char *key;
58                 const char *val;
59
60                 key = ros_reply_param_key_by_index (r, i);
61                 val = ros_reply_param_val_by_index (r, i);
62
63                 if ((key == NULL) || (val == NULL))
64                 {
65                         if (key != NULL)
66                                 fprintf (stderr, "val is NULL but key is %s!\n", key);
67                         if (val != NULL)
68                                 fprintf (stderr, "key is NULL but val is %s!\n", val);
69                         break;
70                 }
71
72                 printf ("  Param %u: %s = %s\n", i, key, val);
73         }
74
75         printf ("===\n");
76
77         return (result_handler (c, ros_reply_next (r), user_data));
78 } /* }}} int result_handler */
79
80 static void regtable_dump (const ros_registration_table_t *r) /* {{{ */
81 {
82         if (r == NULL)
83                 return;
84
85         printf ("=== %s / %s ===\n", r->interface, r->radio_name);
86         printf ("Mode:           %12s\n",
87                         r->ap ? (r->wds ? "AP with WDS" : "Access point") : "Station");
88         printf ("Rate:           %7g Mbps / %7g Mbps\n", r->rx_rate, r->tx_rate);
89         printf ("Packets:        %12"PRIu64" / %12"PRIu64"\n",
90                         r->rx_packets, r->tx_packets);
91         printf ("Bytes:          %12"PRIu64" / %12"PRIu64"\n",
92                         r->rx_bytes, r->tx_bytes);
93         printf ("Frames          %12"PRIu64" / %12"PRIu64"\n",
94                         r->rx_frames, r->tx_frames);
95         printf ("Frame Bytes:    %12"PRIu64" / %12"PRIu64"\n",
96                         r->rx_frame_bytes, r->tx_frame_bytes);
97         printf ("HW Frames:      %12"PRIu64" / %12"PRIu64"\n",
98                         r->rx_hw_frames, r->tx_hw_frames);
99         printf ("HW Frame Bytes: %12"PRIu64" / %12"PRIu64"\n",
100                         r->rx_hw_frame_bytes, r->tx_hw_frame_bytes);
101         printf ("Quality:        %10g %% / %10g %%\n",
102                         r->rx_ccq, r->tx_ccq);
103         printf ("Signal str.:    %8g dBm / %8g dBm\n",
104                 r->rx_signal_strength, r->tx_signal_strength);
105         printf ("Signal / noise: %8g dBm\n", r->signal_to_noise);
106         printf ("==========\n");
107
108         regtable_dump (r->next);
109 } /* }}} void regtable_dump */
110
111 static int regtable_handler (__attribute__((unused)) ros_connection_t *c, /* {{{ */
112                 const ros_registration_table_t *r,
113                 __attribute__((unused)) void *user_data)
114 {
115         regtable_dump (r);
116         return (0);
117 } /* }}} int regtable_handler */
118
119 static void interface_dump (const ros_interface_t *i) /* {{{ */
120 {
121         if (i == NULL)
122                 return;
123
124         printf ("=== %s ===\n"
125                         "Type:    %12s\n"
126                         "Comment: %12s\n"
127                         "Bytes:   %12"PRIu64" / %12"PRIu64"\n"
128                         "Packets: %12"PRIu64" / %12"PRIu64"\n"
129                         "Errors:  %12"PRIu64" / %12"PRIu64"\n"
130                         "Drops:   %12"PRIu64" / %12"PRIu64"\n"
131                         "MTU:     %12u\n"
132                         "L2 MTU:  %12u\n"
133                         "Running: %12s\n"
134                         "Dynamic: %12s\n"
135                         "Enabled: %12s\n"
136                         "==========\n",
137                         i->name, i->type, i->comment,
138                         i->rx_bytes, i->tx_bytes,
139                         i->rx_packets, i->tx_packets,
140                         i->rx_errors, i->tx_errors,
141                         i->rx_drops, i->tx_drops,
142                         i->mtu, i->l2mtu,
143                         i->running ? "true" : "false",
144                         i->dynamic ? "true" : "false",
145                         i->enabled ? "true" : "false");
146
147         interface_dump (i->next);
148 } /* }}} void interface_dump */
149
150 static int interface_handler (__attribute__((unused)) ros_connection_t *c, /* {{{ */
151                 const ros_interface_t *i,
152                 __attribute__((unused)) void *user_data)
153 {
154         interface_dump (i);
155         return (0);
156 } /* }}} int interface_handler */
157
158 static int system_resource_handler (__attribute__((unused)) ros_connection_t *c, /* {{{ */
159                 const ros_system_resource_t *r, __attribute__((unused)) void *user_data)
160 {
161         uint64_t used_memory;
162         uint64_t used_hdd_space;
163
164         if (r == NULL)
165                 return (EINVAL);
166
167         used_memory = r->total_memory - r->free_memory;
168         used_hdd_space = r->total_hdd_space - r->free_hdd_space;
169
170         printf ("====== System resources ======\n"
171                         "Uptime:        %10.2f days\n"
172                         "RouterOS version:  %11s\n"
173                         "Architecture name: %11s\n"
174                         "Board name:    %15s\n"
175                         "CPU model:     %15s\n"
176                         "CPU count:     %15u\n"
177                         "CPU load:      %15u\n"
178                         "CPU frequency: %11g MHz\n"
179                         "Memory free:   %10"PRIu64" Byte (%4.1f %%)\n"
180                         "Memory used:   %10"PRIu64" Byte (%4.1f %%)\n"
181                         "Memory total:  %10"PRIu64" Byte\n"
182                         "Space free:    %10"PRIu64" Byte (%4.1f %%)\n"
183                         "Space used:    %10"PRIu64" Byte (%4.1f %%)\n"
184                         "Space total:   %10"PRIu64" Byte\n"
185                         "Sectors written: %13"PRIu64" (%"PRIu64")\n"
186                         "Bad blocks:    %15"PRIu64"\n"
187                         "==============================\n",
188                         ((double) r->uptime) / 86400.0, r->version,
189                         r->architecture_name, r->board_name,
190                         r->cpu_model, r->cpu_count, r->cpu_load,
191                         ((double) r->cpu_frequency) / 1000000.0,
192                         r->free_memory,
193                         100.0 * (((double) r->free_memory) / ((double) r->total_memory)),
194                         used_memory,
195                         100.0 * (((double) used_memory) / ((double) r->total_memory)),
196                         r->total_memory,
197                         r->free_hdd_space,
198                         100.0 * (((double) r->free_hdd_space) / ((double) r->total_hdd_space)),
199                         used_hdd_space,
200                         100.0 * (((double) used_hdd_space) / ((double) r->total_hdd_space)),
201                         r->total_hdd_space,
202                         r->write_sect_since_reboot,
203                         r->write_sect_total,
204                         r->bad_blocks);
205
206         return (0);
207 } /* }}} int system_resource_handler */
208
209 static char *read_password (void) /* {{{ */
210 {
211         FILE *tty;
212         struct termios old_flags;
213         struct termios new_flags;
214         int status;
215         char buffer[1024];
216         size_t buffer_len;
217         char *passwd;
218
219         tty = fopen ("/dev/tty", "w+");
220         if (tty == NULL)
221         {
222                 fprintf (stderr, "Unable to open /dev/tty: %s\n",
223                                 strerror (errno));
224                 return (NULL);
225         }
226
227         fprintf (tty, "Password for user %s: ", opt_username);
228         fflush (tty);
229
230         memset (&old_flags, 0, sizeof (old_flags));
231         tcgetattr (fileno (tty), &old_flags);
232         new_flags = old_flags;
233         /* clear ECHO */
234         new_flags.c_lflag &= ~ECHO;
235         /* set ECHONL */
236         new_flags.c_lflag |= ECHONL;
237
238         status = tcsetattr (fileno (tty), TCSANOW, &new_flags);
239         if (status != 0)
240         {
241                 fprintf (stderr, "tcsetattr failed: %s\n", strerror (errno));
242                 fclose (tty);
243                 return (NULL);
244         }
245
246         if (fgets (buffer, sizeof (buffer), tty) == NULL)
247         {
248                 fprintf (stderr, "fgets failed: %s\n", strerror (errno));
249                 fclose (tty);
250                 return (NULL);
251         }
252         buffer[sizeof (buffer) - 1] = 0;
253         buffer_len = strlen (buffer);
254
255         status = tcsetattr (fileno (tty), TCSANOW, &old_flags);
256         if (status != 0)
257                 fprintf (stderr, "tcsetattr failed: %s\n", strerror (errno));
258
259         fclose (tty);
260         tty = NULL;
261
262         while ((buffer_len > 0) && ((buffer[buffer_len-1] == '\n') || (buffer[buffer_len-1] == '\r')))
263         {
264                 buffer_len--;
265                 buffer[buffer_len] = 0;
266         }
267         if (buffer_len == 0)
268                 return (NULL);
269
270         passwd = malloc (strlen (buffer) + 1);
271         if (passwd == NULL)
272                 return (NULL);
273         memcpy (passwd, buffer, strlen (buffer) + 1);
274         memset (buffer, 0, sizeof (buffer));
275
276         return (passwd);
277 } /* }}} char *read_password */
278
279 static void exit_usage (void) /* {{{ */
280 {
281         printf ("Usage: ros [options] <host> <command> [args]\n"
282                         "\n"
283                         "OPTIONS:\n"
284                         "  -u <user>       Use <user> to authenticate.\n"
285                         "  -h              Display this help message.\n"
286                         "\n");
287         if (ros_version () == ROS_VERSION)
288                 printf ("Using librouteros %s\n", ROS_VERSION_STRING);
289         else
290                 printf ("Using librouteros %s (%s)\n",
291                                 ros_version_string (), ROS_VERSION_STRING);
292         printf ("Copyright (c) 2009 by Florian Forster\n");
293
294         exit (EXIT_SUCCESS);
295 } /* }}} void exit_usage */
296
297 int main (int argc, char **argv) /* {{{ */
298 {
299         ros_connection_t *c;
300         char *passwd;
301         const char *host;
302         const char *command;
303
304         int option;
305
306         while ((option = getopt (argc, argv, "u:h?")) != -1)
307         {
308                 switch (option)
309                 {
310                         case 'u':
311                                 opt_username = optarg;
312                                 break;
313
314                         case 'h':
315                         case '?':
316                         default:
317                                 exit_usage ();
318                                 break;
319                 }
320         }
321
322         if ((argc - optind) < 2)
323                 exit_usage ();
324
325         host = argv[optind];
326         command = argv[optind+1];
327
328         passwd = read_password ();
329         if (passwd == NULL)
330                 exit (EXIT_FAILURE);
331
332         c = ros_connect (host, ROUTEROS_API_PORT,
333                         opt_username, passwd);
334         memset (passwd, 0, strlen (passwd));
335         if (c == NULL)
336         {
337                 fprintf (stderr, "ros_connect failed: %s\n", strerror (errno));
338                 exit (EXIT_FAILURE);
339         }
340
341         if (command[0] == '/')
342         {
343                 ros_query (c, command,
344                                 (size_t) (argc - (optind + 2)), (const char * const *) (argv + optind + 2),
345                                 result_handler, /* user data = */ NULL);
346         }
347         else if (strcmp ("interface", command) == 0)
348         {
349                 ros_interface (c, interface_handler, /* user data = */ NULL);
350         }
351         else if (strcmp ("registration-table", command) == 0)
352         {
353                 ros_registration_table (c, regtable_handler, /* user data = */ NULL);
354         }
355         else if (strcmp ("system-resource", command) == 0)
356         {
357                 ros_system_resource (c, system_resource_handler, /* user data = */ NULL);
358         }
359         else
360         {
361                 fprintf (stderr, "Unknown built-in command %s. "
362                                 "Are you missing a leading slash?\n", command);
363         }
364
365         ros_disconnect (c);
366
367         return (0);
368 } /* }}} int main */
369
370 /* vim: set ts=2 sw=2 noet fdm=marker : */