oops
[asterisk/asterisk.git] / asterisk.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19
20 /* Doxygenified Copyright Header */
21 /*!
22  * \mainpage Asterisk -- An Open Source Telephony Toolkit
23  *
24  * \par Developer Documentation for Asterisk
25  * This is the main developer documentation for Asterisk. It is 
26  * generated by running "make progdocs".
27  * \par Additional documentation
28  * \arg \ref DevDoc 
29  * \arg \ref ConfigFiles
30  *
31  * \section copyright Copyright and author
32  *
33  * Copyright (C) 1999 - 2005, Digium, Inc.
34  * Asterisk is a trade mark registered by Digium, Inc.
35  *
36  * \author Mark Spencer <markster@digium.com>
37  * Also see \ref AstCREDITS
38  *
39  * \section license License
40  * See http://www.asterisk.org for more information about
41  * the Asterisk project. Please do not directly contact
42  * any of the maintainers of this project for assistance;
43  * the project provides a web site, mailing lists and IRC
44  * channels for your use.
45  *
46  * This program is free software, distributed under the terms of
47  * the GNU General Public License Version 2. See the LICENSE file
48  * at the top of the source tree.
49  *
50  * \verbinclude LICENSE
51  *
52  */
53
54 /*! \file
55   \brief Top level source file for Asterisk  - the Open Source PBX. Implementation
56   of PBX core functions and CLI interface.
57   
58  */
59
60 #include <unistd.h>
61 #include <stdlib.h>
62 #include <sys/time.h>
63 #include <fcntl.h>
64 #include <stdio.h>
65 #include <signal.h>
66 #include <sched.h>
67 #include <sys/socket.h>
68 #include <sys/un.h>
69 #include <sys/wait.h>
70 #include <string.h>
71 #include <errno.h>
72 #include <ctype.h>
73 #include <sys/resource.h>
74 #include <grp.h>
75 #include <pwd.h>
76 #include <sys/stat.h>
77 #include <regex.h>
78
79 #if  defined(__FreeBSD__) || defined( __NetBSD__ ) || defined(SOLARIS)
80 #include <netdb.h>
81 #endif
82
83 #include "asterisk.h"
84
85 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
86
87 #include "asterisk/logger.h"
88 #include "asterisk/options.h"
89 #include "asterisk/cli.h"
90 #include "asterisk/channel.h"
91 #include "asterisk/ulaw.h"
92 #include "asterisk/alaw.h"
93 #include "asterisk/callerid.h"
94 #include "asterisk/module.h"
95 #include "asterisk/image.h"
96 #include "asterisk/tdd.h"
97 #include "asterisk/term.h"
98 #include "asterisk/manager.h"
99 #include "asterisk/cdr.h"
100 #include "asterisk/pbx.h"
101 #include "asterisk/enum.h"
102 #include "asterisk/rtp.h"
103 #include "asterisk/app.h"
104 #include "asterisk/lock.h"
105 #include "asterisk/utils.h"
106 #include "asterisk/file.h"
107 #include "asterisk/io.h"
108 #include "asterisk/lock.h"
109 #include "editline/histedit.h"
110 #include "asterisk/config.h"
111 #include "asterisk/version.h"
112 #include "asterisk/linkedlists.h"
113 #include "asterisk/devicestate.h"
114 #include "asterisk/compat.h"
115
116 #include "asterisk/doxyref.h"           /* Doxygen documentation */
117
118 #include "defaults.h"
119
120 #ifndef AF_LOCAL
121 #define AF_LOCAL AF_UNIX
122 #define PF_LOCAL PF_UNIX
123 #endif
124
125 #define AST_MAX_CONNECTS 128
126 #define NUM_MSGS 64
127
128 /*! \brief Welcome message when starting a CLI interface */
129 #define WELCOME_MESSAGE \
130         ast_verbose("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2005 Digium, Inc. and others.\n"); \
131         ast_verbose("Created by Mark Spencer <markster@digium.com>\n"); \
132         ast_verbose("Asterisk comes with ABSOLUTELY NO WARRANTY; type 'show warranty' for details.\n"); \
133         ast_verbose("This is free software, with components licensed under the GNU General Public\n"); \
134         ast_verbose("License version 2 and other licenses; you are welcome to redistribute it under\n"); \
135         ast_verbose("certain conditions. Type 'show license' for details.\n"); \
136         ast_verbose("=========================================================================\n")
137
138 /*! \defgroup main_options 
139  \brief Main configuration options from \ref Config_ast "asterisk.conf" or 
140   the operating system command line when starting Asterisk 
141   Some of them can be changed in the CLI 
142  */
143 /*! @{ */
144
145 struct ast_flags ast_options = { AST_OPT_FLAG_TRANSCODE_VIA_SLIN };
146
147 int option_verbose = 0;                         /*!< Verbosity level */
148 int option_debug = 0;                           /*!< Debug level */
149
150 double option_maxload = 0.0;                    /*!< Max load avg on system */
151 int option_maxcalls = 0;                        /*!< Max number of active calls */
152
153 /*! @} */
154
155 char record_cache_dir[AST_CACHE_DIR_LEN] = AST_TMP_DIR;
156 char debug_filename[AST_FILENAME_MAX] = "";
157
158 static int ast_socket = -1;             /*!< UNIX Socket for allowing remote control */
159 static int ast_consock = -1;            /*!< UNIX Socket for controlling another asterisk */
160 int ast_mainpid;
161 struct console {
162         int fd;                         /*!< File descriptor */
163         int p[2];                       /*!< Pipe */
164         pthread_t t;                    /*!< Thread of handler */
165 };
166
167 static struct ast_atexit {
168         void (*func)(void);
169         struct ast_atexit *next;
170 } *atexits = NULL;
171
172 AST_MUTEX_DEFINE_STATIC(atexitslock);
173
174 time_t ast_startuptime;
175 time_t ast_lastreloadtime;
176
177 static History *el_hist = NULL;
178 static EditLine *el = NULL;
179 static char *remotehostname;
180
181 struct console consoles[AST_MAX_CONNECTS];
182
183 char defaultlanguage[MAX_LANGUAGE] = DEFAULT_LANGUAGE;
184
185 static int ast_el_add_history(char *);
186 static int ast_el_read_history(char *);
187 static int ast_el_write_history(char *);
188
189 char ast_config_AST_CONFIG_DIR[AST_CONFIG_MAX_PATH];
190 char ast_config_AST_CONFIG_FILE[AST_CONFIG_MAX_PATH];
191 char ast_config_AST_MODULE_DIR[AST_CONFIG_MAX_PATH];
192 char ast_config_AST_SPOOL_DIR[AST_CONFIG_MAX_PATH];
193 char ast_config_AST_MONITOR_DIR[AST_CONFIG_MAX_PATH];
194 char ast_config_AST_VAR_DIR[AST_CONFIG_MAX_PATH];
195 char ast_config_AST_LOG_DIR[AST_CONFIG_MAX_PATH];
196 char ast_config_AST_AGI_DIR[AST_CONFIG_MAX_PATH];
197 char ast_config_AST_DB[AST_CONFIG_MAX_PATH];
198 char ast_config_AST_KEY_DIR[AST_CONFIG_MAX_PATH];
199 char ast_config_AST_PID[AST_CONFIG_MAX_PATH];
200 char ast_config_AST_SOCKET[AST_CONFIG_MAX_PATH];
201 char ast_config_AST_RUN_DIR[AST_CONFIG_MAX_PATH];
202 char ast_config_AST_RUN_USER[AST_CONFIG_MAX_PATH];
203 char ast_config_AST_RUN_GROUP[AST_CONFIG_MAX_PATH];
204 char ast_config_AST_CTL_PERMISSIONS[AST_CONFIG_MAX_PATH];
205 char ast_config_AST_CTL_OWNER[AST_CONFIG_MAX_PATH] = "\0";
206 char ast_config_AST_CTL_GROUP[AST_CONFIG_MAX_PATH] = "\0";
207 char ast_config_AST_CTL[AST_CONFIG_MAX_PATH] = "asterisk.ctl";
208
209 static char *_argv[256];
210 static int shuttingdown = 0;
211 static int restartnow = 0;
212 static pthread_t consolethread = AST_PTHREADT_NULL;
213
214 #if !defined(LOW_MEMORY)
215 struct file_version {
216         AST_LIST_ENTRY(file_version) list;
217         const char *file;
218         char *version;
219 };
220
221 static AST_LIST_HEAD_STATIC(file_versions, file_version);
222
223 void ast_register_file_version(const char *file, const char *version)
224 {
225         struct file_version *new;
226         char *work;
227         size_t version_length;
228
229         work = ast_strdupa(version);
230         work = ast_strip(ast_strip_quoted(work, "$", "$"));
231         version_length = strlen(work) + 1;
232
233         new = calloc(1, sizeof(*new) + version_length);
234         if (!new)
235                 return;
236
237         new->file = file;
238         new->version = (char *) new + sizeof(*new);
239         memcpy(new->version, work, version_length);
240         AST_LIST_LOCK(&file_versions);
241         AST_LIST_INSERT_HEAD(&file_versions, new, list);
242         AST_LIST_UNLOCK(&file_versions);
243 }
244
245 void ast_unregister_file_version(const char *file)
246 {
247         struct file_version *find;
248
249         AST_LIST_LOCK(&file_versions);
250         AST_LIST_TRAVERSE_SAFE_BEGIN(&file_versions, find, list) {
251                 if (!strcasecmp(find->file, file)) {
252                         AST_LIST_REMOVE_CURRENT(&file_versions, list);
253                         break;
254                 }
255         }
256         AST_LIST_TRAVERSE_SAFE_END;
257         AST_LIST_UNLOCK(&file_versions);
258         if (find)
259                 free(find);
260 }
261
262 static char show_version_files_help[] = 
263 "Usage: show version files [like <pattern>]\n"
264 "       Shows the revision numbers of the files used to build this copy of Asterisk.\n"
265 "       Optional regular expression pattern is used to filter the file list.\n";
266
267 /*! CLI command to list module versions */
268 static int handle_show_version_files(int fd, int argc, char *argv[])
269 {
270 #define FORMAT "%-25.25s %-40.40s\n"
271         struct file_version *iterator;
272         regex_t regexbuf;
273         int havepattern = 0;
274         int havename = 0;
275         int count_files = 0;
276
277         switch (argc) {
278         case 5:
279                 if (!strcasecmp(argv[3], "like")) {
280                         if (regcomp(&regexbuf, argv[4], REG_EXTENDED | REG_NOSUB))
281                                 return RESULT_SHOWUSAGE;
282                         havepattern = 1;
283                 } else
284                         return RESULT_SHOWUSAGE;
285                 break;
286         case 4:
287                 havename = 1;
288                 break;
289         case 3:
290                 break;
291         default:
292                 return RESULT_SHOWUSAGE;
293         }
294
295         ast_cli(fd, FORMAT, "File", "Revision");
296         ast_cli(fd, FORMAT, "----", "--------");
297         AST_LIST_LOCK(&file_versions);
298         AST_LIST_TRAVERSE(&file_versions, iterator, list) {
299                 if (havename && strcasecmp(iterator->file, argv[3]))
300                         continue;
301
302                 if (havepattern && regexec(&regexbuf, iterator->file, 0, NULL, 0))
303                         continue;
304
305                 ast_cli(fd, FORMAT, iterator->file, iterator->version);
306                 count_files++;
307                 if (havename)
308                         break;
309         }
310         AST_LIST_UNLOCK(&file_versions);
311         if (!havename) {
312                 ast_cli(fd, "%d files listed.\n", count_files);
313         }
314
315         if (havepattern)
316                 regfree(&regexbuf);
317
318         return RESULT_SUCCESS;
319 #undef FORMAT
320 }
321
322 static char *complete_show_version_files(char *line, char *word, int pos, int state)
323 {
324         struct file_version *find;
325         int which = 0;
326         char *ret = NULL;
327         int matchlen = strlen(word);
328
329         if (pos != 3)
330                 return NULL;
331
332         AST_LIST_LOCK(&file_versions);
333         AST_LIST_TRAVERSE(&file_versions, find, list) {
334                 if (!strncasecmp(word, find->file, matchlen)) {
335                         if (++which > state) {
336                                 ret = strdup(find->file);
337                                 break;
338                         }
339                 }
340         }
341         AST_LIST_UNLOCK(&file_versions);
342
343         return ret;
344 }
345 #endif /* ! LOW_MEMORY */
346
347 int ast_register_atexit(void (*func)(void))
348 {
349         int res = -1;
350         struct ast_atexit *ae;
351         ast_unregister_atexit(func);
352         ae = malloc(sizeof(struct ast_atexit));
353         ast_mutex_lock(&atexitslock);
354         if (ae) {
355                 memset(ae, 0, sizeof(struct ast_atexit));
356                 ae->next = atexits;
357                 ae->func = func;
358                 atexits = ae;
359                 res = 0;
360         }
361         ast_mutex_unlock(&atexitslock);
362         return res;
363 }
364
365 void ast_unregister_atexit(void (*func)(void))
366 {
367         struct ast_atexit *ae, *prev = NULL;
368         ast_mutex_lock(&atexitslock);
369         ae = atexits;
370         while(ae) {
371                 if (ae->func == func) {
372                         if (prev)
373                                 prev->next = ae->next;
374                         else
375                                 atexits = ae->next;
376                         break;
377                 }
378                 prev = ae;
379                 ae = ae->next;
380         }
381         ast_mutex_unlock(&atexitslock);
382 }
383
384 static int fdprint(int fd, const char *s)
385 {
386         return write(fd, s, strlen(s) + 1);
387 }
388
389 /*! NULL handler so we can collect the child exit status */
390 static void null_sig_handler(int signal)
391 {
392
393 }
394
395 AST_MUTEX_DEFINE_STATIC(safe_system_lock);
396 static unsigned int safe_system_level = 0;
397 static void *safe_system_prev_handler;
398
399 int ast_safe_system(const char *s)
400 {
401         pid_t pid;
402         int x;
403         int res;
404         struct rusage rusage;
405         int status;
406         unsigned int level;
407
408         /* keep track of how many ast_safe_system() functions
409            are running at this moment
410         */
411         ast_mutex_lock(&safe_system_lock);
412         level = safe_system_level++;
413
414         /* only replace the handler if it has not already been done */
415         if (level == 0)
416                 safe_system_prev_handler = signal(SIGCHLD, null_sig_handler);
417
418         ast_mutex_unlock(&safe_system_lock);
419
420         pid = fork();
421
422         if (pid == 0) {
423                 /* Close file descriptors and launch system command */
424                 for (x = STDERR_FILENO + 1; x < 4096; x++)
425                         close(x);
426                 execl("/bin/sh", "/bin/sh", "-c", s, NULL);
427                 exit(1);
428         } else if (pid > 0) {
429                 for(;;) {
430                         res = wait4(pid, &status, 0, &rusage);
431                         if (res > -1) {
432                                 res = WIFEXITED(status) ? WEXITSTATUS(status) : -1;
433                                 break;
434                         } else if (errno != EINTR) 
435                                 break;
436                 }
437         } else {
438                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
439                 res = -1;
440         }
441
442         ast_mutex_lock(&safe_system_lock);
443         level = --safe_system_level;
444
445         /* only restore the handler if we are the last one */
446         if (level == 0)
447                 signal(SIGCHLD, safe_system_prev_handler);
448
449         ast_mutex_unlock(&safe_system_lock);
450
451         return res;
452 }
453
454 /*!
455  * write the string to all attached console clients
456  */
457 static void ast_network_puts(const char *string)
458 {
459         int x;
460         for (x=0;x<AST_MAX_CONNECTS; x++) {
461                 if (consoles[x].fd > -1) 
462                         fdprint(consoles[x].p[1], string);
463         }
464 }
465
466 /*!
467  * write the string to the console, and all attached
468  * console clients
469  */
470 void ast_console_puts(const char *string)
471 {
472         fputs(string, stdout);
473         fflush(stdout);
474         ast_network_puts(string);
475 }
476
477 static void network_verboser(const char *s, int pos, int replace, int complete)
478         /* ARGUSED */
479 {
480         if (replace) {
481                 char *t = alloca(strlen(s) + 2);
482                 if (t) {
483                         sprintf(t, "\r%s", s);
484                         if (complete)
485                                 ast_network_puts(t);
486                 } else {
487                         ast_log(LOG_ERROR, "Out of memory\n");
488                         ast_network_puts(s);
489                 }
490         } else {
491                 if (complete)
492                         ast_network_puts(s);
493         }
494 }
495
496 static pthread_t lthread;
497
498 static void *netconsole(void *vconsole)
499 {
500         struct console *con = vconsole;
501         char hostname[MAXHOSTNAMELEN]="";
502         char tmp[512];
503         int res;
504         struct pollfd fds[2];
505         
506         if (gethostname(hostname, sizeof(hostname)-1))
507                 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
508         snprintf(tmp, sizeof(tmp), "%s/%d/%s\n", hostname, ast_mainpid, ASTERISK_VERSION);
509         fdprint(con->fd, tmp);
510         for(;;) {
511                 fds[0].fd = con->fd;
512                 fds[0].events = POLLIN;
513                 fds[0].revents = 0;
514                 fds[1].fd = con->p[0];
515                 fds[1].events = POLLIN;
516                 fds[1].revents = 0;
517
518                 res = poll(fds, 2, -1);
519                 if (res < 0) {
520                         if (errno != EINTR)
521                                 ast_log(LOG_WARNING, "poll returned < 0: %s\n", strerror(errno));
522                         continue;
523                 }
524                 if (fds[0].revents) {
525                         res = read(con->fd, tmp, sizeof(tmp));
526                         if (res < 1) {
527                                 break;
528                         }
529                         tmp[res] = 0;
530                         ast_cli_command(con->fd, tmp);
531                 }
532                 if (fds[1].revents) {
533                         res = read(con->p[0], tmp, sizeof(tmp));
534                         if (res < 1) {
535                                 ast_log(LOG_ERROR, "read returned %d\n", res);
536                                 break;
537                         }
538                         res = write(con->fd, tmp, res);
539                         if (res < 1)
540                                 break;
541                 }
542         }
543         if (option_verbose > 2) 
544                 ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection disconnected\n");
545         close(con->fd);
546         close(con->p[0]);
547         close(con->p[1]);
548         con->fd = -1;
549         
550         return NULL;
551 }
552
553 static void *listener(void *unused)
554 {
555         struct sockaddr_un sunaddr;
556         int s;
557         socklen_t len;
558         int x;
559         int flags;
560         struct pollfd fds[1];
561         pthread_attr_t attr;
562         pthread_attr_init(&attr);
563         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
564         for(;;) {
565                 if (ast_socket < 0)
566                         return NULL;
567                 fds[0].fd = ast_socket;
568                 fds[0].events= POLLIN;
569                 s = poll(fds, 1, -1);
570                 if (s < 0) {
571                         if (errno != EINTR)
572                                 ast_log(LOG_WARNING, "poll returned error: %s\n", strerror(errno));
573                         continue;
574                 }
575                 len = sizeof(sunaddr);
576                 s = accept(ast_socket, (struct sockaddr *)&sunaddr, &len);
577                 if (s < 0) {
578                         if (errno != EINTR)
579                                 ast_log(LOG_WARNING, "Accept returned %d: %s\n", s, strerror(errno));
580                 } else {
581                         for (x=0;x<AST_MAX_CONNECTS;x++) {
582                                 if (consoles[x].fd < 0) {
583                                         if (socketpair(AF_LOCAL, SOCK_STREAM, 0, consoles[x].p)) {
584                                                 ast_log(LOG_ERROR, "Unable to create pipe: %s\n", strerror(errno));
585                                                 consoles[x].fd = -1;
586                                                 fdprint(s, "Server failed to create pipe\n");
587                                                 close(s);
588                                                 break;
589                                         }
590                                         flags = fcntl(consoles[x].p[1], F_GETFL);
591                                         fcntl(consoles[x].p[1], F_SETFL, flags | O_NONBLOCK);
592                                         consoles[x].fd = s;
593                                         if (ast_pthread_create(&consoles[x].t, &attr, netconsole, &consoles[x])) {
594                                                 ast_log(LOG_ERROR, "Unable to spawn thread to handle connection: %s\n", strerror(errno));
595                                                 consoles[x].fd = -1;
596                                                 fdprint(s, "Server failed to spawn thread\n");
597                                                 close(s);
598                                         }
599                                         break;
600                                 }
601                         }
602                         if (x >= AST_MAX_CONNECTS) {
603                                 fdprint(s, "No more connections allowed\n");
604                                 ast_log(LOG_WARNING, "No more connections allowed\n");
605                                 close(s);
606                         } else if (consoles[x].fd > -1) {
607                                 if (option_verbose > 2) 
608                                         ast_verbose(VERBOSE_PREFIX_3 "Remote UNIX connection\n");
609                         }
610                 }
611         }
612         return NULL;
613 }
614
615 static int ast_makesocket(void)
616 {
617         struct sockaddr_un sunaddr;
618         int res;
619         int x;
620         uid_t uid = -1;
621         gid_t gid = -1;
622
623         for (x = 0; x < AST_MAX_CONNECTS; x++)  
624                 consoles[x].fd = -1;
625         unlink(ast_config_AST_SOCKET);
626         ast_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
627         if (ast_socket < 0) {
628                 ast_log(LOG_WARNING, "Unable to create control socket: %s\n", strerror(errno));
629                 return -1;
630         }               
631         memset(&sunaddr, 0, sizeof(sunaddr));
632         sunaddr.sun_family = AF_LOCAL;
633         ast_copy_string(sunaddr.sun_path, ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
634         res = bind(ast_socket, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
635         if (res) {
636                 ast_log(LOG_WARNING, "Unable to bind socket to %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
637                 close(ast_socket);
638                 ast_socket = -1;
639                 return -1;
640         }
641         res = listen(ast_socket, 2);
642         if (res < 0) {
643                 ast_log(LOG_WARNING, "Unable to listen on socket %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
644                 close(ast_socket);
645                 ast_socket = -1;
646                 return -1;
647         }
648         ast_register_verbose(network_verboser);
649         ast_pthread_create(&lthread, NULL, listener, NULL);
650
651         if (!ast_strlen_zero(ast_config_AST_CTL_OWNER)) {
652                 struct passwd *pw;
653                 if ((pw = getpwnam(ast_config_AST_CTL_OWNER)) == NULL) {
654                         ast_log(LOG_WARNING, "Unable to find uid of user %s\n", ast_config_AST_CTL_OWNER);
655                 } else {
656                         uid = pw->pw_uid;
657                 }
658         }
659                 
660         if (!ast_strlen_zero(ast_config_AST_CTL_GROUP)) {
661                 struct group *grp;
662                 if ((grp = getgrnam(ast_config_AST_CTL_GROUP)) == NULL) {
663                         ast_log(LOG_WARNING, "Unable to find gid of group %s\n", ast_config_AST_CTL_GROUP);
664                 } else {
665                         gid = grp->gr_gid;
666                 }
667         }
668
669         if (chown(ast_config_AST_SOCKET, uid, gid) < 0)
670                 ast_log(LOG_WARNING, "Unable to change ownership of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
671
672         if (!ast_strlen_zero(ast_config_AST_CTL_PERMISSIONS)) {
673                 int p1;
674                 mode_t p;
675                 sscanf(ast_config_AST_CTL_PERMISSIONS, "%o", &p1);
676                 p = p1;
677                 if ((chmod(ast_config_AST_SOCKET, p)) < 0)
678                         ast_log(LOG_WARNING, "Unable to change file permissions of %s: %s\n", ast_config_AST_SOCKET, strerror(errno));
679         }
680
681         return 0;
682 }
683
684 static int ast_tryconnect(void)
685 {
686         struct sockaddr_un sunaddr;
687         int res;
688         ast_consock = socket(PF_LOCAL, SOCK_STREAM, 0);
689         if (ast_consock < 0) {
690                 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno));
691                 return 0;
692         }
693         memset(&sunaddr, 0, sizeof(sunaddr));
694         sunaddr.sun_family = AF_LOCAL;
695         ast_copy_string(sunaddr.sun_path, (char *)ast_config_AST_SOCKET, sizeof(sunaddr.sun_path));
696         res = connect(ast_consock, (struct sockaddr *)&sunaddr, sizeof(sunaddr));
697         if (res) {
698                 close(ast_consock);
699                 ast_consock = -1;
700                 return 0;
701         } else
702                 return 1;
703 }
704
705 /*! Urgent handler
706  Called by soft_hangup to interrupt the poll, read, or other
707  system call.  We don't actually need to do anything though.  
708  Remember: Cannot EVER ast_log from within a signal handler 
709  SLD: seems to be some pthread activity relating to the printf anyway:
710  which is leading to a deadlock? 
711  */
712 static void urg_handler(int num)
713 {
714 #if 0
715         if (option_debug > 2) 
716                 printf("-- Asterisk Urgent handler\n");
717 #endif
718         signal(num, urg_handler);
719         return;
720 }
721
722 static void hup_handler(int num)
723 {
724         if (option_verbose > 1) 
725                 printf("Received HUP signal -- Reloading configs\n");
726         if (restartnow)
727                 execvp(_argv[0], _argv);
728         /* XXX This could deadlock XXX */
729         ast_module_reload(NULL);
730         signal(num, hup_handler);
731 }
732
733 static void child_handler(int sig)
734 {
735         /* Must not ever ast_log or ast_verbose within signal handler */
736         int n, status;
737
738         /*
739          * Reap all dead children -- not just one
740          */
741         for (n = 0; wait4(-1, &status, WNOHANG, NULL) > 0; n++)
742                 ;
743         if (n == 0 && option_debug)     
744                 printf("Huh?  Child handler, but nobody there?\n");
745         signal(sig, child_handler);
746 }
747
748 /*! Set an X-term or screen title */
749 static void set_title(char *text)
750 {
751         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
752                 fprintf(stdout, "\033]2;%s\007", text);
753 }
754
755 static void set_icon(char *text)
756 {
757         if (getenv("TERM") && strstr(getenv("TERM"), "xterm"))
758                 fprintf(stdout, "\033]1;%s\007", text);
759 }
760
761 /*! We set ourselves to a high priority, that we might pre-empt everything
762    else.  If your PBX has heavy activity on it, this is a good thing.  */
763 int ast_set_priority(int pri)
764 {
765         struct sched_param sched;
766         memset(&sched, 0, sizeof(sched));
767 #ifdef __linux__
768         if (pri) {  
769                 sched.sched_priority = 10;
770                 if (sched_setscheduler(0, SCHED_RR, &sched)) {
771                         ast_log(LOG_WARNING, "Unable to set high priority\n");
772                         return -1;
773                 } else
774                         if (option_verbose)
775                                 ast_verbose("Set to realtime thread\n");
776         } else {
777                 sched.sched_priority = 0;
778                 if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
779                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
780                         return -1;
781                 }
782         }
783 #else
784         if (pri) {
785                 if (setpriority(PRIO_PROCESS, 0, -10) == -1) {
786                         ast_log(LOG_WARNING, "Unable to set high priority\n");
787                         return -1;
788                 } else
789                         if (option_verbose)
790                                 ast_verbose("Set to high priority\n");
791         } else {
792                 if (setpriority(PRIO_PROCESS, 0, 0) == -1) {
793                         ast_log(LOG_WARNING, "Unable to set normal priority\n");
794                         return -1;
795                 }
796         }
797 #endif
798         return 0;
799 }
800
801 static void ast_run_atexits(void)
802 {
803         struct ast_atexit *ae;
804         ast_mutex_lock(&atexitslock);
805         ae = atexits;
806         while(ae) {
807                 if (ae->func) 
808                         ae->func();
809                 ae = ae->next;
810         }
811         ast_mutex_unlock(&atexitslock);
812 }
813
814 static void quit_handler(int num, int nice, int safeshutdown, int restart)
815 {
816         char filename[80] = "";
817         time_t s,e;
818         int x;
819         /* Try to get as many CDRs as possible submitted to the backend engines (if in batch mode) */
820         ast_cdr_engine_term();
821         if (safeshutdown) {
822                 shuttingdown = 1;
823                 if (!nice) {
824                         /* Begin shutdown routine, hanging up active channels */
825                         ast_begin_shutdown(1);
826                         if (option_verbose && ast_opt_console)
827                                 ast_verbose("Beginning asterisk %s....\n", restart ? "restart" : "shutdown");
828                         time(&s);
829                         for(;;) {
830                                 time(&e);
831                                 /* Wait up to 15 seconds for all channels to go away */
832                                 if ((e - s) > 15)
833                                         break;
834                                 if (!ast_active_channels())
835                                         break;
836                                 if (!shuttingdown)
837                                         break;
838                                 /* Sleep 1/10 of a second */
839                                 usleep(100000);
840                         }
841                 } else {
842                         if (nice < 2)
843                                 ast_begin_shutdown(0);
844                         if (option_verbose && ast_opt_console)
845                                 ast_verbose("Waiting for inactivity to perform %s...\n", restart ? "restart" : "halt");
846                         for(;;) {
847                                 if (!ast_active_channels())
848                                         break;
849                                 if (!shuttingdown)
850                                         break;
851                                 sleep(1);
852                         }
853                 }
854
855                 if (!shuttingdown) {
856                         if (option_verbose && ast_opt_console)
857                                 ast_verbose("Asterisk %s cancelled.\n", restart ? "restart" : "shutdown");
858                         return;
859                 }
860         }
861         if (ast_opt_console || ast_opt_remote) {
862                 if (getenv("HOME")) 
863                         snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
864                 if (!ast_strlen_zero(filename))
865                         ast_el_write_history(filename);
866                 if (el != NULL)
867                         el_end(el);
868                 if (el_hist != NULL)
869                         history_end(el_hist);
870         }
871         if (option_verbose)
872                 ast_verbose("Executing last minute cleanups\n");
873         ast_run_atexits();
874         /* Called on exit */
875         if (option_verbose && ast_opt_console)
876                 ast_verbose("Asterisk %s ending (%d).\n", ast_active_channels() ? "uncleanly" : "cleanly", num);
877         else if (option_debug)
878                 ast_log(LOG_DEBUG, "Asterisk ending (%d).\n", num);
879         manager_event(EVENT_FLAG_SYSTEM, "Shutdown", "Shutdown: %s\r\nRestart: %s\r\n", ast_active_channels() ? "Uncleanly" : "Cleanly", restart ? "True" : "False");
880         if (ast_socket > -1) {
881                 close(ast_socket);
882                 ast_socket = -1;
883         }
884         if (ast_consock > -1)
885                 close(ast_consock);
886         if (ast_socket > -1)
887                 unlink(ast_config_AST_SOCKET);
888         if (!ast_opt_remote)
889                 unlink(ast_config_AST_PID);
890         printf(term_quit());
891         if (restart) {
892                 if (option_verbose || ast_opt_console)
893                         ast_verbose("Preparing for Asterisk restart...\n");
894                 /* Mark all FD's for closing on exec */
895                 for (x=3;x<32768;x++) {
896                         fcntl(x, F_SETFD, FD_CLOEXEC);
897                 }
898                 if (option_verbose || ast_opt_console)
899                         ast_verbose("Restarting Asterisk NOW...\n");
900                 restartnow = 1;
901
902                 /* close logger */
903                 close_logger();
904
905                 /* If there is a consolethread running send it a SIGHUP 
906                    so it can execvp, otherwise we can do it ourselves */
907                 if ((consolethread != AST_PTHREADT_NULL) && (consolethread != pthread_self())) {
908                         pthread_kill(consolethread, SIGHUP);
909                         /* Give the signal handler some time to complete */
910                         sleep(2);
911                 } else
912                         execvp(_argv[0], _argv);
913         
914         } else {
915                 /* close logger */
916                 close_logger();
917         }
918         exit(0);
919 }
920
921 static void __quit_handler(int num)
922 {
923         quit_handler(num, 0, 1, 0);
924 }
925
926 static const char *fix_header(char *outbuf, int maxout, const char *s, char *cmp)
927 {
928         const char *c;
929         if (!strncmp(s, cmp, strlen(cmp))) {
930                 c = s + strlen(cmp);
931                 term_color(outbuf, cmp, COLOR_GRAY, 0, maxout);
932                 return c;
933         }
934         return NULL;
935 }
936
937 static void console_verboser(const char *s, int pos, int replace, int complete)
938 {
939         char tmp[80];
940         const char *c=NULL;
941         /* Return to the beginning of the line */
942         if (!pos) {
943                 fprintf(stdout, "\r");
944                 if ((c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_4)) ||
945                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_3)) ||
946                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_2)) ||
947                         (c = fix_header(tmp, sizeof(tmp), s, VERBOSE_PREFIX_1)))
948                         fputs(tmp, stdout);
949         }
950         if (c)
951                 fputs(c + pos,stdout);
952         else
953                 fputs(s + pos,stdout);
954         fflush(stdout);
955         if (complete) {
956                 /* Wake up a poll()ing console */
957                 if (ast_opt_console && consolethread != AST_PTHREADT_NULL)
958                         pthread_kill(consolethread, SIGURG);
959         }
960 }
961
962 static int ast_all_zeros(char *s)
963 {
964         while(*s) {
965                 if (*s > 32)
966                         return 0;
967                 s++;  
968         }
969         return 1;
970 }
971
972 static void consolehandler(char *s)
973 {
974         printf(term_end());
975         fflush(stdout);
976         /* Called when readline data is available */
977         if (s && !ast_all_zeros(s))
978                 ast_el_add_history(s);
979         /* Give the console access to the shell */
980         if (s) {
981                 /* The real handler for bang */
982                 if (s[0] == '!') {
983                         if (s[1])
984                                 ast_safe_system(s+1);
985                         else
986                                 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
987                 } else 
988                 ast_cli_command(STDOUT_FILENO, s);
989         } else
990                 fprintf(stdout, "\nUse \"quit\" to exit\n");
991 }
992
993 static int remoteconsolehandler(char *s)
994 {
995         int ret = 0;
996         /* Called when readline data is available */
997         if (s && !ast_all_zeros(s))
998                 ast_el_add_history(s);
999         /* Give the console access to the shell */
1000         if (s) {
1001                 /* The real handler for bang */
1002                 if (s[0] == '!') {
1003                         if (s[1])
1004                                 ast_safe_system(s+1);
1005                         else
1006                                 ast_safe_system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
1007                         ret = 1;
1008                 }
1009                 if ((strncasecmp(s, "quit", 4) == 0 || strncasecmp(s, "exit", 4) == 0) &&
1010                     (s[4] == '\0' || isspace(s[4]))) {
1011                         quit_handler(0, 0, 0, 0);
1012                         ret = 1;
1013                 }
1014         } else
1015                 fprintf(stdout, "\nUse \"quit\" to exit\n");
1016
1017         return ret;
1018 }
1019
1020 static char abort_halt_help[] = 
1021 "Usage: abort shutdown\n"
1022 "       Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
1023 "       call operations.\n";
1024
1025 static char shutdown_now_help[] = 
1026 "Usage: stop now\n"
1027 "       Shuts down a running Asterisk immediately, hanging up all active calls .\n";
1028
1029 static char shutdown_gracefully_help[] = 
1030 "Usage: stop gracefully\n"
1031 "       Causes Asterisk to not accept new calls, and exit when all\n"
1032 "       active calls have terminated normally.\n";
1033
1034 static char shutdown_when_convenient_help[] = 
1035 "Usage: stop when convenient\n"
1036 "       Causes Asterisk to perform a shutdown when all active calls have ended.\n";
1037
1038 static char restart_now_help[] = 
1039 "Usage: restart now\n"
1040 "       Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
1041 "       restart.\n";
1042
1043 static char restart_gracefully_help[] = 
1044 "Usage: restart gracefully\n"
1045 "       Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
1046 "       restart when all active calls have ended.\n";
1047
1048 static char restart_when_convenient_help[] = 
1049 "Usage: restart when convenient\n"
1050 "       Causes Asterisk to perform a cold restart when all active calls have ended.\n";
1051
1052 static char bang_help[] =
1053 "Usage: !<command>\n"
1054 "       Executes a given shell command\n";
1055
1056 static char show_warranty_help[] =
1057 "Usage: show warranty\n"
1058 "       Shows the warranty (if any) for this copy of Asterisk.\n";
1059
1060 static char show_license_help[] =
1061 "Usage: show license\n"
1062 "       Shows the license(s) for this copy of Asterisk.\n";
1063
1064 #if 0
1065 static int handle_quit(int fd, int argc, char *argv[])
1066 {
1067         if (argc != 1)
1068                 return RESULT_SHOWUSAGE;
1069         quit_handler(0, 0, 1, 0);
1070         return RESULT_SUCCESS;
1071 }
1072 #endif
1073
1074 static int handle_shutdown_now(int fd, int argc, char *argv[])
1075 {
1076         if (argc != 2)
1077                 return RESULT_SHOWUSAGE;
1078         quit_handler(0, 0 /* Not nice */, 1 /* safely */, 0 /* not restart */);
1079         return RESULT_SUCCESS;
1080 }
1081
1082 static int handle_shutdown_gracefully(int fd, int argc, char *argv[])
1083 {
1084         if (argc != 2)
1085                 return RESULT_SHOWUSAGE;
1086         quit_handler(0, 1 /* nicely */, 1 /* safely */, 0 /* no restart */);
1087         return RESULT_SUCCESS;
1088 }
1089
1090 static int handle_shutdown_when_convenient(int fd, int argc, char *argv[])
1091 {
1092         if (argc != 3)
1093                 return RESULT_SHOWUSAGE;
1094         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 0 /* don't restart */);
1095         return RESULT_SUCCESS;
1096 }
1097
1098 static int handle_restart_now(int fd, int argc, char *argv[])
1099 {
1100         if (argc != 2)
1101                 return RESULT_SHOWUSAGE;
1102         quit_handler(0, 0 /* not nicely */, 1 /* safely */, 1 /* restart */);
1103         return RESULT_SUCCESS;
1104 }
1105
1106 static int handle_restart_gracefully(int fd, int argc, char *argv[])
1107 {
1108         if (argc != 2)
1109                 return RESULT_SHOWUSAGE;
1110         quit_handler(0, 1 /* nicely */, 1 /* safely */, 1 /* restart */);
1111         return RESULT_SUCCESS;
1112 }
1113
1114 static int handle_restart_when_convenient(int fd, int argc, char *argv[])
1115 {
1116         if (argc != 3)
1117                 return RESULT_SHOWUSAGE;
1118         quit_handler(0, 2 /* really nicely */, 1 /* safely */, 1 /* restart */);
1119         return RESULT_SUCCESS;
1120 }
1121
1122 static int handle_abort_halt(int fd, int argc, char *argv[])
1123 {
1124         if (argc != 2)
1125                 return RESULT_SHOWUSAGE;
1126         ast_cancel_shutdown();
1127         shuttingdown = 0;
1128         return RESULT_SUCCESS;
1129 }
1130
1131 static int handle_bang(int fd, int argc, char *argv[])
1132 {
1133         return RESULT_SUCCESS;
1134 }
1135 static const char *warranty_lines[] = {
1136         "\n",
1137         "                           NO WARRANTY\n",
1138         "\n",
1139         "BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\n",
1140         "FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\n",
1141         "OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\n",
1142         "PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\n",
1143         "OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n",
1144         "MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\n",
1145         "TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\n",
1146         "PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\n",
1147         "REPAIR OR CORRECTION.\n",
1148         "\n",
1149         "IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n",
1150         "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\n",
1151         "REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\n",
1152         "INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\n",
1153         "OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n",
1154         "TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n",
1155         "YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n",
1156         "PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n",
1157         "POSSIBILITY OF SUCH DAMAGES.\n",
1158 };
1159
1160 static int show_warranty(int fd, int argc, char *argv[])
1161 {
1162         int x;
1163
1164         for (x = 0; x < sizeof(warranty_lines) / sizeof(warranty_lines[0]); x++)
1165                 ast_cli(fd, (char *) warranty_lines[x]);
1166
1167         return RESULT_SUCCESS;
1168 }
1169
1170 static const char *license_lines[] = {
1171         "\n",
1172         "This program is free software; you can redistribute it and/or modify\n",
1173         "it under the terms of the GNU General Public License version 2 as\n",
1174         "published by the Free Software Foundation.\n",
1175         "\n",
1176         "This program also contains components licensed under other licenses.\n",
1177         "They include:\n",
1178         "\n",
1179         "This program is distributed in the hope that it will be useful,\n",
1180         "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
1181         "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n",
1182         "GNU General Public License for more details.\n",
1183         "\n",
1184         "You should have received a copy of the GNU General Public License\n",
1185         "along with this program; if not, write to the Free Software\n",
1186         "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n",
1187 };
1188
1189 static int show_license(int fd, int argc, char *argv[])
1190 {
1191         int x;
1192
1193         for (x = 0; x < sizeof(license_lines) / sizeof(license_lines[0]); x++)
1194                 ast_cli(fd, (char *) license_lines[x]);
1195
1196         return RESULT_SUCCESS;
1197 }
1198
1199 #define ASTERISK_PROMPT "*CLI> "
1200
1201 #define ASTERISK_PROMPT2 "%s*CLI> "
1202
1203 static struct ast_cli_entry core_cli[] = {
1204         { { "abort", "halt", NULL }, handle_abort_halt,
1205           "Cancel a running halt", abort_halt_help },
1206         { { "stop", "now", NULL }, handle_shutdown_now,
1207           "Shut down Asterisk immediately", shutdown_now_help },
1208         { { "stop", "gracefully", NULL }, handle_shutdown_gracefully,
1209           "Gracefully shut down Asterisk", shutdown_gracefully_help },
1210         { { "stop", "when","convenient", NULL }, handle_shutdown_when_convenient,
1211           "Shut down Asterisk at empty call volume", shutdown_when_convenient_help },
1212         { { "restart", "now", NULL }, handle_restart_now,
1213           "Restart Asterisk immediately", restart_now_help },
1214         { { "restart", "gracefully", NULL }, handle_restart_gracefully,
1215           "Restart Asterisk gracefully", restart_gracefully_help },
1216         { { "restart", "when", "convenient", NULL }, handle_restart_when_convenient,
1217           "Restart Asterisk at empty call volume", restart_when_convenient_help },
1218         { { "show", "warranty", NULL }, show_warranty,
1219           "Show the warranty (if any) for this copy of Asterisk", show_warranty_help },
1220         { { "show", "license", NULL }, show_license,
1221           "Show the license(s) for this copy of Asterisk", show_license_help },
1222         { { "!", NULL }, handle_bang,
1223           "Execute a shell command", bang_help },
1224 #if !defined(LOW_MEMORY)
1225         { { "show", "version", "files", NULL }, handle_show_version_files,
1226           "Show versions of files used to build Asterisk", show_version_files_help, complete_show_version_files },
1227 #endif /* ! LOW_MEMORY */
1228 };
1229
1230 static int ast_el_read_char(EditLine *el, char *cp)
1231 {
1232         int num_read=0;
1233         int lastpos=0;
1234         struct pollfd fds[2];
1235         int res;
1236         int max;
1237         char buf[512];
1238
1239         for (;;) {
1240                 max = 1;
1241                 fds[0].fd = ast_consock;
1242                 fds[0].events = POLLIN;
1243                 if (!ast_opt_exec) {
1244                         fds[1].fd = STDIN_FILENO;
1245                         fds[1].events = POLLIN;
1246                         max++;
1247                 }
1248                 res = poll(fds, max, -1);
1249                 if (res < 0) {
1250                         if (errno == EINTR)
1251                                 continue;
1252                         ast_log(LOG_ERROR, "poll failed: %s\n", strerror(errno));
1253                         break;
1254                 }
1255
1256                 if (!ast_opt_exec && fds[1].revents) {
1257                         num_read = read(STDIN_FILENO, cp, 1);
1258                         if (num_read < 1) {
1259                                 break;
1260                         } else 
1261                                 return (num_read);
1262                 }
1263                 if (fds[0].revents) {
1264                         res = read(ast_consock, buf, sizeof(buf) - 1);
1265                         /* if the remote side disappears exit */
1266                         if (res < 1) {
1267                                 fprintf(stderr, "\nDisconnected from Asterisk server\n");
1268                                 if (!ast_opt_reconnect) {
1269                                         quit_handler(0, 0, 0, 0);
1270                                 } else {
1271                                         int tries;
1272                                         int reconnects_per_second = 20;
1273                                         fprintf(stderr, "Attempting to reconnect for 30 seconds\n");
1274                                         for (tries=0;tries<30 * reconnects_per_second;tries++) {
1275                                                 if (ast_tryconnect()) {
1276                                                         fprintf(stderr, "Reconnect succeeded after %.3f seconds\n", 1.0 / reconnects_per_second * tries);
1277                                                         printf(term_quit());
1278                                                         WELCOME_MESSAGE;
1279                                                         break;
1280                                                 } else {
1281                                                         usleep(1000000 / reconnects_per_second);
1282                                                 }
1283                                         }
1284                                         if (tries >= 30 * reconnects_per_second) {
1285                                                 fprintf(stderr, "Failed to reconnect for 30 seconds.  Quitting.\n");
1286                                                 quit_handler(0, 0, 0, 0);
1287                                         }
1288                                 }
1289                         }
1290
1291                         buf[res] = '\0';
1292
1293                         if (!ast_opt_exec && !lastpos)
1294                                 write(STDOUT_FILENO, "\r", 1);
1295                         write(STDOUT_FILENO, buf, res);
1296                         if ((buf[res-1] == '\n') || (buf[res-2] == '\n')) {
1297                                 *cp = CC_REFRESH;
1298                                 return(1);
1299                         } else {
1300                                 lastpos = 1;
1301                         }
1302                 }
1303         }
1304
1305         *cp = '\0';
1306         return (0);
1307 }
1308
1309 static char *cli_prompt(EditLine *el)
1310 {
1311         static char prompt[200];
1312         char *pfmt;
1313         int color_used=0;
1314         char term_code[20];
1315
1316         if ((pfmt = getenv("ASTERISK_PROMPT"))) {
1317                 char *t = pfmt, *p = prompt;
1318                 memset(prompt, 0, sizeof(prompt));
1319                 while (*t != '\0' && *p < sizeof(prompt)) {
1320                         if (*t == '%') {
1321                                 char hostname[MAXHOSTNAMELEN]="";
1322                                 int i;
1323                                 time_t ts;
1324                                 struct tm tm;
1325 #ifdef linux
1326                                 FILE *LOADAVG;
1327 #endif
1328                                 int fgcolor = COLOR_WHITE, bgcolor = COLOR_BLACK;
1329
1330                                 t++;
1331                                 switch (*t) {
1332                                         case 'C': /* color */
1333                                                 t++;
1334                                                 if (sscanf(t, "%d;%d%n", &fgcolor, &bgcolor, &i) == 2) {
1335                                                         strncat(p, term_color_code(term_code, fgcolor, bgcolor, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1336                                                         t += i - 1;
1337                                                 } else if (sscanf(t, "%d%n", &fgcolor, &i) == 1) {
1338                                                         strncat(p, term_color_code(term_code, fgcolor, 0, sizeof(term_code)),sizeof(prompt) - strlen(prompt) - 1);
1339                                                         t += i - 1;
1340                                                 }
1341
1342                                                 /* If the color has been reset correctly, then there's no need to reset it later */
1343                                                 if ((fgcolor == COLOR_WHITE) && (bgcolor == COLOR_BLACK)) {
1344                                                         color_used = 0;
1345                                                 } else {
1346                                                         color_used = 1;
1347                                                 }
1348                                                 break;
1349                                         case 'd': /* date */
1350                                                 memset(&tm, 0, sizeof(struct tm));
1351                                                 time(&ts);
1352                                                 if (localtime_r(&ts, &tm)) {
1353                                                         strftime(p, sizeof(prompt) - strlen(prompt), "%Y-%m-%d", &tm);
1354                                                 }
1355                                                 break;
1356                                         case 'h': /* hostname */
1357                                                 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1358                                                         strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1359                                                 } else {
1360                                                         strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1361                                                 }
1362                                                 break;
1363                                         case 'H': /* short hostname */
1364                                                 if (!gethostname(hostname, sizeof(hostname) - 1)) {
1365                                                         for (i=0;i<sizeof(hostname);i++) {
1366                                                                 if (hostname[i] == '.') {
1367                                                                         hostname[i] = '\0';
1368                                                                         break;
1369                                                                 }
1370                                                         }
1371                                                         strncat(p, hostname, sizeof(prompt) - strlen(prompt) - 1);
1372                                                 } else {
1373                                                         strncat(p, "localhost", sizeof(prompt) - strlen(prompt) - 1);
1374                                                 }
1375                                                 break;
1376 #ifdef linux
1377                                         case 'l': /* load avg */
1378                                                 t++;
1379                                                 if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
1380                                                         float avg1, avg2, avg3;
1381                                                         int actproc, totproc, npid, which;
1382                                                         fscanf(LOADAVG, "%f %f %f %d/%d %d",
1383                                                                 &avg1, &avg2, &avg3, &actproc, &totproc, &npid);
1384                                                         if (sscanf(t, "%d", &which) == 1) {
1385                                                                 switch (which) {
1386                                                                         case 1:
1387                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg1);
1388                                                                                 break;
1389                                                                         case 2:
1390                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg2);
1391                                                                                 break;
1392                                                                         case 3:
1393                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%.2f", avg3);
1394                                                                                 break;
1395                                                                         case 4:
1396                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%d/%d", actproc, totproc);
1397                                                                                 break;
1398                                                                         case 5:
1399                                                                                 snprintf(p, sizeof(prompt) - strlen(prompt), "%d", npid);
1400                                                                                 break;
1401                                                                 }
1402                                                         }
1403                                                 }
1404                                                 break;
1405 #endif
1406                                         case 't': /* time */
1407                                                 memset(&tm, 0, sizeof(struct tm));
1408                                                 time(&ts);
1409                                                 if (localtime_r(&ts, &tm)) {
1410                                                         strftime(p, sizeof(prompt) - strlen(prompt), "%H:%M:%S", &tm);
1411                                                 }
1412                                                 break;
1413                                         case '#': /* process console or remote? */
1414                                                 if (!ast_opt_remote) {
1415                                                         strncat(p, "#", sizeof(prompt) - strlen(prompt) - 1);
1416                                                 } else {
1417                                                         strncat(p, ">", sizeof(prompt) - strlen(prompt) - 1);
1418                                                 }
1419                                                 break;
1420                                         case '%': /* literal % */
1421                                                 strncat(p, "%", sizeof(prompt) - strlen(prompt) - 1);
1422                                                 break;
1423                                         case '\0': /* % is last character - prevent bug */
1424                                                 t--;
1425                                                 break;
1426                                 }
1427                                 while (*p != '\0') {
1428                                         p++;
1429                                 }
1430                                 t++;
1431                         } else {
1432                                 *p = *t;
1433                                 p++;
1434                                 t++;
1435                         }
1436                 }
1437                 if (color_used) {
1438                         /* Force colors back to normal at end */
1439                         term_color_code(term_code, COLOR_WHITE, COLOR_BLACK, sizeof(term_code));
1440                         if (strlen(term_code) > sizeof(prompt) - strlen(prompt)) {
1441                                 strncat(prompt + sizeof(prompt) - strlen(term_code) - 1, term_code, strlen(term_code));
1442                         } else {
1443                                 strncat(p, term_code, sizeof(term_code));
1444                         }
1445                 }
1446         } else if (remotehostname)
1447                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT2, remotehostname);
1448         else
1449                 snprintf(prompt, sizeof(prompt), ASTERISK_PROMPT);
1450
1451         return(prompt); 
1452 }
1453
1454 static char **ast_el_strtoarr(char *buf)
1455 {
1456         char **match_list = NULL, *retstr;
1457         size_t match_list_len;
1458         int matches = 0;
1459
1460         match_list_len = 1;
1461         while ( (retstr = strsep(&buf, " ")) != NULL) {
1462
1463                 if (!strcmp(retstr, AST_CLI_COMPLETE_EOF))
1464                         break;
1465                 if (matches + 1 >= match_list_len) {
1466                         match_list_len <<= 1;
1467                         match_list = realloc(match_list, match_list_len * sizeof(char *));
1468                 }
1469
1470                 match_list[matches++] = strdup(retstr);
1471         }
1472
1473         if (!match_list)
1474                 return (char **) NULL;
1475
1476         if (matches>= match_list_len)
1477                 match_list = realloc(match_list, (match_list_len + 1) * sizeof(char *));
1478
1479         match_list[matches] = (char *) NULL;
1480
1481         return match_list;
1482 }
1483
1484 static int ast_el_sort_compare(const void *i1, const void *i2)
1485 {
1486         char *s1, *s2;
1487
1488         s1 = ((char **)i1)[0];
1489         s2 = ((char **)i2)[0];
1490
1491         return strcasecmp(s1, s2);
1492 }
1493
1494 static int ast_cli_display_match_list(char **matches, int len, int max)
1495 {
1496         int i, idx, limit, count;
1497         int screenwidth = 0;
1498         int numoutput = 0, numoutputline = 0;
1499
1500         screenwidth = ast_get_termcols(STDOUT_FILENO);
1501
1502         /* find out how many entries can be put on one line, with two spaces between strings */
1503         limit = screenwidth / (max + 2);
1504         if (limit == 0)
1505                 limit = 1;
1506
1507         /* how many lines of output */
1508         count = len / limit;
1509         if (count * limit < len)
1510                 count++;
1511
1512         idx = 1;
1513
1514         qsort(&matches[0], (size_t)(len), sizeof(char *), ast_el_sort_compare);
1515
1516         for (; count > 0; count--) {
1517                 numoutputline = 0;
1518                 for (i=0; i < limit && matches[idx]; i++, idx++) {
1519
1520                         /* Don't print dupes */
1521                         if ( (matches[idx+1] != NULL && strcmp(matches[idx], matches[idx+1]) == 0 ) ) {
1522                                 i--;
1523                                 free(matches[idx]);
1524                                 matches[idx] = NULL;
1525                                 continue;
1526                         }
1527
1528                         numoutput++;
1529                         numoutputline++;
1530                         fprintf(stdout, "%-*s  ", max, matches[idx]);
1531                         free(matches[idx]);
1532                         matches[idx] = NULL;
1533                 }
1534                 if (numoutputline > 0)
1535                         fprintf(stdout, "\n");
1536         }
1537
1538         return numoutput;
1539 }
1540
1541
1542 static char *cli_complete(EditLine *el, int ch)
1543 {
1544         int len=0;
1545         char *ptr;
1546         int nummatches = 0;
1547         char **matches;
1548         int retval = CC_ERROR;
1549         char buf[2048];
1550         int res;
1551
1552         LineInfo *lf = (LineInfo *)el_line(el);
1553
1554         *(char *)lf->cursor = '\0';
1555         ptr = (char *)lf->cursor;
1556         if (ptr) {
1557                 while (ptr > lf->buffer) {
1558                         if (isspace(*ptr)) {
1559                                 ptr++;
1560                                 break;
1561                         }
1562                         ptr--;
1563                 }
1564         }
1565
1566         len = lf->cursor - ptr;
1567
1568         if (ast_opt_remote) {
1569                 snprintf(buf, sizeof(buf),"_COMMAND NUMMATCHES \"%s\" \"%s\"", lf->buffer, ptr); 
1570                 fdprint(ast_consock, buf);
1571                 res = read(ast_consock, buf, sizeof(buf));
1572                 buf[res] = '\0';
1573                 nummatches = atoi(buf);
1574
1575                 if (nummatches > 0) {
1576                         char *mbuf;
1577                         int mlen = 0, maxmbuf = 2048;
1578                         /* Start with a 2048 byte buffer */
1579                         mbuf = malloc(maxmbuf);
1580                         if (!mbuf)
1581                                 return (char *)(CC_ERROR);
1582                         snprintf(buf, sizeof(buf),"_COMMAND MATCHESARRAY \"%s\" \"%s\"", lf->buffer, ptr); 
1583                         fdprint(ast_consock, buf);
1584                         res = 0;
1585                         mbuf[0] = '\0';
1586                         while (!strstr(mbuf, AST_CLI_COMPLETE_EOF) && res != -1) {
1587                                 if (mlen + 1024 > maxmbuf) {
1588                                         /* Every step increment buffer 1024 bytes */
1589                                         maxmbuf += 1024;
1590                                         mbuf = realloc(mbuf, maxmbuf);
1591                                         if (!mbuf)
1592                                                 return (char *)(CC_ERROR);
1593                                 }
1594                                 /* Only read 1024 bytes at a time */
1595                                 res = read(ast_consock, mbuf + mlen, 1024);
1596                                 if (res > 0)
1597                                         mlen += res;
1598                         }
1599                         mbuf[mlen] = '\0';
1600
1601                         matches = ast_el_strtoarr(mbuf);
1602                         free(mbuf);
1603                 } else
1604                         matches = (char **) NULL;
1605         } else {
1606                 char **p, *oldbuf=NULL;
1607                 nummatches = 0;
1608                 matches = ast_cli_completion_matches((char *)lf->buffer,ptr);
1609                 for (p = matches; p && *p; p++) {
1610                         if (!oldbuf || strcmp(*p,oldbuf))
1611                                 nummatches++;
1612                         oldbuf = *p;
1613                 }
1614         }
1615
1616         if (matches) {
1617                 int i;
1618                 int matches_num, maxlen, match_len;
1619
1620                 if (matches[0][0] != '\0') {
1621                         el_deletestr(el, (int) len);
1622                         el_insertstr(el, matches[0]);
1623                         retval = CC_REFRESH;
1624                 }
1625
1626                 if (nummatches == 1) {
1627                         /* Found an exact match */
1628                         el_insertstr(el, " ");
1629                         retval = CC_REFRESH;
1630                 } else {
1631                         /* Must be more than one match */
1632                         for (i=1, maxlen=0; matches[i]; i++) {
1633                                 match_len = strlen(matches[i]);
1634                                 if (match_len > maxlen)
1635                                         maxlen = match_len;
1636                         }
1637                         matches_num = i - 1;
1638                         if (matches_num >1) {
1639                                 fprintf(stdout, "\n");
1640                                 ast_cli_display_match_list(matches, nummatches, maxlen);
1641                                 retval = CC_REDISPLAY;
1642                         } else { 
1643                                 el_insertstr(el," ");
1644                                 retval = CC_REFRESH;
1645                         }
1646                 }
1647                 free(matches);
1648         }
1649
1650         return (char *)(long)retval;
1651 }
1652
1653 static int ast_el_initialize(void)
1654 {
1655         HistEvent ev;
1656         char *editor = getenv("AST_EDITOR");
1657
1658         if (el != NULL)
1659                 el_end(el);
1660         if (el_hist != NULL)
1661                 history_end(el_hist);
1662
1663         el = el_init("asterisk", stdin, stdout, stderr);
1664         el_set(el, EL_PROMPT, cli_prompt);
1665
1666         el_set(el, EL_EDITMODE, 1);             
1667         el_set(el, EL_EDITOR, editor ? editor : "emacs");               
1668         el_hist = history_init();
1669         if (!el || !el_hist)
1670                 return -1;
1671
1672         /* setup history with 100 entries */
1673         history(el_hist, &ev, H_SETSIZE, 100);
1674
1675         el_set(el, EL_HIST, history, el_hist);
1676
1677         el_set(el, EL_ADDFN, "ed-complete", "Complete argument", cli_complete);
1678         /* Bind <tab> to command completion */
1679         el_set(el, EL_BIND, "^I", "ed-complete", NULL);
1680         /* Bind ? to command completion */
1681         el_set(el, EL_BIND, "?", "ed-complete", NULL);
1682         /* Bind ^D to redisplay */
1683         el_set(el, EL_BIND, "^D", "ed-redisplay", NULL);
1684
1685         return 0;
1686 }
1687
1688 static int ast_el_add_history(char *buf)
1689 {
1690         HistEvent ev;
1691
1692         if (el_hist == NULL || el == NULL)
1693                 ast_el_initialize();
1694         if (strlen(buf) > 256)
1695                 return 0;
1696         return (history(el_hist, &ev, H_ENTER, buf));
1697 }
1698
1699 static int ast_el_write_history(char *filename)
1700 {
1701         HistEvent ev;
1702
1703         if (el_hist == NULL || el == NULL)
1704                 ast_el_initialize();
1705
1706         return (history(el_hist, &ev, H_SAVE, filename));
1707 }
1708
1709 static int ast_el_read_history(char *filename)
1710 {
1711         char buf[256];
1712         FILE *f;
1713         int ret = -1;
1714
1715         if (el_hist == NULL || el == NULL)
1716                 ast_el_initialize();
1717
1718         if ((f = fopen(filename, "r")) == NULL)
1719                 return ret;
1720
1721         while (!feof(f)) {
1722                 fgets(buf, sizeof(buf), f);
1723                 if (!strcmp(buf, "_HiStOrY_V2_\n"))
1724                         continue;
1725                 if (ast_all_zeros(buf))
1726                         continue;
1727                 if ((ret = ast_el_add_history(buf)) == -1)
1728                         break;
1729         }
1730         fclose(f);
1731
1732         return ret;
1733 }
1734
1735 static void ast_remotecontrol(char * data)
1736 {
1737         char buf[80];
1738         int res;
1739         char filename[80] = "";
1740         char *hostname;
1741         char *cpid;
1742         char *version;
1743         int pid;
1744         char tmp[80];
1745         char *stringp=NULL;
1746
1747         char *ebuf;
1748         int num = 0;
1749
1750         read(ast_consock, buf, sizeof(buf));
1751         if (data)
1752                 write(ast_consock, data, strlen(data) + 1);
1753         stringp=buf;
1754         hostname = strsep(&stringp, "/");
1755         cpid = strsep(&stringp, "/");
1756         version = strsep(&stringp, "\n");
1757         if (!version)
1758                 version = "<Version Unknown>";
1759         stringp=hostname;
1760         strsep(&stringp, ".");
1761         if (cpid)
1762                 pid = atoi(cpid);
1763         else
1764                 pid = -1;
1765         snprintf(tmp, sizeof(tmp), "set verbose atleast %d", option_verbose);
1766         fdprint(ast_consock, tmp);
1767         snprintf(tmp, sizeof(tmp), "set debug atleast %d", option_debug);
1768         fdprint(ast_consock, tmp);
1769         ast_verbose("Connected to Asterisk %s currently running on %s (pid = %d)\n", version, hostname, pid);
1770         remotehostname = hostname;
1771         if (getenv("HOME")) 
1772                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
1773         if (el_hist == NULL || el == NULL)
1774                 ast_el_initialize();
1775
1776         el_set(el, EL_GETCFN, ast_el_read_char);
1777
1778         if (!ast_strlen_zero(filename))
1779                 ast_el_read_history(filename);
1780
1781         if (ast_opt_exec && data) {  /* hack to print output then exit if asterisk -rx is used */
1782                 char tempchar;
1783                 struct pollfd fds[0];
1784                 fds[0].fd = ast_consock;
1785                 fds[0].events = POLLIN;
1786                 fds[0].revents = 0;
1787                 while(poll(fds, 1, 100) > 0) {
1788                         ast_el_read_char(el, &tempchar);
1789                 }
1790                 return;
1791         }
1792         for(;;) {
1793                 ebuf = (char *)el_gets(el, &num);
1794
1795                 if (!ast_strlen_zero(ebuf)) {
1796                         if (ebuf[strlen(ebuf)-1] == '\n')
1797                                 ebuf[strlen(ebuf)-1] = '\0';
1798                         if (!remoteconsolehandler(ebuf)) {
1799                                 res = write(ast_consock, ebuf, strlen(ebuf) + 1);
1800                                 if (res < 1) {
1801                                         ast_log(LOG_WARNING, "Unable to write: %s\n", strerror(errno));
1802                                         break;
1803                                 }
1804                         }
1805                 }
1806         }
1807         printf("\nDisconnected from Asterisk server\n");
1808 }
1809
1810 static int show_version(void)
1811 {
1812         printf("Asterisk " ASTERISK_VERSION "\n");
1813         return 0;
1814 }
1815
1816 static int show_cli_help(void) {
1817         printf("Asterisk " ASTERISK_VERSION ", Copyright (C) 1999 - 2005, Digium, Inc. and others.\n");
1818         printf("Usage: asterisk [OPTIONS]\n");
1819         printf("Valid Options:\n");
1820         printf("   -V              Display version number and exit\n");
1821         printf("   -C <configfile> Use an alternate configuration file\n");
1822         printf("   -G <group>      Run as a group other than the caller\n");
1823         printf("   -U <user>       Run as a user other than the caller\n");
1824         printf("   -c              Provide console CLI\n");
1825         printf("   -d              Enable extra debugging\n");
1826         printf("   -f              Do not fork\n");
1827         printf("   -g              Dump core in case of a crash\n");
1828         printf("   -h              This help screen\n");
1829         printf("   -i              Initialize crypto keys at startup\n");
1830         printf("   -n              Disable console colorization\n");
1831         printf("   -p              Run as pseudo-realtime thread\n");
1832         printf("   -q              Quiet mode (suppress output)\n");
1833         printf("   -r              Connect to Asterisk on this machine\n");
1834         printf("   -R              Connect to Asterisk, and attempt to reconnect if disconnected\n");
1835         printf("   -t              Record soundfiles in /var/tmp and move them where they belong after they are done.\n");
1836         printf("   -T              Display the time in [Mmm dd hh:mm:ss] format for each line of output to the CLI.\n");
1837         printf("   -v              Increase verbosity (multiple v's = more verbose)\n");
1838         printf("   -x <cmd>        Execute command <cmd> (only valid with -r)\n");
1839         printf("\n");
1840         return 0;
1841 }
1842
1843 static void ast_readconfig(void) {
1844         struct ast_config *cfg;
1845         struct ast_variable *v;
1846         char *config = AST_CONFIG_FILE;
1847
1848         if (ast_opt_override_config) {
1849                 cfg = ast_config_load(ast_config_AST_CONFIG_FILE);
1850                 if (!cfg)
1851                         ast_log(LOG_WARNING, "Unable to open specified master config file '%s', using built-in defaults\n", ast_config_AST_CONFIG_FILE);
1852         } else {
1853                 cfg = ast_config_load(config);
1854         }
1855
1856         /* init with buildtime config */
1857         ast_copy_string(ast_config_AST_CONFIG_DIR, AST_CONFIG_DIR, sizeof(ast_config_AST_CONFIG_DIR));
1858         ast_copy_string(ast_config_AST_SPOOL_DIR, AST_SPOOL_DIR, sizeof(ast_config_AST_SPOOL_DIR));
1859         ast_copy_string(ast_config_AST_MODULE_DIR, AST_MODULE_DIR, sizeof(ast_config_AST_VAR_DIR));
1860         snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", ast_config_AST_SPOOL_DIR);
1861         ast_copy_string(ast_config_AST_VAR_DIR, AST_VAR_DIR, sizeof(ast_config_AST_VAR_DIR));
1862         ast_copy_string(ast_config_AST_LOG_DIR, AST_LOG_DIR, sizeof(ast_config_AST_LOG_DIR));
1863         ast_copy_string(ast_config_AST_AGI_DIR, AST_AGI_DIR, sizeof(ast_config_AST_AGI_DIR));
1864         ast_copy_string(ast_config_AST_DB, AST_DB, sizeof(ast_config_AST_DB));
1865         ast_copy_string(ast_config_AST_KEY_DIR, AST_KEY_DIR, sizeof(ast_config_AST_KEY_DIR));
1866         ast_copy_string(ast_config_AST_PID, AST_PID, sizeof(ast_config_AST_PID));
1867         ast_copy_string(ast_config_AST_SOCKET, AST_SOCKET, sizeof(ast_config_AST_SOCKET));
1868         ast_copy_string(ast_config_AST_RUN_DIR, AST_RUN_DIR, sizeof(ast_config_AST_RUN_DIR));
1869
1870         /* no asterisk.conf? no problem, use buildtime config! */
1871         if (!cfg) {
1872                 return;
1873         }
1874         v = ast_variable_browse(cfg, "files");
1875         while (v) {
1876                 if (!strcasecmp(v->name, "astctlpermissions")) {
1877                         ast_copy_string(ast_config_AST_CTL_PERMISSIONS, v->value, sizeof(ast_config_AST_CTL_PERMISSIONS));
1878                 } else if (!strcasecmp(v->name, "astctlowner")) {
1879                         ast_copy_string(ast_config_AST_CTL_OWNER, v->value, sizeof(ast_config_AST_CTL_OWNER));
1880                 } else if (!strcasecmp(v->name, "astctlgroup")) {
1881                         ast_copy_string(ast_config_AST_CTL_GROUP, v->value, sizeof(ast_config_AST_CTL_GROUP));
1882                 } else if (!strcasecmp(v->name, "astctl")) {
1883                         ast_copy_string(ast_config_AST_CTL, v->value, sizeof(ast_config_AST_CTL));
1884                 }
1885                 v = v->next;
1886         }
1887         v = ast_variable_browse(cfg, "directories");
1888         while(v) {
1889                 if (!strcasecmp(v->name, "astetcdir")) {
1890                         ast_copy_string(ast_config_AST_CONFIG_DIR, v->value, sizeof(ast_config_AST_CONFIG_DIR));
1891                 } else if (!strcasecmp(v->name, "astspooldir")) {
1892                         ast_copy_string(ast_config_AST_SPOOL_DIR, v->value, sizeof(ast_config_AST_SPOOL_DIR));
1893                         snprintf(ast_config_AST_MONITOR_DIR, sizeof(ast_config_AST_MONITOR_DIR) - 1, "%s/monitor", v->value);
1894                 } else if (!strcasecmp(v->name, "astvarlibdir")) {
1895                         ast_copy_string(ast_config_AST_VAR_DIR, v->value, sizeof(ast_config_AST_VAR_DIR));
1896                         snprintf(ast_config_AST_DB, sizeof(ast_config_AST_DB), "%s/%s", v->value, "astdb");    
1897                 } else if (!strcasecmp(v->name, "astlogdir")) {
1898                         ast_copy_string(ast_config_AST_LOG_DIR, v->value, sizeof(ast_config_AST_LOG_DIR));
1899                 } else if (!strcasecmp(v->name, "astagidir")) {
1900                         ast_copy_string(ast_config_AST_AGI_DIR, v->value, sizeof(ast_config_AST_AGI_DIR));
1901                 } else if (!strcasecmp(v->name, "astrundir")) {
1902                         snprintf(ast_config_AST_PID, sizeof(ast_config_AST_PID), "%s/%s", v->value, "asterisk.pid");
1903                         snprintf(ast_config_AST_SOCKET, sizeof(ast_config_AST_SOCKET), "%s/%s", v->value, ast_config_AST_CTL);
1904                         ast_copy_string(ast_config_AST_RUN_DIR, v->value, sizeof(ast_config_AST_RUN_DIR));
1905                 } else if (!strcasecmp(v->name, "astmoddir")) {
1906                         ast_copy_string(ast_config_AST_MODULE_DIR, v->value, sizeof(ast_config_AST_MODULE_DIR));
1907                 }
1908                 v = v->next;
1909         }
1910         v = ast_variable_browse(cfg, "options");
1911         while(v) {
1912                 /* verbose level (-v at startup) */
1913                 if (!strcasecmp(v->name, "verbose")) {
1914                         option_verbose = atoi(v->value);
1915                 /* whether or not to force timestamping. (-T at startup) */
1916                 } else if (!strcasecmp(v->name, "timestamp")) {
1917                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TIMESTAMP);
1918                 /* whether or not to support #exec in config files */
1919                 } else if (!strcasecmp(v->name, "execincludes")) {
1920                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_EXEC_INCLUDES);
1921                 /* debug level (-d at startup) */
1922                 } else if (!strcasecmp(v->name, "debug")) {
1923                         option_debug = 0;
1924                         if (sscanf(v->value, "%d", &option_debug) != 1) {
1925                                 option_debug = ast_true(v->value);
1926                         }
1927                 /* Disable forking (-f at startup) */
1928                 } else if (!strcasecmp(v->name, "nofork")) {
1929                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_FORK);
1930                 /* Run quietly (-q at startup ) */
1931                 } else if (!strcasecmp(v->name, "quiet")) {
1932                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_QUIET);
1933                 /* Run as console (-c at startup, implies nofork) */
1934                 } else if (!strcasecmp(v->name, "console")) {
1935                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CONSOLE);
1936                 /* Run with highg priority if the O/S permits (-p at startup) */
1937                 } else if (!strcasecmp(v->name, "highpriority")) {
1938                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_HIGH_PRIORITY);
1939                 /* Initialize RSA auth keys (IAX2) (-i at startup) */
1940                 } else if (!strcasecmp(v->name, "initcrypto")) {
1941                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_INIT_KEYS);
1942                 /* Disable ANSI colors for console (-c at startup) */
1943                 } else if (!strcasecmp(v->name, "nocolor")) {
1944                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_NO_COLOR);
1945                 /* Disable some usage warnings for picky people :p */
1946                 } else if (!strcasecmp(v->name, "dontwarn")) {
1947                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DONT_WARN);
1948                 /* Dump core in case of crash (-g) */
1949                 } else if (!strcasecmp(v->name, "dumpcore")) {
1950                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_DUMP_CORE);
1951                 /* Cache recorded sound files to another directory during recording */
1952                 } else if (!strcasecmp(v->name, "cache_record_files")) {
1953                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_CACHE_RECORD_FILES);
1954                 /* Specify cache directory */
1955                 }  else if (!strcasecmp(v->name, "record_cache_dir")) {
1956                         ast_copy_string(record_cache_dir, v->value, AST_CACHE_DIR_LEN);
1957                 /* Build transcode paths via SLINEAR, instead of directly */
1958                 } else if (!strcasecmp(v->name, "transcode_via_sln")) {
1959                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSCODE_VIA_SLIN);
1960                 /* Transmit SLINEAR silence while a channel is being recorded */
1961                 } else if (!strcasecmp(v->name, "transmit_silence_during_record")) {
1962                         ast_set2_flag(&ast_options, ast_true(v->value), AST_OPT_FLAG_TRANSMIT_SILENCE);
1963                 } else if (!strcasecmp(v->name, "maxcalls")) {
1964                         if ((sscanf(v->value, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0)) {
1965                                 option_maxcalls = 0;
1966                         }
1967                 } else if (!strcasecmp(v->name, "maxload")) {
1968                         double test[1];
1969
1970                         if (getloadavg(test, 1) == -1) {
1971                                 ast_log(LOG_ERROR, "Cannot obtain load average on this system. 'maxload' option disabled.\n");
1972                                 option_maxload = 0.0;
1973                         } else if ((sscanf(v->value, "%lf", &option_maxload) != 1) || (option_maxload < 0.0)) {
1974                                 option_maxload = 0.0;
1975                         }
1976                 /* What user to run as */
1977                 } else if (!strcasecmp(v->name, "runuser")) {
1978                         ast_copy_string(ast_config_AST_RUN_USER, v->value, sizeof(ast_config_AST_RUN_USER));
1979                 /* What group to run as */
1980                 } else if (!strcasecmp(v->name, "rungroup")) {
1981                         ast_copy_string(ast_config_AST_RUN_GROUP, v->value, sizeof(ast_config_AST_RUN_GROUP));
1982                 }
1983                 v = v->next;
1984         }
1985         ast_config_destroy(cfg);
1986 }
1987
1988 int main(int argc, char *argv[])
1989 {
1990         int c;
1991         char filename[80] = "";
1992         char hostname[MAXHOSTNAMELEN]="";
1993         char tmp[80];
1994         char * xarg = NULL;
1995         int x;
1996         FILE *f;
1997         sigset_t sigs;
1998         int num;
1999         int is_child_of_nonroot=0;
2000         char *buf;
2001         char *runuser=NULL, *rungroup=NULL;
2002
2003         /* Remember original args for restart */
2004         if (argc > sizeof(_argv) / sizeof(_argv[0]) - 1) {
2005                 fprintf(stderr, "Truncating argument size to %d\n", (int)(sizeof(_argv) / sizeof(_argv[0])) - 1);
2006                 argc = sizeof(_argv) / sizeof(_argv[0]) - 1;
2007         }
2008         for (x=0;x<argc;x++)
2009                 _argv[x] = argv[x];
2010         _argv[x] = NULL;
2011
2012         /* if the progname is rasterisk consider it a remote console */
2013         if (argv[0] && (strstr(argv[0], "rasterisk")) != NULL) {
2014                 ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2015         }
2016         if (gethostname(hostname, sizeof(hostname)-1))
2017                 ast_copy_string(hostname, "<Unknown>", sizeof(hostname));
2018         ast_mainpid = getpid();
2019         ast_ulaw_init();
2020         ast_alaw_init();
2021         callerid_init();
2022         ast_utils_init();
2023         tdd_init();
2024         /* When Asterisk restarts after it has dropped the root privileges,
2025          * it can't issue setuid(), setgid(), setgroups() or set_priority() 
2026          * */
2027         if (getenv("ASTERISK_ALREADY_NONROOT"))
2028                 is_child_of_nonroot=1;
2029         if (getenv("HOME")) 
2030                 snprintf(filename, sizeof(filename), "%s/.asterisk_history", getenv("HOME"));
2031         /* Check if we're root */
2032         /*
2033         if (geteuid()) {
2034                 ast_log(LOG_ERROR, "Must be run as root\n");
2035                 exit(1);
2036         }
2037         */
2038         /* Check for options */
2039         while((c=getopt(argc, argv, "tThfdvVqprRgcinx:U:G:C:L:M:")) != -1) {
2040                 switch(c) {
2041                 case 'd':
2042                         option_debug++;
2043                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2044                         break;
2045                 case 'c':
2046                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_CONSOLE);
2047                         break;
2048                 case 'f':
2049                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2050                         break;
2051                 case 'n':
2052                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_COLOR);
2053                         break;
2054                 case 'r':
2055                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE);
2056                         break;
2057                 case 'R':
2058                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK | AST_OPT_FLAG_REMOTE | AST_OPT_FLAG_RECONNECT);
2059                         break;
2060                 case 'p':
2061                         ast_set_flag(&ast_options, AST_OPT_FLAG_HIGH_PRIORITY);
2062                         break;
2063                 case 'v':
2064                         option_verbose++;
2065                         ast_set_flag(&ast_options, AST_OPT_FLAG_NO_FORK);
2066                         break;
2067                 case 'M':
2068                         if ((sscanf(optarg, "%d", &option_maxcalls) != 1) || (option_maxcalls < 0))
2069                                 option_maxcalls = 0;
2070                         break;
2071                 case 'L':
2072                         if ((sscanf(optarg, "%lf", &option_maxload) != 1) || (option_maxload < 0.0))
2073                                 option_maxload = 0.0;
2074                         break;
2075                 case 'q':
2076                         ast_set_flag(&ast_options, AST_OPT_FLAG_QUIET);
2077                         break;
2078                 case 't':
2079                         ast_set_flag(&ast_options, AST_OPT_FLAG_CACHE_RECORD_FILES);
2080                         break;
2081                 case 'T':
2082                         ast_set_flag(&ast_options, AST_OPT_FLAG_TIMESTAMP);
2083                         break;
2084                 case 'x':
2085                         ast_set_flag(&ast_options, AST_OPT_FLAG_EXEC);
2086                         xarg = optarg;
2087                         break;
2088                 case 'C':
2089                         ast_copy_string(ast_config_AST_CONFIG_FILE, optarg, sizeof(ast_config_AST_CONFIG_FILE));
2090                         ast_set_flag(&ast_options, AST_OPT_FLAG_OVERRIDE_CONFIG);
2091                         break;
2092                 case 'i':
2093                         ast_set_flag(&ast_options, AST_OPT_FLAG_INIT_KEYS);
2094                         break;
2095                 case'g':
2096                         ast_set_flag(&ast_options, AST_OPT_FLAG_DUMP_CORE);
2097                         break;
2098                 case 'h':
2099                         show_cli_help();
2100                         exit(0);
2101                 case 'V':
2102                         show_version();
2103                         exit(0);
2104                 case 'U':
2105                         runuser = optarg;
2106                         break;
2107                 case 'G':
2108                         rungroup = optarg;
2109                         break;
2110                 case '?':
2111                         exit(1);
2112                 }
2113         }
2114
2115         /* For remote connections, change the name of the remote connection.
2116          * We do this for the benefit of init scripts (which need to know if/when
2117          * the main asterisk process has died yet). */
2118         if (ast_opt_remote) {
2119                 strcpy(argv[0], "rasterisk");
2120                 for (x = 1; x < argc; x++) {
2121                         argv[x] = argv[0] + 10;
2122                 }
2123         }
2124
2125         if (ast_opt_dump_core) {
2126                 struct rlimit l;
2127                 memset(&l, 0, sizeof(l));
2128                 l.rlim_cur = RLIM_INFINITY;
2129                 l.rlim_max = RLIM_INFINITY;
2130                 if (setrlimit(RLIMIT_CORE, &l)) {
2131                         ast_log(LOG_WARNING, "Unable to disable core size resource limit: %s\n", strerror(errno));
2132                 }
2133         }
2134
2135         if (ast_opt_console && !option_verbose) 
2136                 ast_verbose("[ Reading Master Configuration ]");
2137         ast_readconfig();
2138
2139         if ((!rungroup) && !ast_strlen_zero(ast_config_AST_RUN_GROUP))
2140                 rungroup = ast_config_AST_RUN_GROUP;
2141         if ((!runuser) && !ast_strlen_zero(ast_config_AST_RUN_USER))
2142                 runuser = ast_config_AST_RUN_USER;
2143 #ifndef __CYGWIN__
2144
2145         if (!is_child_of_nonroot) 
2146                 ast_set_priority(ast_opt_high_priority);
2147
2148         if (!is_child_of_nonroot && rungroup) {
2149                 struct group *gr;
2150                 gr = getgrnam(rungroup);
2151                 if (!gr) {
2152                         ast_log(LOG_WARNING, "No such group '%s'!\n", rungroup);
2153                         exit(1);
2154                 }
2155                 if (setgid(gr->gr_gid)) {
2156                         ast_log(LOG_WARNING, "Unable to setgid to %d (%s)\n", gr->gr_gid, rungroup);
2157                         exit(1);
2158                 }
2159                 if (setgroups(0, NULL)) {
2160                         ast_log(LOG_WARNING, "Unable to drop unneeded groups\n");
2161                         exit(1);
2162                 }
2163                 if (option_verbose)
2164                         ast_verbose("Running as group '%s'\n", rungroup);
2165         }
2166
2167         if (!is_child_of_nonroot && runuser) {
2168                 struct passwd *pw;
2169                 pw = getpwnam(runuser);
2170                 if (!pw) {
2171                         ast_log(LOG_WARNING, "No such user '%s'!\n", runuser);
2172                         exit(1);
2173                 }
2174                 if (!ast_strlen_zero(rungroup)) {
2175                         if (initgroups(pw->pw_name, pw->pw_gid)) {
2176                                 ast_log(LOG_WARNING, "Unable to init groups for '%s'\n", runuser);
2177                                 exit(1);
2178                         }
2179                 }
2180                 if (setuid(pw->pw_uid)) {
2181                         ast_log(LOG_WARNING, "Unable to setuid to %d (%s)\n", pw->pw_uid, runuser);
2182                         exit(1);
2183                 }
2184                 setenv("ASTERISK_ALREADY_NONROOT","yes",1);
2185                 if (option_verbose)
2186                         ast_verbose("Running as user '%s'\n", runuser);
2187         }
2188
2189 #endif /* __CYGWIN__ */
2190
2191         term_init();
2192         printf(term_end());
2193         fflush(stdout);
2194
2195         if (ast_opt_console && !option_verbose) 
2196                 ast_verbose("[ Initializing Custom Configuration Options ]");
2197         /* custom config setup */
2198         register_config_cli();
2199         read_config_maps();
2200         
2201
2202         if (ast_opt_console) {
2203                 if (el_hist == NULL || el == NULL)
2204                         ast_el_initialize();
2205
2206                 if (!ast_strlen_zero(filename))
2207                         ast_el_read_history(filename);
2208         }
2209
2210         if (ast_tryconnect()) {
2211                 /* One is already running */
2212                 if (ast_opt_remote) {
2213                         if (ast_opt_exec) {
2214                                 ast_remotecontrol(xarg);
2215                                 quit_handler(0, 0, 0, 0);
2216                                 exit(0);
2217                         }
2218                         printf(term_quit());
2219                         ast_register_verbose(console_verboser);
2220                         WELCOME_MESSAGE;
2221                         ast_remotecontrol(NULL);
2222                         quit_handler(0, 0, 0, 0);
2223                         exit(0);
2224                 } else {
2225                         ast_log(LOG_ERROR, "Asterisk already running on %s.  Use 'asterisk -r' to connect.\n", ast_config_AST_SOCKET);
2226                         printf(term_quit());
2227                         exit(1);
2228                 }
2229         } else if (ast_opt_remote || ast_opt_exec) {
2230                 ast_log(LOG_ERROR, "Unable to connect to remote asterisk (does %s exist?)\n",ast_config_AST_SOCKET);
2231                 printf(term_quit());
2232                 exit(1);
2233         }
2234         /* Blindly write pid file since we couldn't connect */
2235         unlink(ast_config_AST_PID);
2236         f = fopen(ast_config_AST_PID, "w");
2237         if (f) {
2238                 fprintf(f, "%d\n", getpid());
2239                 fclose(f);
2240         } else
2241                 ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2242
2243         if (!option_verbose && !option_debug && !ast_opt_no_fork && !ast_opt_console) {
2244                 daemon(0,0);
2245                 /* Blindly re-write pid file since we are forking */
2246                 unlink(ast_config_AST_PID);
2247                 f = fopen(ast_config_AST_PID, "w");
2248                 if (f) {
2249                         fprintf(f, "%d\n", getpid());
2250                         fclose(f);
2251                 } else
2252                         ast_log(LOG_WARNING, "Unable to open pid file '%s': %s\n", ast_config_AST_PID, strerror(errno));
2253         }
2254
2255         /* Test recursive mutex locking. */
2256         if (test_for_thread_safety())
2257                 ast_verbose("Warning! Asterisk is not thread safe.\n");
2258
2259         ast_makesocket();
2260         sigemptyset(&sigs);
2261         sigaddset(&sigs, SIGHUP);
2262         sigaddset(&sigs, SIGTERM);
2263         sigaddset(&sigs, SIGINT);
2264         sigaddset(&sigs, SIGPIPE);
2265         sigaddset(&sigs, SIGWINCH);
2266         pthread_sigmask(SIG_BLOCK, &sigs, NULL);
2267         if (ast_opt_console || option_verbose || ast_opt_remote)
2268                 ast_register_verbose(console_verboser);
2269         /* Print a welcome message if desired */
2270         if (option_verbose || ast_opt_console) {
2271                 WELCOME_MESSAGE;
2272         }
2273         if (ast_opt_console && !option_verbose) 
2274                 ast_verbose("[ Booting...");
2275
2276         signal(SIGURG, urg_handler);
2277         signal(SIGINT, __quit_handler);
2278         signal(SIGTERM, __quit_handler);
2279         signal(SIGHUP, hup_handler);
2280         signal(SIGCHLD, child_handler);
2281         signal(SIGPIPE, SIG_IGN);
2282
2283         /* ensure that the random number generators are seeded with a different value every time
2284            Asterisk is started
2285         */
2286         srand((unsigned int) getpid() + (unsigned int) time(NULL));
2287         srandom((unsigned int) getpid() + (unsigned int) time(NULL));
2288
2289         if (init_logger()) {
2290                 printf(term_quit());
2291                 exit(1);
2292         }
2293         if (dnsmgr_init()) {
2294                 printf(term_quit());
2295                 exit(1);
2296         }
2297         /* load 'preload' modules, required for access to Realtime-mapped configuration files */
2298         if (load_modules(1)) {
2299                 printf(term_quit());
2300                 exit(1);
2301         }
2302         ast_channels_init();
2303         if (init_manager()) {
2304                 printf(term_quit());
2305                 exit(1);
2306         }
2307         if (ast_cdr_engine_init()) {
2308                 printf(term_quit());
2309                 exit(1);
2310         }
2311         if (ast_device_state_engine_init()) {
2312                 printf(term_quit());
2313                 exit(1);
2314         }
2315         ast_rtp_init();
2316         if (ast_image_init()) {
2317                 printf(term_quit());
2318                 exit(1);
2319         }
2320         if (ast_file_init()) {
2321                 printf(term_quit());
2322                 exit(1);
2323         }
2324         if (load_pbx()) {
2325                 printf(term_quit());
2326                 exit(1);
2327         }
2328         if (load_modules(0)) {
2329                 printf(term_quit());
2330                 exit(1);
2331         }
2332         if (init_framer()) {
2333                 printf(term_quit());
2334                 exit(1);
2335         }
2336         if (astdb_init()) {
2337                 printf(term_quit());
2338                 exit(1);
2339         }
2340         if (ast_enum_init()) {
2341                 printf(term_quit());
2342                 exit(1);
2343         }
2344
2345         dnsmgr_start_refresh();
2346
2347 #if 0
2348         /* This should no longer be necessary */
2349         /* sync cust config and reload some internals in case a custom config handler binded to them */
2350         read_ast_cust_config();
2351         reload_logger(0);
2352         reload_manager();
2353         ast_enum_reload();
2354         ast_rtp_reload();
2355 #endif
2356
2357
2358         /* We might have the option of showing a console, but for now just
2359            do nothing... */
2360         if (ast_opt_console && !option_verbose)
2361                 ast_verbose(" ]\n");
2362         if (option_verbose || ast_opt_console)
2363                 ast_verbose(term_color(tmp, "Asterisk Ready.\n", COLOR_BRWHITE, COLOR_BLACK, sizeof(tmp)));
2364         if (ast_opt_no_fork)
2365                 consolethread = pthread_self();
2366         ast_set_flag(&ast_options, AST_OPT_FLAG_FULLY_BOOTED);
2367         pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
2368 #ifdef __AST_DEBUG_MALLOC
2369         __ast_mm_init();
2370 #endif  
2371         time(&ast_startuptime);
2372         ast_cli_register_multiple(core_cli, sizeof(core_cli) / sizeof(core_cli[0]));
2373         if (ast_opt_console) {
2374                 /* Console stuff now... */
2375                 /* Register our quit function */
2376                 char title[256];
2377                 set_icon("Asterisk");
2378                 snprintf(title, sizeof(title), "Asterisk Console on '%s' (pid %d)", hostname, ast_mainpid);
2379                 set_title(title);
2380
2381                 for (;;) {
2382                         buf = (char *)el_gets(el, &num);
2383                         if (buf) {
2384                                 if (buf[strlen(buf)-1] == '\n')
2385                                         buf[strlen(buf)-1] = '\0';
2386
2387                                 consolehandler((char *)buf);
2388                         } else {
2389                                 if (write(STDOUT_FILENO, "\nUse EXIT or QUIT to exit the asterisk console\n",
2390                                                                   strlen("\nUse EXIT or QUIT to exit the asterisk console\n")) < 0) {
2391                                         /* Whoa, stdout disappeared from under us... Make /dev/null's */
2392                                         int fd;
2393                                         fd = open("/dev/null", O_RDWR);
2394                                         if (fd > -1) {
2395                                                 dup2(fd, STDOUT_FILENO);
2396                                                 dup2(fd, STDIN_FILENO);
2397                                         } else
2398                                                 ast_log(LOG_WARNING, "Failed to open /dev/null to recover from dead console.  Bad things will happen!\n");
2399                                         break;
2400                                 }
2401                         }
2402                 }
2403
2404         }
2405         /* Do nothing */
2406         for(;;)  {      /* apparently needed for the MACos */
2407                 struct pollfd p = { -1 /* no descriptor */, 0, 0 };
2408                 poll(&p, 0, -1);
2409         }
2410         return 0;
2411 }