p_link newlink() { register link *rval; if (Lcache) { rval = Lcache; Lcache = Lcache->l_next; strclear((char *) rval, sizeof(link)); } else if ((rval = (link * ) calloc(1, sizeof(link))) == 0) nomem(); return rval; }
/* * Print gopher menu line */ void info(state *st, char *str, char type) { char buf[BUFSIZE]; char selector[16]; /* Convert string to output charset */ if (st->opt_iconv) sstrniconv(st->out_charset, buf, str); else sstrlcpy(buf, str); /* Handle gopher title resources */ strclear(selector); if (type == TYPE_TITLE) { sstrlcpy(selector, "TITLE"); type = TYPE_INFO; } /* Output info line */ strcut(buf, st->out_width); printf("%c%s\t%s\t%s" CRLF, type, buf, selector, DUMMY_HOST); }
/* * Parse command-line arguments */ void parse_args(state *st, int argc, char *argv[]) { FILE *fp; static const char readme[] = README; static const char license[] = LICENSE; struct stat file; char buf[BUFSIZE]; int opt; /* Parse args */ while ((opt = getopt(argc, argv, "h:p:r:t:g:a:c:u:m:l:w:o:s:i:k:f:e:R:D:L:A:P:n:db?-")) != ERROR) { switch(opt) { case 'h': sstrlcpy(st->server_host, optarg); break; case 'p': st->server_port = atoi(optarg); break; case 'r': sstrlcpy(st->server_root, optarg); break; case 't': st->default_filetype = *optarg; break; case 'g': sstrlcpy(st->map_file, optarg); break; case 'a': sstrlcpy(st->map_file, optarg); break; case 'c': sstrlcpy(st->cgi_file, optarg); break; case 'u': sstrlcpy(st->user_dir, optarg); break; case 'm': /* obsolete, replaced by -l */ case 'l': sstrlcpy(st->log_file, optarg); break; case 'w': st->out_width = atoi(optarg); break; case 'o': if (sstrncasecmp(optarg, "UTF-8") == MATCH) st->out_charset = UTF_8; if (sstrncasecmp(optarg, "ISO-8859-1") == MATCH) st->out_charset = ISO_8859_1; break; case 's': st->session_timeout = atoi(optarg); break; case 'i': st->session_max_kbytes = abs(atoi(optarg)); break; case 'k': st->session_max_hits = abs(atoi(optarg)); break; case 'f': sstrlcpy(st->filter_dir, optarg); break; case 'e': add_ftype_mapping(st, optarg); break; case 'R': add_rewrite_mapping(st, optarg); break; case 'D': sstrlcpy(st->server_description, optarg); break; case 'L': sstrlcpy(st->server_location, optarg); break; case 'A': sstrlcpy(st->server_admin, optarg); break; case 'n': if (*optarg == 'v') { st->opt_vhost = FALSE; break; } if (*optarg == 'l') { st->opt_parent = FALSE; break; } if (*optarg == 'h') { st->opt_header = FALSE; break; } if (*optarg == 'f') { st->opt_footer = FALSE; break; } if (*optarg == 'd') { st->opt_date = FALSE; break; } if (*optarg == 'c') { st->opt_magic = FALSE; break; } if (*optarg == 'o') { st->opt_iconv = FALSE; break; } if (*optarg == 'q') { st->opt_query = FALSE; break; } if (*optarg == 's') { st->opt_syslog = FALSE; break; } if (*optarg == 'a') { st->opt_caps = FALSE; break; } if (*optarg == 'm') { st->opt_shm = FALSE; break; } if (*optarg == 'r') { st->opt_root = FALSE; break; } break; case 'd': st->debug = TRUE; break; case 'b': puts(license); exit(EXIT_SUCCESS); default : puts(readme); exit(EXIT_SUCCESS); } } /* Sanitize options */ if (st->out_width > MAX_WIDTH) st->out_width = MAX_WIDTH; if (st->out_width < MIN_WIDTH) st->out_width = MIN_WIDTH; if (st->out_width < MIN_WIDTH + DATE_WIDTH) st->opt_date = FALSE; if (!st->opt_syslog) st->debug = FALSE; /* Primary vhost directory must exist or we disable vhosting */ if (st->opt_vhost) { snprintf(buf, sizeof(buf), "%s/%s", st->server_root, st->server_host); if (stat(buf, &file) == ERROR) st->opt_vhost = FALSE; } /* If -D arg looks like a file load the file contents */ if (*st->server_description == '/') { if ((fp = fopen(st->server_description , "r"))) { fgets(st->server_description, sizeof(st->server_description), fp); chomp(st->server_description); fclose(fp); } else strclear(st->server_description); } /* If -L arg looks like a file load the file contents */ if (*st->server_location == '/') { if ((fp = fopen(st->server_location , "r"))) { fgets(st->server_location, sizeof(st->server_location), fp); chomp(st->server_location); fclose(fp); } else strclear(st->server_location); } }
/* * Get OS name, version & architecture we're running on */ void platform(state *st) { #ifdef HAVE_UNAME #if defined(_AIX) || defined(__linux) || defined(__APPLE__) FILE *fp; #endif #if defined(__arm__) || defined(__mips__) || defined(__APPLE__) char buf[BUFSIZE]; #endif #ifdef __linux struct stat file; #endif struct utsname name; char sysname[64]; char release[64]; char machine[64]; char *c; /* Fetch system information */ uname(&name); strclear(sysname); strclear(release); strclear(machine); /* AIX-specific */ #ifdef _AIX /* Fix uname() results */ sstrlcpy(machine, "powerpc"); snprintf(release, sizeof(release), "%s.%s", name.version, name.release); /* Get CPU type */ if ((fp = popen("/usr/sbin/getsystype -i", "r"))) { fgets(machine, sizeof(machine), fp); pclose(fp); strreplace(machine, ' ', '_'); } /* Get hardware name using shell uname */ if (!*st->server_description && (fp = popen("/usr/bin/uname -M", "r"))) { fgets(st->server_description, sizeof(st->server_description), fp); pclose(fp); strreplace(st->server_description, ',', ' '); chomp(st->server_description); } #endif /* Mac OS X, just like Unix but totally different... */ #ifdef __APPLE__ /* Hardcode OS name */ sstrlcpy(sysname, "MacOSX"); /* Get OS X version */ if ((fp = popen("/usr/bin/sw_vers -productVersion", "r"))) { fgets(release, sizeof(release), fp); pclose(fp); } /* Get hardware name */ if (!*st->server_description && (fp = popen("/usr/sbin/sysctl -n hw.model", "r"))) { /* Read hardware name */ fgets(buf, sizeof(buf), fp); pclose(fp); /* Clones are gone now so we'll hardcode the manufacturer */ sstrlcpy(st->server_description, "Apple "); sstrlcat(st->server_description, buf); /* Remove hardware revision */ for (c = st->server_description; *c; c++) if (*c >= '0' && *c <= '9') { *c = '\0'; break; } } #endif /* Linux uname() just says Linux/2.6 - let's dig deeper... */ #ifdef __linux /* Most Linux ARM/MIPS boards have hardware name in /proc/cpuinfo */ #if defined(__arm__) || defined(__mips__) if (!*st->server_description && (fp = fopen("/proc/cpuinfo" , "r"))) { while (fgets(buf, sizeof(buf), fp)) { #ifdef __arm__ if ((c = strkey(buf, "Hardware"))) { #else if ((c = strkey(buf, "machine"))) { #endif sstrlcpy(st->server_description, c); chomp(st->server_description); break; } } fclose(fp); } #endif /* Identify RedHat */ if (!*sysname && (fp = fopen("/etc/redhat-release", "r"))) { fgets(sysname, sizeof(sysname), fp); fclose(fp); if ((c = strstr(sysname, "release "))) sstrlcpy(release, c + 8); if ((c = strchr(release, ' '))) *c = '\0'; if ((c = strchr(sysname, ' '))) *c = '\0'; if (strcmp(sysname, "Red") == MATCH) sstrlcpy(sysname, "RedHat"); } /* Identify Slackware */ if (!*sysname && (fp = fopen("/etc/slackware-version", "r"))) { fgets(sysname, sizeof(sysname), fp); fclose(fp); if ((c = strchr(sysname, ' '))) { sstrlcpy(release, c + 1); *c = '\0'; } } /* Uh-oh.... how about a standard Linux with lsb_release? */ if (stat("/usr/bin/lsb_release", &file) == OK && (file.st_mode & S_IXOTH)) { if (!*sysname && (fp = popen("/usr/bin/lsb_release -i -s", "r"))) { fgets(sysname, sizeof(sysname), fp); pclose(fp); } if (!*release && (fp = popen("/usr/bin/lsb_release -r -s", "r"))) { fgets(release, sizeof(release), fp); pclose(fp); } } /* OK, nothing worked - let's try /etc/issue for sysname */ if (!*sysname && (fp = fopen("/etc/issue", "r"))) { fgets(sysname, sizeof(sysname), fp); fclose(fp); if ((c = strchr(sysname, ' '))) *c = '\0'; if ((c = strchr(sysname, '\\'))) *c = '\0'; } /* Debian version should be in /etc/debian_version */ if (!*release && (fp = fopen("/etc/debian_version", "r"))) { fgets (release, sizeof(release), fp); fclose(fp); if ((c = strchr(release, '/'))) *c = '\0'; } #endif /* Haiku OS */ #ifdef __HAIKU__ /* Fix release name */ snprintf(release, sizeof(release), "R%s", name.release); #endif /* Fill in the blanks using uname() data */ if (!*sysname) sstrlcpy(sysname, name.sysname); if (!*release) sstrlcpy(release, name.release); if (!*machine) sstrlcpy(machine, name.machine); /* I always liked weird Perl-only functions */ chomp(sysname); chomp(release); chomp(machine); /* We're only interested in major.minor version */ if ((c = strchr(release, '.'))) if ((c = strchr(c + 1, '.'))) *c = '\0'; if ((c = strchr(release, '-'))) *c = '\0'; if ((c = strchr(release, '/'))) *c = '\0'; /* Create a nicely formatted platform string */ snprintf(st->server_platform, sizeof(st->server_platform), "%s/%s %s", sysname, #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) machine, release); #else release, machine); #endif /* Debug */ if (st->debug) { syslog(LOG_INFO, "generated platform string \"%s\"", st->server_platform); } #else /* Fallback reply */ sstrlcpy(st->server_platform, "Unknown computer-like system"); #endif } /* * Return current CPU load */ float loadavg(void) { FILE *fp; char buf[BUFSIZE]; /* Faster Linux version */ #ifdef __linux buf[0] = '\0'; if ((fp = fopen("/proc/loadavg" , "r")) == NULL) return 0; fgets(buf, sizeof(buf), fp); fclose(fp); return (float) atof(buf); /* Generic slow version - parse the output of uptime */ #else #ifdef HAVE_POPEN char *c; if ((fp = popen("/usr/bin/uptime", "r"))) { fgets(buf, sizeof(buf), fp); pclose(fp); if ((c = strstr(buf, "average: ")) || (c = strstr(buf, "averages: "))) return (float) atof(c + 10); } #endif /* Fallback reply */ return 0; #endif }
/* * Initialize state struct to default/empty values */ void init_state(state *st) { static const char *filetypes[] = { FILETYPES }; char buf[BUFSIZE]; char *c; int i; /* Request */ strclear(st->req_selector); strclear(st->req_realpath); strclear(st->req_query_string); strclear(st->req_referrer); sstrlcpy(st->req_local_addr, get_local_address()); sstrlcpy(st->req_remote_addr, get_peer_address()); /* strclear(st->req_remote_host); */ st->req_filetype = DEFAULT_TYPE; st->req_protocol = PROTO_GOPHER; st->req_filesize = 0; /* Output */ st->out_width = DEFAULT_WIDTH; st->out_charset = DEFAULT_CHARSET; /* Settings */ sstrlcpy(st->server_root, DEFAULT_ROOT); sstrlcpy(st->server_host_default, DEFAULT_HOST); if ((c = getenv("HOSTNAME"))) sstrlcpy(st->server_host, c); else if ((gethostname(buf, sizeof(buf))) != ERROR) sstrlcpy(st->server_host, buf); st->server_port = DEFAULT_PORT; st->default_filetype = DEFAULT_TYPE; sstrlcpy(st->map_file, DEFAULT_MAP); sstrlcpy(st->tag_file, DEFAULT_TAG); sstrlcpy(st->cgi_file, DEFAULT_CGI); sstrlcpy(st->user_dir, DEFAULT_USERDIR); strclear(st->log_file); st->hidden_count = 0; st->filetype_count = 0; strclear(st->filter_dir); st->rewrite_count = 0; strclear(st->server_description); strclear(st->server_location); strclear(st->server_platform); strclear(st->server_admin); /* Session */ st->session_timeout = DEFAULT_SESSION_TIMEOUT; st->session_max_kbytes = DEFAULT_SESSION_MAX_KBYTES; st->session_max_hits = DEFAULT_SESSION_MAX_HITS; /* Feature options */ st->opt_vhost = TRUE; st->opt_parent = TRUE; st->opt_header = TRUE; st->opt_footer = TRUE; st->opt_date = TRUE; st->opt_syslog = TRUE; st->opt_magic = TRUE; st->opt_iconv = TRUE; st->opt_query = TRUE; st->opt_caps = TRUE; st->opt_shm = TRUE; st->opt_root = TRUE; st->debug = FALSE; /* Load default suffix -> filetype mappings */ for (i = 0; filetypes[i]; i += 2) { if (st->filetype_count < MAX_FILETYPES) { sstrlcpy(st->filetype[st->filetype_count].suffix, filetypes[i]); st->filetype[st->filetype_count].type = *filetypes[i + 1]; st->filetype_count++; } } }