/* * Validate file access. Since we have no uid or gid, for now require * file to exist and be publicly readable/writable. * If we were invoked with arguments from inetd then the file must also * be in one of the given directory prefixes. Note also, full path name * must be given as we have no login directory. */ int validate_access( Client *cl, char *file ) { struct stat stbuf; /* * Prevent tricksters from getting around the directory restrictions */ if (strstr(file, "/../")) { errstr = "\"..\" in path"; return (EACCESS); } if (strstr(file, "../")) { errstr = "..\" in path"; return (EACCESS); } if (stat(file, &stbuf) < 0) { if (errno == ENOENT) { if (read_dynamic_file( cl->sin.sin_addr.s_addr, (u_int32_t *) &(cl->fnum), (u_int32_t *) &(cl->maxb) )) { errno = 0; cl->dynam = 1; return 0; } } errstr = strerror(errno); return (errno == ENOENT ? ENOTFOUND : EACCESS); } if ((stbuf.st_mode & S_IFMT) != S_IFREG) { errstr = "not a regular file"; return (ENOTFOUND); } if ((stbuf.st_mode & S_IROTH) == 0) { errstr = "not readable"; return (EACCESS); } if ( read_static_file( file, (u_int32_t *) &(cl->fnum), (u_int32_t *) &(cl->maxb) ) != 0 ) { return( EACCESS ); } return 0; }
int main(int argc, char* argv[]) { // Parse any command-line options. namespace po = boost::program_options; po::options_description desc("Allowed options"); desc.add_options() ("help", "show help") ("debug-httpd", po::value<bool>(&mp3d_debug_httpd), "show httpd debug output") ("root", po::value<std::string>(&mp3d_music_root), "root of file system mp3 tree") ("port", po::value<int>(&mp3d_port), "httpd port number") ; po::variables_map args; po::store(po::parse_command_line(argc, argv, desc), args); po::notify(args); if (args.count("help")) { std::cout << desc << std::endl; return 1; } // Index all the mp3s. Paths paths; find_mp3_files(mp3d_music_root, paths); std::cerr << ".mp3 files found: " << paths.size() << std::endl; int old_percentage = -1; size_t id = 0; for (Paths::const_iterator it = paths.begin(); it != paths.end(); ++it) { Mp3Info mp3; mp3.filename = (*it).string(); const ID3_Tag tag(mp3.filename.c_str()); ID3_Tag::ConstIterator* it = tag.CreateIterator(); for (size_t i = 0; i < tag.NumFrames(); ++i) { const ID3_Frame* frame = it->GetNext(); if (frame != 0) { std::string* dst; switch (frame->GetID()) { case ID3FID_ALBUM: dst = &mp3.album; break; case ID3FID_LEADARTIST: dst = &mp3.artist; break; case ID3FID_TITLE: dst = &mp3.title; break; default: continue; } char* text = ID3_GetString(frame, ID3FN_TEXT); dst->assign(text); ID3_FreeString(text); } } // FIXME: maybe a hash, to enable bookmarks? mp3.id = id++; all_mp3s.push_back(mp3); // Show progress. Not really useful when we're not debugging. // FIXME: start the web server straight away, and say "Indexing..." there. const int new_percentage = (100*all_mp3s.size())/paths.size(); if (new_percentage != old_percentage) { std::cout << "\rScanned: " << new_percentage << "%" << std::flush; old_percentage = new_percentage; } } std::cout << "\r.mp3 files scanned: " << all_mp3s.size() << std::endl; // Set up the static files we need to serve. read_static_file("/static/add.png", "/usr/share/icons/gnome/16x16/actions/gtk-add.png"); read_static_file("/static/play.png", "/usr/share/icons/gnome/16x16/actions/gtk-media-play-ltr.png"); read_static_file("/static/remove.png", "/usr/share/icons/gnome/16x16/actions/gtk-remove.png"); static_file_map["/static/site.css"] = make_css(); // Start the mp3 player thread. boost::thread mp3_player_thread(mp3_play_loop); // Start the HTTP server. std::cerr << "Starting HTTP server on port " << mp3d_port << "..." << std::endl; const int mhd_flags = MHD_USE_SELECT_INTERNALLY; MHD_Daemon* daemon = MHD_start_daemon(mhd_flags, mp3d_port, 0, 0, &handle_request, 0, MHD_OPTION_END); if (daemon == 0) { fail("MHD_start_daemon failed!"); } getchar(); // Wait for the user to hit enter. MHD_stop_daemon(daemon); //mp3_player_thread.join(); return 0; }