Add “ros”, a small sample command line tool.
[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 static const char *opt_username = "admin";
40
41 static int result_handler (ros_connection_t *c, const ros_reply_t *r, /* {{{ */
42                 void *user_data)
43 {
44         unsigned int i;
45
46         if (r == NULL)
47                 return (0);
48
49         printf ("Status: %s\n", ros_reply_status (r));
50
51         for (i = 0; /* true */; i++)
52         {
53                 const char *key;
54                 const char *val;
55
56                 key = ros_reply_param_key_by_index (r, i);
57                 val = ros_reply_param_val_by_index (r, i);
58
59                 if ((key == NULL) || (val == NULL))
60                 {
61                         if (key != NULL)
62                                 fprintf (stderr, "val is NULL but key is %s!\n", key);
63                         if (val != NULL)
64                                 fprintf (stderr, "key is NULL but val is %s!\n", val);
65                         break;
66                 }
67
68                 printf ("  Param %u: %s = %s\n", i, key, val);
69         }
70
71         printf ("===\n");
72
73         return (result_handler (c, ros_reply_next (r), user_data));
74 } /* }}} int result_handler */
75
76 static void regtable_dump (const ros_registration_table_t *r) /* {{{ */
77 {
78         if (r == NULL)
79                 return;
80
81         printf ("=== %s ===\n", r->interface);
82         printf ("Rate:           %7g Mbps / %7g Mbps\n", r->rx_rate, r->tx_rate);
83         printf ("Packets:        %12"PRIu64" / %12"PRIu64"\n",
84                         r->rx_packets, r->tx_packets);
85         printf ("Bytes:          %12"PRIu64" / %12"PRIu64"\n",
86                         r->rx_bytes, r->tx_bytes);
87         printf ("Frames          %12"PRIu64" / %12"PRIu64"\n",
88                         r->rx_frames, r->tx_frames);
89         printf ("Frame Bytes:    %12"PRIu64" / %12"PRIu64"\n",
90                         r->rx_frame_bytes, r->tx_frame_bytes);
91         printf ("HW Frames:      %12"PRIu64" / %12"PRIu64"\n",
92                         r->rx_hw_frames, r->tx_hw_frames);
93         printf ("HW Frame Bytes: %12"PRIu64" / %12"PRIu64"\n",
94                         r->rx_hw_frame_bytes, r->tx_hw_frame_bytes);
95         printf ("Quality:        %10g %% / %10g %%\n",
96                         r->rx_ccq, r->tx_ccq);
97         printf ("Signal str.:    %8g dBm / %8g dBm\n",
98                 r->rx_signal_strength, r->tx_signal_strength);
99         printf ("Signal / noise: %8g dBm\n", r->signal_to_noise);
100         printf ("==========\n");
101
102         regtable_dump (r->next);
103 } /* }}} void regtable_dump */
104
105 static int regtable_handler (ros_connection_t *c, /* {{{ */
106                 const ros_registration_table_t *r, void *user_data)
107 {
108         regtable_dump (r);
109         return (0);
110 } /* }}} int regtable_handler */
111
112 static char *read_password (void) /* {{{ */
113 {
114         FILE *tty;
115         struct termios old_flags;
116         struct termios new_flags;
117         int status;
118         char buffer[1024];
119         size_t buffer_len;
120         char *passwd;
121
122         tty = fopen ("/dev/tty", "w+");
123         if (tty == NULL)
124         {
125                 fprintf (stderr, "Unable to open /dev/tty: %s\n",
126                                 strerror (errno));
127                 return (NULL);
128         }
129
130         fprintf (tty, "Password for user %s: ", opt_username);
131         fflush (tty);
132
133         memset (&old_flags, 0, sizeof (old_flags));
134         tcgetattr (fileno (tty), &old_flags);
135         new_flags = old_flags;
136         /* clear ECHO */
137         new_flags.c_lflag &= ~ECHO;
138         /* set ECHONL */
139         new_flags.c_lflag |= ECHONL;
140
141         status = tcsetattr (fileno (tty), TCSANOW, &new_flags);
142         if (status != 0)
143         {
144                 fprintf (stderr, "tcsetattr failed: %s\n", strerror (errno));
145                 fclose (tty);
146                 return (NULL);
147         }
148
149         fgets (buffer, sizeof (buffer), tty);
150         buffer[sizeof (buffer) - 1] = 0;
151         buffer_len = strlen (buffer);
152
153         status = tcsetattr (fileno (tty), TCSANOW, &old_flags);
154         if (status != 0)
155                 fprintf (stderr, "tcsetattr failed: %s\n", strerror (errno));
156
157         fclose (tty);
158         tty = NULL;
159
160         while ((buffer_len > 0) && ((buffer[buffer_len-1] == '\n') || (buffer[buffer_len-1] == '\r')))
161         {
162                 buffer_len--;
163                 buffer[buffer_len] = 0;
164         }
165         if (buffer_len == 0)
166                 return (NULL);
167
168         passwd = malloc (strlen (buffer) + 1);
169         if (passwd == NULL)
170                 return (NULL);
171         memcpy (passwd, buffer, strlen (buffer) + 1);
172         memset (buffer, 0, sizeof (buffer));
173
174         return (passwd);
175 } /* }}} char *read_password */
176
177 static void exit_usage (void) /* {{{ */
178 {
179         printf ("Usage: ros [options] <host> <command> [args]\n");
180         exit (EXIT_SUCCESS);
181 } /* }}} void exit_usage */
182
183 int main (int argc, char **argv) /* {{{ */
184 {
185         ros_connection_t *c;
186         char *passwd;
187         const char *host;
188         const char *command;
189
190         int option;
191
192         while ((option = getopt (argc, argv, "u:h?")) != -1)
193         {
194                 switch (option)
195                 {
196                         case 'u':
197                                 opt_username = optarg;
198                                 break;
199
200                         case 'h':
201                         case '?':
202                         default:
203                                 exit_usage ();
204                                 break;
205                 }
206         }
207
208         if ((argc - optind) < 2)
209                 exit_usage ();
210
211         host = argv[optind];
212         command = argv[optind+1];
213
214         passwd = read_password ();
215         if (passwd == NULL)
216                 exit (EXIT_FAILURE);
217
218         c = ros_connect (argv[optind], ROUTEROS_API_PORT,
219                         opt_username, passwd);
220         memset (passwd, 0, strlen (passwd));
221         if (c == NULL)
222         {
223                 fprintf (stderr, "ros_connect failed: %s\n", strerror (errno));
224                 exit (EXIT_FAILURE);
225         }
226
227         if (command[0] == '/')
228         {
229                 ros_query (c, command,
230                                 (size_t) (argc - (optind + 2)), (const char * const *) (argv + optind + 2),
231                                 result_handler, /* user data = */ NULL);
232         }
233         else if (strcmp ("registration-table", command) == 0)
234         {
235                 ros_registration_table (c, regtable_handler, /* user data = */ NULL);
236         }
237         else
238         {
239                 fprintf (stderr, "Unknown built-in command %s. "
240                                 "Are you missing a leading slash?\n", command);
241         }
242
243         ros_disconnect (c);
244
245         return (0);
246 } /* }}} int main */
247
248 /* vim: set ts=2 sw=2 noet fdm=marker : */