home *** CD-ROM | disk | FTP | other *** search
- /* MikMod example player
- (c) 1998 Miodrag Vallat and others - see file AUTHORS for complete list
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- /*==============================================================================
-
- $Id: marchive.c,v 1.22 1998/12/07 06:01:24 miod Exp $
-
- Archive support
-
- These routines are used to detect different archive/compression formats
- and decompress/de-archive the mods from them if necessary.
-
- ==============================================================================*/
-
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
-
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #ifndef HAVE_FNMATCH_H
- #include "../extra/fnmatch.h"
- #else
- #include <fnmatch.h>
- #endif
- #ifdef HAVE_LIMITS_H
- #include <limits.h>
- #endif
- #ifdef __EMX__
- #define PATH_MAX _POSIX_PATH_MAX
- #endif
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #if !defined(__OS2__)&&!defined(__EMX__)
- #ifdef HAVE_FCNTL_H
- #include <fcntl.h>
- #endif
- #include <pwd.h>
- #include <sys/wait.h>
- #endif
-
- #include <mikmod.h>
- #include "player.h"
-
- /*========== Archives */
-
- typedef struct {
- unsigned int location;
- char *marker;
- char *command;
- #if !defined(__OS2__)&&!defined(__EMX__)
- char *extrargs,*extrargs2;
- char *listargs,*listargs2;
- #else
- char *extrargs;
- char *listargs;
- #endif
- unsigned int nameoffset;
- } ARCHIVE;
-
- /* use similar signature idea to "file" to see what format we have... */
- static char gzsignature[]={0x1f,0x8b,0};
- static char pksignature[]={'P','K',0x03,0x04,0};
- static char zoosignature[]={0xdc,0xa7,0xc4,0xfd,0};
- static char rarsignature[]={'R','a','r','!',0};
- #if !defined(__OS2__)&&!defined(__EMX__)
- static char arjsignature[]={0x60,0xea,0};
- static char lhsignature[]={'-','l','h',0};
- static char lzsignature[]={'-','l','z',0};
- #endif
-
- ARCHIVE MA_archiver[]={
- /* location, marker, command, extract and view args, filenames column */
- #if !defined(__OS2__)&&!defined(__EMX__)
- /* PKzip archive */
- { 0, pksignature, "unzip", "-pqq", "", "-vqq", "", 58},
- /* gzip */
- { 0, gzsignature, "gzip", "-dqc", "", "-lq", "", 27},
- /* zoo */
- { 20, zoosignature, "zoo", "xpq", "", "lq", "", 47},
- /* rar */
- { 0, rarsignature, "unrar", "p", "-inul", "v", "-c-", 1},
- /* lharc */
- { 2, lhsignature, "lha", "pq", "", "vvq", "", 0},
- { 2, lzsignature, "lha", "pq", "", "vvq", "", 0},
- /* arj with the "extract to stdout" patch */
- { 0, arjsignature, "unarj", "c", "", "l", "", 0},
- /* needed to end the array... */
- { 0, NULL, NULL, NULL, NULL, NULL, NULL, 0}
- #else
- /* PKzip archive */
- { 0, pksignature, "unzip", "-pqq", "-lqq", 41},
- /* gzip */
- { 0, gzsignature, "gzip", "-dqc", "-lq", 27},
- /* zoo */
- { 20, zoosignature, "zoo", "xpq", "lq", 47},
- { 0, rarsignature, "unrar", "p -inul", "v -c-", 1},
- /* needed to end the array... */
- { 0, NULL, NULL, NULL, NULL, 0}
- #endif
- };
-
- /* rightmost column position */
- #if defined(__OS2__)||defined(__EMX__)
- #define MAXCOLUMN 47
- #else
- #define MAXCOLUMN 58
- #endif
-
- /* largest signature length */
- #define MAXSIGNATURE 16
-
- /* module filenames patterns */
- #define PATTERNCOUNT 13
- CHAR* modulepatterns[PATTERNCOUNT]={
- "*.669",
- "*.[Aa][Mm][Ff]",
- "*.[Dd][Ss][Mm]",
- "*.[Ff][Aa][Rr]",
- "*.[Ii][Tt]",
- "*.[Mm][Ee][Dd]",
- "*.[Mm][Oo][Dd]",
- "[Mm][Oo][Dd].*",
- "*.[Mm][Tt][Mm]",
- "*.[Ss]3[Mm]",
- "*.[Ss][Tt][Mm]",
- "*.[Uu][Ll][Tt]",
- "*.[Xx][Mm]"
- };
-
- #if !defined(__OS2__)&&!defined(__EMX__)
- BOOL DropPrivileges(void)
- {
- if(!geteuid()) {
- if(getuid()) {
- /* setuid root -> drop setuid, become the real user */
- if(setuid(getuid()))
- return 1;
- } else {
- /* run as root -> drop all, become user 'nobody' */
- struct passwd *nobody;
- int uid;
-
- if(!(nobody=getpwnam("nobody")))
- return 1; /* no such user ? */
- uid=nobody->pw_uid;
- free(nobody);
- if(!uid) /* user 'nobody' has root privileges ? weird... */
- return 1;
- if(setuid(uid))
- return 1;
- }
- }
- return 0;
- }
- #endif
-
- BOOL MA_ismodulefilename(CHAR* filename)
- {
- int t;
-
- for(t=0;t<PATTERNCOUNT;t++)
- if(!fnmatch(modulepatterns[t],filename,0))
- return 1;
- return 0;
- }
-
- int* MA_identify(CHAR* filename,int header_location,CHAR* header_string)
- {
- FILE *fp;
- CHAR id[MAXSIGNATURE+1];
-
- #ifdef MIKMOD_DEBUG
- if(strlen(header_string)>MAXSIGNATURE)
- fputs("Error: wrong constant MAXSIGNATURE in MikMod source\n",stderr);
- #endif
- if(!(fp=fopen(filename,"rb")))
- return NULL;
-
- fseek(fp,header_location,SEEK_SET);
-
- if(!fread(id,strlen(header_string),1,fp)) {
- fclose(fp);
- return 0;
- }
- if(!memcmp(id,(CHAR*)header_string,strlen(header_string))) {
- fclose(fp);
- return (int*)1;
- }
- fclose(fp);
-
- return 0;
- }
-
- CHAR* MA_dearchive(CHAR* arc,CHAR* file)
- {
- int t;
- CHAR *tmp_file;
-
- /* not an archive file... */
- if((!arc)||(!arc[0]))
- return strdup(file);
-
- #if defined(__OS2__) && defined(__WATCOMC__)
- if(!(tmp_file=malloc(strlen(getenv("TEMP"))+strlen("\\!MikMod.tmp")+1)))
- return NULL;
- strcpy(tmp_file,getenv("TEMP"));
- strcat(tmp_file,"\\!MikMod.tmp");
- #else
- if(!(tmp_file=tempnam(NULL,".mod")))
- if(!(tmp_file=tempnam(getenv("HOME"),".mod")))
- return NULL;
- #endif
-
- for(t=0;MA_archiver[t].command;t++)
- if(MA_identify(arc,MA_archiver[t].location,MA_archiver[t].marker)) {
- /* display "extracting" message, as this may take some time... */
- display_extractbanner();
- #if defined(__OS2__)||defined(__EMX__)
- /* extracting, the non-Unix way */
- {
- CHAR command_buff[PATH_MAX<<1];
-
- sprintf(command_buff,"%s %s %s \"%s\" >\"%s\"",
- MA_archiver[t].command,MA_archiver[t].extrargs,arc,file,tmp_file);
- system(command_buff);
- }
- #else
- /* extracting, the Unix way */
- {
- pid_t pid;
- int status,fd;
-
- switch(pid=fork()) {
- case -1: /* fork failed */
- return NULL;
- break;
- case 0: /* fork succeeded, child process code */
- /* if we have root privileges, drop them */
- if(DropPrivileges()) exit(0);
- fd=open(tmp_file,O_WRONLY|O_CREAT|O_TRUNC,S_IREAD|S_IWRITE);
- if(fd!=-1) {
- close(0);close(1);close(2);
- dup2(fd,1);
- signal(SIGINT,SIG_DFL);signal(SIGQUIT,SIG_DFL);
- execlp(MA_archiver[t].command,
- MA_archiver[t].command,
- MA_archiver[t].extrargs,
- MA_archiver[t].extrargs2,
- arc,
- file,
- NULL);
- close(fd);
- unlink(tmp_file);
- }
- exit(0);
- break;
- default: /* fork succeeded, main process code */
- waitpid(pid,&status,0);
- if(!WIFEXITED(status)) {
- unlink(tmp_file);
- return NULL;
- }
- break;
- }
- }
- #endif
- break;
- }
-
- return tmp_file;
- }
-
- void MA_FindFiles(PLAYLIST* pl,CHAR* filename)
- {
- int t;
- int archive=0;
- CHAR string[PATH_MAX+(MAXCOLUMN+1)+1];
- struct stat statbuf;
-
- #ifdef MIKMOD_DEBUG
- for(t=0;MA_archiver[t].command;t++)
- if(MA_archiver[t].nameoffset>MAXCOLUMN) {
- fputs("Error: wrong constant MAXCOLUMN in MikMod source\n",stderr);
- return;
- }
- #endif
-
- if (stat(filename,&statbuf))
- return; /* File does not exist or not enough access rights */
- if ((S_ISDIR(statbuf.st_mode))||(S_ISCHR(statbuf.st_mode))
- #ifndef __EMX__
- ||(S_ISBLK(statbuf.st_mode))
- #endif
- )
- return; /* Directories and devices can't be modules... */
-
- /* if filename looks like a module, don't try to unzip the file...*/
- if(MA_ismodulefilename(filename)) {
- PL_Add(pl,filename,NULL);
- return;
- }
-
- for(t=0;MA_archiver[t].command;t++)
- if(MA_identify(filename,MA_archiver[t].location,MA_archiver[t].marker)) {
- archive=t+1;
- break;
- }
-
- if(archive--) {
- #if defined(__OS2__)||defined(__EMX__)
- /* Archive display, the non-Unix way */
- FILE *file;
-
- sprintf(string,"%s %s \"%s\"",MA_archiver[archive].command,
- MA_archiver[archive].listargs,filename);
- #ifdef __WATCOMC__
- file=_popen(string,"r");
- #else
- file=popen(string,"r");
- #endif
- fgets(string,PATH_MAX+MAXCOLUMN+1,file);
- while(!feof(file)) {
- string[strlen(string)-1]=0;
- if(!MA_archiver[archive].nameoffset) {
- /* this won't work with .arj and files embedding whitespaces,
- but arj shouldn't exist anyway... */
- for(t=0;string[t]!=' ';t++);
- string[t]=0;
- }
- if(MA_ismodulefilename(string+MA_archiver[archive].nameoffset))
- PL_Add(pl,(string+MA_archiver[archive].nameoffset),filename);
- fgets(string,PATH_MAX,file);
- }
- #ifdef __WATCOMC__
- _pclose(file);
- #else
- pclose(file);
- #endif
- #else
- /* Archive display, the Unix way */
- int fd[2];
-
- if(!pipe(fd)) {
- pid_t pid;
- int status,cur;
- char ch;
-
- switch(pid=fork()) {
- case -1: /* fork failed */
- break;
- case 0: /* fork succeeded, child process code */
- /* if we have root privileges, drop them */
- if(DropPrivileges()) exit(0);
- close(0);close(1);close(2);
- dup2(fd[1],1);dup2(fd[1],2);
- signal(SIGINT,SIG_DFL);signal(SIGQUIT,SIG_DFL);
- execlp(MA_archiver[archive].command,
- MA_archiver[archive].command,
- MA_archiver[archive].listargs,
- MA_archiver[archive].listargs2,
- filename,
- NULL);
- close(fd[1]);
- exit(0);
- break;
- default: /* fork succeeded, main process code */
- /* have to wait for the child to ensure the command was
- successful and the pipe contains useful information */
- waitpid(pid,&status,0);
- close(fd[1]);
- if(!WIFEXITED(status)) {
- close(fd[0]);
- break;
- }
- /* read from the pipe */
- cur=0;
- while(read(fd[0],&ch,1)) {
- if(ch=='\n') ch=0;
- string[cur++]=ch;
- if(!ch) {
- cur=0;
- if(!MA_archiver[archive].nameoffset) {
- /* this won't work with .arj and files embedding
- whitespaces, but arj shouldn't exist anyway
- and I doubt it can store those files...*/
- for(t=0;string[t]!=' ';t++);
- string[t]=0;
- }
- if(MA_ismodulefilename(string+MA_archiver[archive].nameoffset))
- PL_Add(pl,(string+MA_archiver[archive].nameoffset),filename);
- }
- }
- close(fd[0]);
- break;
- }
- }
- #endif
- } else
- PL_Add(pl,filename,NULL);
- }
-