setup.c

00001 /*
00002  * $Id: setup.c 5147 2007-05-08 15:36:22Z ajc $
00003  *
00004  * WebCit setup utility
00005  * 
00006  * (This is basically just an install wizard.  It's not required.)
00007  *
00008  */
00009 
00010 #include "config.h"
00011 #include "webcit.h"
00012 #include "webserver.h"
00013 
00014 
00015 #define UI_TEXT         0       /* Default setup type -- text only */
00016 #define UI_DIALOG       2       /* Use the 'dialog' program */
00017 #define UI_SILENT       3       /* Silent running, for use in scripts */
00018 
00019 int setup_type;
00020 char setup_directory[SIZ];
00021 int using_web_installer = 0;
00022 char suggested_url[SIZ];
00023 
00024 /*
00025  * Delete an entry from /etc/inittab
00026  */
00027 void delete_init_entry(char *which_entry)
00028 {
00029         char *inittab = NULL;
00030         FILE *fp;
00031         char buf[SIZ];
00032         char entry[SIZ];
00033         char levels[SIZ];
00034         char state[SIZ];
00035         char prog[SIZ];
00036 
00037         inittab = strdup("");
00038         if (inittab == NULL) return;
00039 
00040         fp = fopen("/etc/inittab", "r");
00041         if (fp == NULL) return;
00042 
00043         while(fgets(buf, sizeof buf, fp) != NULL) {
00044 
00045                 if (num_tokens(buf, ':') == 4) {
00046                         extract_token(entry, buf, 0, ':', sizeof entry);
00047                         extract_token(levels, buf, 1, ':', sizeof levels);
00048                         extract_token(state, buf, 2, ':', sizeof state);
00049                         extract_token(prog, buf, 3, ':', sizeof prog); /* includes 0x0a LF */
00050 
00051                         if (!strcmp(entry, which_entry)) {
00052                                 strcpy(state, "off");   /* disable it */
00053                         }
00054                 }
00055 
00056                 inittab = realloc(inittab, strlen(inittab) + strlen(buf) + 2);
00057                 if (inittab == NULL) {
00058                         fclose(fp);
00059                         return;
00060                 }
00061                 
00062                 strcat(inittab, buf);
00063         }
00064         fclose(fp);
00065         fp = fopen("/etc/inittab", "w");
00066         if (fp != NULL) {
00067                 fwrite(inittab, strlen(inittab), 1, fp);
00068                 fclose(fp);
00069                 kill(1, SIGHUP);        /* Tell init to re-read /etc/inittab */
00070         }
00071         free(inittab);
00072 }
00073 
00074 
00075 
00076 
00077 /* 
00078  * Remove any /etc/inittab entries for webcit, because we don't
00079  * start it that way anymore.
00080  */
00081 void delete_the_old_way(void) {
00082         FILE *infp;
00083         char buf[1024];
00084         char looking_for[1024];
00085         int have_entry = 0;
00086         char entry[1024];
00087         char prog[1024];
00088         char init_entry[1024];
00089 
00090 
00091         strcpy(init_entry, "");
00092 
00093         /* Determine the fully qualified path name of webserver */
00094         snprintf(looking_for, sizeof looking_for, "%s/webserver ", setup_directory);
00095 
00096         /* Pound through /etc/inittab line by line.  Set have_entry to 1 if
00097          * an entry is found which we believe starts webserver.
00098          */
00099         infp = fopen("/etc/inittab", "r");
00100         if (infp == NULL) {
00101                 return;
00102         } else {
00103                 while (fgets(buf, sizeof buf, infp) != NULL) {
00104                         buf[strlen(buf) - 1] = 0;
00105                         extract_token(entry, buf, 0, ':', sizeof entry);
00106                         extract_token(prog, buf, 3, ':', sizeof prog);
00107                         if (!strncasecmp(prog, looking_for,
00108                            strlen(looking_for))) {
00109                                 ++have_entry;
00110                                 strcpy(init_entry, entry);
00111                         }
00112                 }
00113                 fclose(infp);
00114         }
00115 
00116         /* Bail out if there's nothing to do. */
00117         if (!have_entry) return;
00118 
00119         delete_init_entry(init_entry);
00120 }
00121 
00122 
00123 
00124 void cleanup(int exitcode)
00125 {
00126         exit(exitcode);
00127 }
00128 
00129 
00130 
00131 void title(char *text)
00132 {
00133         if (setup_type == UI_TEXT) {
00134                 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n<%s>\n", text);
00135         }
00136 }
00137 
00138 
00139 
00140 
00141 int yesno(char *question, int default_value)
00142 {
00143         int i = 0;
00144         int answer = 0;
00145         char buf[SIZ];
00146 
00147         switch (setup_type) {
00148 
00149         case UI_TEXT:
00150                 do {
00151                         printf("%s\nYes/No [%s] --> ",
00152                                 question,
00153                                 ( default_value ? "Yes" : "No" )
00154                         );
00155                         fgets(buf, sizeof buf, stdin);
00156                         answer = tolower(buf[0]);
00157                         if ((buf[0]==0) || (buf[0]==13) || (buf[0]==10))
00158                                 answer = default_value;
00159                         else if (answer == 'y')
00160                                 answer = 1;
00161                         else if (answer == 'n')
00162                                 answer = 0;
00163                 } while ((answer < 0) || (answer > 1));
00164                 break;
00165 
00166         case UI_DIALOG:
00167                 sprintf(buf, "exec %s %s --yesno '%s' 15 75",
00168                         getenv("CTDL_DIALOG"),
00169                         ( default_value ? "" : "--defaultno" ),
00170                         question);
00171                 i = system(buf);
00172                 if (i == 0) {
00173                         answer = 1;
00174                 }
00175                 else {
00176                         answer = 0;
00177                 }
00178                 break;
00179 
00180         }
00181         return (answer);
00182 }
00183 
00184 
00185 
00186 
00187 void set_value(char *prompt, char str[])
00188 {
00189         char buf[SIZ];
00190         char dialog_result[PATH_MAX];
00191         char setupmsg[SIZ];
00192         FILE *fp;
00193 
00194         strcpy(setupmsg, "");
00195 
00196         switch (setup_type) {
00197         case UI_TEXT:
00198                 title("WebCit setup");
00199                 printf("\n%s\n", prompt);
00200                 printf("This is currently set to:\n%s\n", str);
00201                 printf("Enter new value or press return to leave unchanged:\n");
00202                 fgets(buf, sizeof buf, stdin);
00203                 buf[strlen(buf) - 1] = 0;
00204                 if (strlen(buf) != 0)
00205                         strcpy(str, buf);
00206                 break;
00207 
00208         case UI_DIALOG:
00209                 CtdlMakeTempFileName(dialog_result, sizeof dialog_result);
00210                 sprintf(buf, "exec %s --inputbox '%s' 19 72 '%s' 2>%s",
00211                         getenv("CTDL_DIALOG"),
00212                         prompt,
00213                         str,
00214                         dialog_result);
00215                 system(buf);
00216                 fp = fopen(dialog_result, "r");
00217                 if (fp != NULL) {
00218                         fgets(str, sizeof buf, fp);
00219                         if (str[strlen(str)-1] == 10) {
00220                                 str[strlen(str)-1] = 0;
00221                         }
00222                         fclose(fp);
00223                         unlink(dialog_result);
00224                 }
00225                 break;
00226 
00227         }
00228 }
00229 
00230 
00231 void important_message(char *title, char *msgtext)
00232 {
00233         char buf[SIZ];
00234 
00235         switch (setup_type) {
00236 
00237         case UI_TEXT:
00238                 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
00239                 printf("       %s \n\n%s\n\n", title, msgtext);
00240                 printf("Press return to continue...");
00241                 fgets(buf, sizeof buf, stdin);
00242                 break;
00243 
00244         case UI_DIALOG:
00245                 sprintf(buf, "exec %s --msgbox '%s' 19 72",
00246                         getenv("CTDL_DIALOG"),
00247                         msgtext);
00248                 system(buf);
00249                 break;
00250         }
00251 }
00252 
00253 
00254 void display_error(char *error_message)
00255 {
00256         important_message("Error", error_message);
00257 }
00258 
00259 void progress(char *text, long int curr, long int cmax)
00260 {
00261         static long dots_printed = 0L;
00262         long a = 0;
00263         char buf[SIZ];
00264         static FILE *fp = NULL;
00265 
00266         switch (setup_type) {
00267 
00268         case UI_TEXT:
00269                 if (curr == 0) {
00270                         printf("%s\n", text);
00271                         printf("..........................");
00272                         printf("..........................");
00273                         printf("..........................\r");
00274                         fflush(stdout);
00275                         dots_printed = 0;
00276                 } else if (curr == cmax) {
00277                         printf("\r%79s\n", "");
00278                 } else {
00279                         a = (curr * 100) / cmax;
00280                         a = a * 78;
00281                         a = a / 100;
00282                         while (dots_printed < a) {
00283                                 printf("*");
00284                                 ++dots_printed;
00285                                 fflush(stdout);
00286                         }
00287                 }
00288                 break;
00289 
00290         case UI_DIALOG:
00291                 if (curr == 0) {
00292                         sprintf(buf, "exec %s --gauge '%s' 7 72 0",
00293                                 getenv("CTDL_DIALOG"),
00294                                 text);
00295                         fp = popen(buf, "w");
00296                         if (fp != NULL) {
00297                                 fprintf(fp, "0\n");
00298                                 fflush(fp);
00299                         }
00300                 } 
00301                 else if (curr == cmax) {
00302                         if (fp != NULL) {
00303                                 fprintf(fp, "100\n");
00304                                 pclose(fp);
00305                                 fp = NULL;
00306                         }
00307                 }
00308                 else {
00309                         a = (curr * 100) / cmax;
00310                         if (fp != NULL) {
00311                                 fprintf(fp, "%ld\n", a);
00312                                 fflush(fp);
00313                         }
00314                 }
00315                 break;
00316         }
00317 }
00318 
00319 
00320 
00321 
00322 /*
00323  * install_init_scripts()  -- Create and deploy SysV init scripts.
00324  *
00325  */
00326 void install_init_scripts(void)
00327 {
00328         char question[1024];
00329         char buf[256];
00330         char http_port[128];
00331 #ifdef HAVE_OPENSSL
00332         char https_port[128];
00333 #endif
00334         char hostname[128];
00335         char portname[128];
00336         char command[SIZ];
00337         struct utsname my_utsname;
00338         struct stat etcinitd;
00339         FILE *fp;
00340         char *initfile = "/etc/init.d/webcit";
00341 
00342         /* Otherwise, prompt the user to create an entry. */
00343         snprintf(question, sizeof question,
00344                 "Would you like to automatically start WebCit at boot?"
00345         );
00346         if (yesno(question, 1) == 0)
00347                 return;
00348 
00349         /* Defaults */
00350         sprintf(http_port, "2000");
00351 #ifdef HAVE_OPENSSL
00352         sprintf(https_port, "443");
00353 #endif
00354         sprintf(hostname, "uds");
00355         sprintf(portname, "/usr/local/citadel");
00356 
00357         /* This is a very hackish way of learning the port numbers used
00358          * in a previous install, if we are upgrading: read them out of
00359          * the existing init script.
00360          */
00361         if ((stat("/etc/init.d/", &etcinitd) == -1) && 
00362             (errno == ENOENT))
00363         {
00364                 if ((stat("/etc/rc.d/init.d/", &etcinitd) == -1) &&
00365                     (errno == ENOENT))
00366                         initfile = PREFIX"/webcit.init";
00367                 else
00368                         initfile = "/etc/rc.d/init.d/webcit";
00369         }
00370 
00371         fp = fopen(initfile, "r");
00372         if (fp != NULL) {
00373                 while (fgets(buf, sizeof buf, fp) != NULL) {
00374                         if (strlen(buf) > 0) {
00375                                 buf[strlen(buf)-1] = 0; /* strip trailing cr */
00376                         }
00377                         if (!strncasecmp(buf, "HTTP_PORT=", 10)) {
00378                                 safestrncpy(http_port, &buf[10], sizeof http_port);
00379                         }
00380 #ifdef HAVE_OPENSSL
00381                         if (!strncasecmp(buf, "HTTPS_PORT=", 11)) {
00382                                 safestrncpy(https_port, &buf[11], sizeof https_port);
00383                         }
00384 #endif
00385                         if (!strncasecmp(buf, "CTDL_HOSTNAME=", 14)) {
00386                                 safestrncpy(hostname, &buf[14], sizeof hostname);
00387                         }
00388                         if (!strncasecmp(buf, "CTDL_PORTNAME=", 14)) {
00389                                 safestrncpy(portname, &buf[14], sizeof portname);
00390                         }
00391                 }
00392                 fclose(fp);
00393         }
00394 
00395         /* Now ask for the port numbers */
00396         snprintf(question, sizeof question,
00397                 "On which port do you want WebCit to listen for HTTP "
00398                 "requests?\n\nYou can use the standard port (80) if you are "
00399                 "not running another\nweb server (such as Apache), otherwise "
00400                 "select another port.");
00401         set_value(question, http_port);
00402         uname(&my_utsname);
00403         sprintf(suggested_url, "http://%s:%s/", my_utsname.nodename, http_port);
00404 
00405 #ifdef HAVE_OPENSSL
00406         snprintf(question, sizeof question,
00407                 "On which port do you want WebCit to listen for HTTPS "
00408                 "requests?\n\nYou can use the standard port (443) if you are "
00409                 "not running another\nweb server (such as Apache), otherwise "
00410                 "select another port.");
00411         set_value(question, https_port);
00412 #endif
00413 
00414         /* Find out where Citadel is. */
00415         if ( (using_web_installer) && (getenv("CITADEL") != NULL) ) {
00416                 strcpy(hostname, "uds");
00417                 strcpy(portname, getenv("CITADEL"));
00418         }
00419         else {
00420                 snprintf(question, sizeof question,
00421                         "Is the Citadel service running on the same host as WebCit?");
00422                 if (yesno(question, ((!strcasecmp(hostname, "uds")) ? 1 : 0))) {
00423                         strcpy(hostname, "uds");
00424                         if (atoi(portname) != 0) strcpy(portname, "/usr/local/citadel");
00425                         set_value("In what directory is Citadel installed?", portname);
00426                 }
00427                 else {
00428                         if (!strcasecmp(hostname, "uds")) strcpy(hostname, "127.0.0.1");
00429                         if (atoi(portname) == 0) strcpy(portname, "504");
00430                         set_value("Enter the host name or IP address of your "
00431                                 "Citadel server.", hostname);
00432                         set_value("Enter the port number on which Citadel is "
00433                                 "running (usually 504)", portname);
00434                 }
00435         }
00436 
00437 
00438         fp = fopen(initfile, "w");
00439 
00440         fprintf(fp,     "#!/bin/sh\n"
00441                         "\n"
00442                         "WEBCIT_DIR=%s\n", setup_directory);
00443         fprintf(fp,     "HTTP_PORT=%s\n", http_port);
00444 #ifdef HAVE_OPENSSL
00445         fprintf(fp,     "HTTPS_PORT=%s\n", https_port);
00446 #endif
00447         fprintf(fp,     "CTDL_HOSTNAME=%s\n", hostname);
00448         fprintf(fp,     "CTDL_PORTNAME=%s\n", portname);
00449         fprintf(fp,     "\n"
00450                         "\n"
00451                         "case \"$1\" in\n"
00452                         "\n"
00453                         "start)         echo -n \"Starting WebCit... \"\n"
00454                         "               if   $WEBCIT_DIR/webserver "
00455                                                         "-D/var/run/webcit.pid "
00456                                                         "-p$HTTP_PORT $CTDL_HOSTNAME $CTDL_PORTNAME\n"
00457                         "               then\n"
00458                         "                       echo \"ok\"\n"
00459                         "               else\n"
00460                         "                       echo \"failed\"\n"
00461                         "               fi\n");
00462 #ifdef HAVE_OPENSSL
00463         fprintf(fp,     "               echo -n \"Starting WebCit SSL... \"\n"
00464                         "               if  $WEBCIT_DIR/webserver "
00465                                                         "-D/var/run/webcit-ssl.pid "
00466                                                         "-s -p$HTTPS_PORT $CTDL_HOSTNAME $CTDL_PORTNAME\n"
00467                         "               then\n"
00468                         "                       echo \"ok\"\n"
00469                         "               else\n"
00470                         "                       echo \"failed\"\n"
00471                         "               fi\n");
00472 #endif
00473         fprintf(fp,     "               ;;\n"
00474                         "stop)          echo -n \"Stopping WebCit... \"\n"
00475                         "               if kill `cat /var/run/webcit.pid 2>/dev/null` 2>/dev/null\n"
00476                         "               then\n"
00477                         "                       echo \"ok\"\n"
00478                         "               else\n"
00479                         "                       echo \"failed\"\n"
00480                         "               fi\n"
00481                         "               rm -f /var/run/webcit.pid 2>/dev/null\n");
00482 #ifdef HAVE_OPENSSL
00483         fprintf(fp,     "               echo -n \"Stopping WebCit SSL... \"\n"
00484                         "               if kill `cat /var/run/webcit-ssl.pid 2>/dev/null` 2>/dev/null\n"
00485                         "               then\n"
00486                         "                       echo \"ok\"\n"
00487                         "               else\n"
00488                         "                       echo \"failed\"\n"
00489                         "               fi\n"
00490                         "               rm -f /var/run/webcit-ssl.pid 2>/dev/null\n");
00491 #endif
00492         fprintf(fp,     "               ;;\n"
00493                         "restart)       $0 stop\n"
00494                         "               $0 start\n"
00495                         "               ;;\n"
00496                         "*)             echo \"Usage: $0 {start|stop|restart}\"\n"
00497                         "               exit 1\n"
00498                         "               ;;\n"
00499                         "esac\n"
00500         );
00501 
00502         fclose(fp);
00503         chmod(initfile, 0755);
00504 
00505         /* Set up the run levels. */
00506         system("/bin/rm -f /etc/rc?.d/[SK]??webcit 2>/dev/null");
00507         snprintf(command, sizeof(command), "for x in 2 3 4 5 ; do [ -d /etc/rc$x.d ] && ln -s %s /etc/rc$x.d/S84webcit ; done 2>/dev/null", initfile);
00508         system(command);
00509         snprintf(command, sizeof(command), "for x in 0 6 S; do [ -d /etc/rc$x.d ] && ln -s %s /etc/rc$x.d/K15webcit ; done 2>/dev/null", initfile);
00510         system(command);
00511 
00512 }
00513 
00514 
00515 
00516 
00517 /*
00518  * Figure out what type of user interface we're going to use
00519  */
00520 int discover_ui(void)
00521 {
00522 
00523         /* Use "dialog" if we have it */
00524         if (getenv("CTDL_DIALOG") != NULL) {
00525                 return UI_DIALOG;
00526         }
00527                 
00528         return UI_TEXT;
00529 }
00530 
00531 
00532 
00533 
00534 
00535 int main(int argc, char *argv[])
00536 {
00537         int a;
00538         char aaa[256];
00539         int info_only = 0;
00540         strcpy(suggested_url, "http://<your_host_name>:<port>/");
00541 
00542         /* set an invalid setup type */
00543         setup_type = (-1);
00544 
00545         /* Check to see if we're running the web installer */
00546         if (getenv("CITADEL_INSTALLER") != NULL) {
00547                 using_web_installer = 1;
00548         }
00549 
00550         /* parse command line args */
00551         for (a = 0; a < argc; ++a) {
00552                 if (!strncmp(argv[a], "-u", 2)) {
00553                         strcpy(aaa, argv[a]);
00554                         strcpy(aaa, &aaa[2]);
00555                         setup_type = atoi(aaa);
00556                 }
00557                 if (!strcmp(argv[a], "-i")) {
00558                         info_only = 1;
00559                 }
00560                 if (!strcmp(argv[a], "-q")) {
00561                         setup_type = UI_SILENT;
00562                 }
00563         }
00564 
00565 
00566         /* If a setup type was not specified, try to determine automatically
00567          * the best one to use out of all available types.
00568          */
00569         if (setup_type < 0) {
00570                 setup_type = discover_ui();
00571         }
00572         if (info_only == 1) {
00573                 important_message("WebCit Setup", "Welcome to WebCit setup");
00574                 cleanup(0);
00575         }
00576 
00577         /* Get started in a valid setup directory. */
00578         strcpy(setup_directory, PREFIX);
00579         if ( (using_web_installer) && (getenv("WEBCIT") != NULL) ) {
00580                 strcpy(setup_directory, getenv("WEBCIT"));
00581         }
00582         else {
00583                 set_value("In what directory is WebCit installed?",
00584                         setup_directory);
00585         }
00586         if (chdir(setup_directory) != 0) {
00587                 important_message("WebCit Setup",
00588                           "The directory you specified does not exist.");
00589                 cleanup(errno);
00590         }
00591 
00592         /*
00593          * We used to start WebCit by putting it directly into /etc/inittab.
00594          * Since some systems are moving away from init, we can't do this anymore.
00595          */
00596         progress("Removing obsolete /etc/inittab entries...", 0, 1);
00597         delete_the_old_way();
00598         progress("Removing obsolete /etc/inittab entries...", 1, 1);
00599 
00600         /* Now begin. */
00601         switch (setup_type) {
00602 
00603         case UI_TEXT:
00604                 printf("\n\n\n"
00605                         "               *** WebCit setup program ***\n\n");
00606                 break;
00607 
00608         }
00609 
00610         /* 
00611          * If we're running on SysV, install init scripts.
00612          */
00613         if (!access("/var/run", W_OK)) {
00614                 install_init_scripts();
00615 
00616                 if (!access("/etc/init.d/webcit", X_OK)) {
00617                         system("/etc/init.d/webcit stop");
00618                         system("/etc/init.d/webcit start");
00619                 }
00620 
00621                 sprintf(aaa,
00622                         "Setup is finished.  You may now log in.\n"
00623                         "Point your web browser at %s\n", suggested_url
00624                 );
00625                 important_message("Setup finished", aaa);
00626         }
00627 
00628         else {
00629                 important_message("Setup finished",
00630                         "Setup is finished.  You may now start the server.");
00631         }
00632 
00633         cleanup(0);
00634         return 0;
00635 }

Generated on Wed Jun 20 23:13:10 2007 for webcit by  doxygen 1.5.2