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