2 * Copyright (C) 2007 - Luca Bigliardi
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU General Public License
5 * as published by the Free Software Foundation; either version 2
6 * of the License, or (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 #include <sys/socket.h>
29 #include <vdecommon.h>
31 #include <libvdemgmt.h>
34 #define OPENMACHINE_RC INSTALLPATH"/etc/vde2/libvdemgmt/openmachine.rc"
35 #define CLOSEMACHINE_RC INSTALLPATH"/etc/vde2/libvdemgmt/closemachine.rc"
36 #define SENDCMD_RC INSTALLPATH"/etc/vde2/libvdemgmt/sendcmd.rc"
37 #define ASYNCRECV_RC INSTALLPATH"/etc/vde2/libvdemgmt/asyncrecv.rc"
39 #define DEBUGADD "debug/add"
40 #define DEBUGDEL "debug/del"
42 #define CHECK(expr, errval) { char errstr[1024]; if ((expr) == (errval)) { sprintf(errstr, "%s %d %d", __func__, __LINE__, (int)errval); goto error; } }
43 #define CHECKNOT(expr, errval) { char errstr[1024]; if ((expr) != (errval)) { sprintf(errstr, "%s %d %d", __func__, __LINE__, (int)errval); perror(errstr); goto error; } }
53 static struct utm
* open_utm
=NULL
;
54 static struct utm
* close_utm
=NULL
;
55 static struct utm
* sendcmd_utm
=NULL
;
56 static struct utm
* asyncrecv_utm
=NULL
;
60 void (*callback
)(const char *event
, const int tag
, const char *data
);
61 struct asynctab
*next
;
66 struct asynctab
*atab
;
77 struct asynctab
*atab_find(struct asynctab
*atab
, const char *event
)
79 if(!atab
) return atab
;
81 if(!strncmp(atab
->event
, event
, strlen(atab
->event
))) return atab
;
82 else return atab_find(atab
->next
, event
);
86 struct asynctab
*atab_add(struct asynctab
*atab
, struct asynctab
*new)
92 atab
->next
=atab_add(atab
->next
, new);
97 struct asynctab
*atab_del(struct asynctab
*atab
, const char *event
)
99 if(!atab
) return atab
;
101 if(!strncmp(atab
->event
, event
, strlen(atab
->event
))){
102 struct asynctab
*t
=atab
->next
;
106 atab
->next
=atab_del(atab
->next
, event
);
111 static int qstrcmp(const void *a
,const void *b
)
113 return strcmp(*(char * const *)a
,*(char * const *)b
);
121 /* open vdemgmt connection */
122 struct vdemgmt
*vdemgmt_open(const char *path
)
125 struct sockaddr_un sun
;
126 struct vdemgmt
*conn
= NULL
;
129 char *myargv
= NULL
, *sep
;
132 CHECK( open_utm
= utm_alloc(OPENMACHINE_RC
) , NULL
);
134 CHECK( close_utm
= utm_alloc(CLOSEMACHINE_RC
) , NULL
);
136 CHECK( sendcmd_utm
= utm_alloc(SENDCMD_RC
) , NULL
);
138 CHECK( asyncrecv_utm
= utm_alloc(ASYNCRECV_RC
) , NULL
);
140 /* vdemgmt connection struct */
141 CHECK( conn
= (struct vdemgmt
*)malloc(sizeof(struct vdemgmt
)) , NULL
);
142 memset(conn
, 0, sizeof(struct vdemgmt
));
143 CHECK( conn
->pbuf
= (struct utm_buf
*)malloc(sizeof(struct utm_buf
)) , NULL
);
144 memset(conn
->pbuf
, 0, sizeof(struct utm_buf
));
146 /* connect to management socket (non block fd) */
147 sun
.sun_family
=PF_UNIX
;
148 snprintf(sun
.sun_path
,sizeof(sun
.sun_path
),"%s", path
);
149 conn
->fd
= socket(PF_UNIX
,SOCK_STREAM
,0);
150 CHECK( fcntl(conn
->fd
, F_SETFL
, O_NONBLOCK
) , -1 );
151 CHECK( connect(conn
->fd
,(struct sockaddr
*)(&sun
),sizeof(sun
)) , -1 );
155 /* get welcome data */
157 CHECK( utm_run(open_utm
,conn
->pbuf
,conn
->fd
,myargc
,&myargv
,out
,DBGM
), -1 );
159 /* split banner / prompt and extract version */
160 for( sep
=out
->buf
+out
->sz
; ! strstr(sep
, "\n") ; sep
--);
161 conn
->banner
= strndup(out
->buf
, sep
- out
->buf
-1);
162 conn
->prompt
= strndup(sep
+1, (out
->buf
+out
->sz
)-sep
+1);
163 sep
=strstr(conn
->banner
, "V.")+2;
164 conn
->version
= strndup(sep
, strstr(sep
, "\n")-sep
);
174 free(conn
->pbuf
->buf
);
184 /* close vdemgmt connection */
185 void vdemgmt_close(struct vdemgmt
*conn
)
192 /* Deactivate all async events */
193 while(conn
->atab
) vdemgmt_asyncunreg(conn
, conn
->atab
->event
);
197 utm_run(close_utm
,conn
->pbuf
,conn
->fd
,myargc
,&myargv
,out
,DBGM
);
202 free(conn
->pbuf
->buf
);
204 free((char *)conn
->banner
);
205 free((char *)conn
->prompt
);
206 free((char *)conn
->version
);
210 /* return file descriptor of vdemgmt connection */
211 int vdemgmt_getfd(struct vdemgmt
*conn
)
219 /* send command cmd and wait for its output */
220 int vdemgmt_sendcmd(struct vdemgmt
*conn
, const char *cmd
, struct vdemgmt_out
*out
)
224 char *token
, *dupcmd
, **myargv
= NULL
;
225 struct utm_out
*utmout
, *p
;
226 struct asynctab
*t
=NULL
;
228 /* create myargv array from cmd */
229 for( dupcmd
=strdup(cmd
) ; ; dupcmd
=NULL
){
230 token
= strtok(dupcmd
, " ");
231 myargv
=realloc(myargv
, (myargc
+1)*sizeof(char *));
233 myargv
[myargc
]=token
;
238 /* send command using machine */
239 utmout
=utmout_alloc();
240 rv
=utm_run(sendcmd_utm
,conn
->pbuf
,conn
->fd
,myargc
,myargv
,utmout
,DBGM
);
242 /* scan machine data for sync and async output */
245 if( (p
->tag
== DATATAG
) && out
) {
247 out
->buf
=(char *)malloc(p
->sz
*sizeof(char));
248 if(!out
->buf
) { perror(__func__
); exit(-1);}
249 memcpy(out
->buf
, p
->buf
, p
->sz
);
251 if( p
->tag
== ASYNTAG
){
252 t
=atab_find(conn
->atab
, p
->buf
+SKIPHEAD
);
253 if(t
) t
->callback(t
->event
, rv
, p
->buf
+strlen(t
->event
)+SKIPHEAD
+1);
263 /* free outbuffer returned by vdemgmt_sendcmd */
264 void vdemgmt_freeout(struct vdemgmt_out
*out
)
267 if(out
->buf
) free(out
->buf
);
272 /* reset outbuffer after vdemgmt_sendcmd, */
273 void vdemgmt_rstout(struct vdemgmt_out
*out
)
276 if(out
->buf
) free(out
->buf
);
282 /* register func as handler for asyncronous output received with command cmd */
283 int vdemgmt_asyncreg(struct vdemgmt
*conn
, const char *event
, void (*callback
)(const char *event
, const int tag
, const char *data
) )
286 struct asynctab
*new = NULL
;
290 if( atab_find(conn
->atab
, event
) ) return rv
;
293 CHECK( asprintf(&swcmd
,"%s %s",DEBUGADD
,event
) , -1 );
294 CHECKNOT( rv
=vdemgmt_sendcmd(conn
, swcmd
, NULL
) , 0);
295 free(swcmd
); swcmd
=NULL
;
297 /* Add callback function to connection's async tab */
298 CHECK( new = (struct asynctab
*)malloc(sizeof(struct asynctab
)) , NULL
);
299 memset(new, 0, sizeof(struct asynctab
));
300 new->event
= strdup(event
);
301 new->callback
= callback
;
303 conn
->atab
=atab_add(conn
->atab
, new);
308 if(swcmd
) free(swcmd
);
312 /* unregister asyncronous output callback for command cmd */
313 void vdemgmt_asyncunreg(struct vdemgmt
*conn
, const char *event
)
317 /* Dectivate debug on switch */
318 CHECK( asprintf(&swcmd
,"%s %s",DEBUGDEL
,event
) , -1 );
319 CHECKNOT( vdemgmt_sendcmd(conn
, swcmd
, NULL
) , 0);
322 if(swcmd
) free(swcmd
);
323 conn
->atab
=atab_del(conn
->atab
, event
);
326 /* handle asyncronous output */
327 void vdemgmt_asyncrecv(struct vdemgmt
*conn
)
338 /* run async machine and call the handler for the event */
340 outtag
=utm_run(asyncrecv_utm
,conn
->pbuf
,conn
->fd
,myargc
,&myargv
,out
,DBGM
);
342 t
=atab_find(conn
->atab
, out
->buf
+SKIPHEAD
);
343 if(t
) t
->callback(t
->event
, outtag
, out
->buf
+strlen(t
->event
)+SKIPHEAD
+1+prevpos
);
344 prevpos
= conn
->pbuf
->pos
;
345 free(out
->buf
) ; out
->buf
= NULL
; out
->sz
= 0;
346 } while ( conn
->pbuf
->len
> conn
->pbuf
->pos
);
353 const char *vdemgmt_getbanner(struct vdemgmt
*conn
)
358 const char *vdemgmt_getprompt(struct vdemgmt
*conn
)
363 const char *vdemgmt_getversion(struct vdemgmt
*conn
)
365 return conn
->version
;
368 char **vdemgmt_commandlist(struct vdemgmt
*conn
)
370 int i
=0, j
, ncommands
;
371 char *p
=NULL
, *s
=NULL
, **out
=NULL
, *es
="";
372 struct vdemgmt_out buf
;
374 memset(&buf
, 0, sizeof(struct vdemgmt_out
));
376 CHECKNOT(vdemgmt_sendcmd(conn
, "help", &buf
), 0);
379 while(strncmp(p
,"------------",12)) p
++;
381 /* extract command list */
382 while( p
< buf
.buf
+ buf
.sz
){
384 while (*s
&& *s
!=' ' && *s
!='\t') s
++;
385 out
=realloc(out
, (i
+1)*sizeof(char *));
386 out
[i
]=strndup(p
, s
-p
);
391 /* delete menu entries */
392 for(j
=0; j
<i
-1; j
++){
393 if (!strncmp(out
[j
],out
[j
+1],strlen(out
[j
])) &&
394 out
[j
+1][strlen(out
[j
])] == '/') {
395 free(out
[j
]); out
[j
]=es
;
399 /* sort and resize array */
400 qsort(out
,i
,sizeof(char *),qstrcmp
);
401 memmove(out
, out
+(i
-ncommands
), ncommands
*sizeof(char *));
402 out
=realloc(out
, (ncommands
+1)*sizeof(char *));
411 void vdemgmt_freecommandlist(char **cl
)
414 while(cl
[i
]){ free(cl
[i
]); cl
[i
]=NULL
; i
++; }
420 void handle(const char *e, const char *d){
421 printf("--received %s--\n%s\n--\n", e, d);
424 int main(int argc, char **argv){
426 struct vdemgmt *conn;
427 struct vdemgmt_out buf;
431 memset(&buf, 0, sizeof(struct vdemgmt_out));
433 if(argc < 2) {printf("bad cmd\n"); exit(-1);}
434 conn = vdemgmt_open(argv[1]);
435 printf("--open done--\n");
436 printf("--command list--\n");
437 cl=vdemgmt_commandlist(conn);
440 printf("%d, %s\n", j, cl[j]); j++;}}
441 vdemgmt_freecommandlist(cl);
442 printf("--end command list--\n");
443 printf("--parsebuf--\n");
444 write(1, conn->pbuf->buf + conn->pbuf->pos, conn->pbuf->len - conn->pbuf->pos);
445 printf("\n--end parsebuf--\n");
447 printf("--banner is--\n%s\n--\n", vdemgmt_getbanner(conn));
448 printf("--prompt is--\n%s\n--\n", vdemgmt_getprompt(conn));
449 printf("--version is--\n%s\n--\n", vdemgmt_getversion(conn));
451 rv = vdemgmt_sendcmd(conn, "port/allprint", NULL);
452 printf("--null send done--\n");
453 printf("--parsebuf--\n");
454 write(1, conn->pbuf->buf + conn->pbuf->pos, conn->pbuf->len - conn->pbuf->pos);
455 printf("\n--end parsebuf--\n");
457 rv = vdemgmt_sendcmd(conn, "fstp/print", &buf);
458 printf("--send done--\n");
459 write(1, buf.buf, buf.sz);
461 printf("--async reg--\n");
462 rv=vdemgmt_asyncreg(conn, "fstp/root", &handle);
463 printf("--return is: %d\n", rv);
464 vdemgmt_rstout(&buf);
465 vdemgmt_sendcmd(conn, "debug/list", &buf);
466 write(1, buf.buf, buf.sz);
467 printf("--async re-reg--\n");
468 rv=vdemgmt_asyncreg(conn, "fstp/root", &handle);
469 printf("--return is: %d\n", rv);
470 printf("--begin cycle\n");
471 for(i=0; i < 3; i++){
472 struct pollfd pfd={vdemgmt_getfd(conn), POLLIN, 0};
474 vdemgmt_asyncrecv(conn);
476 printf("--end cycle\n");
477 printf("--async unreg--\n");
478 vdemgmt_asyncunreg(conn, "fstp/root");
479 vdemgmt_rstout(&buf);
480 vdemgmt_sendcmd(conn, "debug/list", &buf);
481 write(1, buf.buf, buf.sz);