/* -*- Mode: C ; c-basic-offset: 2 -*- */ /***************************************************************************** * * DESCRIPTION: * Portable frontend to MediaBase 1.2 and 1.3 * * COMPILATION: * gcc addcd.c -lmysqlclient -o addcd * * AUTHOR: * Nedko Arnaudov * * LICENSE: * GNU GENERAL PUBLIC LICENSE verssion 2 * *****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #define MB_T_AUDIO 1 #define MB_T_DATA 2 #define MB_T_EMPTY 3 #define MAX_TITLE_SIZE 128 /* in db */ #define MAX_PASS_SIZE 1024 #define DEFAULT_MYSQL_USER "mediabase" #define DEFAULT_MYSQL_PASS "mediabase" #define DEFAULT_MYSQL_HOST "localhost" #define DEFAULT_MYSQL_DB "mediabase" #define DEFAULT_MOUNT_CMD "sudo /sbin/mount /cdrom" #define DEFAULT_UNMOUNT_CMD "sudo /sbin/umount /cdrom" #define DEFAULT_MOUNTDIR "/cdrom" #define MAX_PATH_DEPTH 65535 #define INITIAL_BUFFER_ADD 4096 #define BUFFER_ADD 4096 //#define DUMMY_SQL_QUERIES //#define PRINT_FILENAMES char strTitle[MAX_TITLE_SIZE+2]; /* + newline + null */ char strPass[MAX_PASS_SIZE]; char *pszPathBuffer = NULL; size_t nPathBufferSize = 0; size_t nMountPrefixLength; unsigned long nTotalFiles; unsigned long long nTotalSize; my_ulonglong nMediaID = 0ULL; char *pszSQLQuery = NULL; size_t nSQLQueryBufferSize = 0; MYSQL *pMYSQL = NULL; int blnMediaMounted = 0; int blnExiting = 0; const char *pszHost = DEFAULT_MYSQL_HOST; const char *pszUser = DEFAULT_MYSQL_USER; const char *pszPass = DEFAULT_MYSQL_PASS; const char *pszDB = DEFAULT_MYSQL_DB; const char *pszMountMediaCommand = DEFAULT_MOUNT_CMD; const char *pszUnmountMediaCommand = DEFAULT_UNMOUNT_CMD; const char *pszMountDir = DEFAULT_MOUNTDIR; char *pszEscapeBuffer1 = NULL; size_t nEscapeBuffer1Size = 0; char *pszEscapeBuffer2 = NULL; size_t nEscapeBuffer2Size = 0; void ExecuteCommand(const char *pszCommand); void MountMedia() { printf("--> Mounting media ...\n"); ExecuteCommand(pszMountMediaCommand); printf("--> Media mounted.\n"); blnMediaMounted = 1; } void UnmountMedia() { printf("--> Unmounting media ...\n"); ExecuteCommand(pszUnmountMediaCommand); printf("--> Media unmounted.\n"); blnMediaMounted = 0; } void Exit(int nRet) { if (blnExiting) return; blnExiting = 1; if (pMYSQL != NULL) { mysql_close(pMYSQL); } if (blnMediaMounted) UnmountMedia(); exit(nRet); } void ExecuteCommand(const char *pszCommand) { int nRet; nRet = system(pszCommand); if (nRet == -1) { fprintf(stderr, "Cannot execute command \"%s\". " "system() returned -1, error is %d (%s)\n", pszCommand, errno, strerror(errno)); Exit(1); } if (WIFEXITED(nRet)) { if (WEXITSTATUS(nRet) != 0) { fprintf(stderr, "Cannot execute command \"%s\". " "Command returned %d\n", pszCommand, (int)WEXITSTATUS(nRet)); Exit(1); } } else if (WIFSIGNALED(nRet)) { fprintf(stderr, "Cannot execute command \"%s\". " "Cammand was terminated because of signal %d\n", pszCommand, (int)WTERMSIG(nRet)); Exit(1); } else { fprintf(stderr, "Cannot execute command \"%s\". " "system() returned %d\n", pszCommand, nRet); Exit(1); } } void ReadTitle() { char *pch; printf("Title: "); if (fgets(strTitle, sizeof(strTitle), stdin) == NULL) { printf("\n"); if (feof(stdin)) { Exit(0); } fprintf(stderr, "Error occured while reading standard input.\n"); Exit(1); } else if (strTitle[0] == '\n') { Exit(0); } if ((pch = strchr(strTitle, '\n')) == NULL) { fprintf(stderr, "input line too long.\n"); Exit(1); } *pch = '\0'; } void AskForPassword() { char *pszPass; pszPass = getpass("MySQL password: "); strcpy(strPass, pszPass); } void MaybeEnlargeBuffer(char ** ppBuffer, size_t *pnBufferSize, size_t nSizeRequired) { char *pNewBuffer; size_t nNewBufferSize; if (nSizeRequired <= *pnBufferSize) return; if (*pnBufferSize == 0 || *ppBuffer == NULL) { /* Allocate */ nNewBufferSize = nSizeRequired + INITIAL_BUFFER_ADD; pNewBuffer = (char *)malloc(nNewBufferSize); if (pNewBuffer == NULL) { fprintf(stderr, "Cannot allocate %u bytes of memory.\n", (unsigned int)nNewBufferSize); Exit(0); } } else { /* Reallocate */ nNewBufferSize = nSizeRequired + BUFFER_ADD; pNewBuffer = (char *)malloc(nNewBufferSize); if (pNewBuffer == NULL) { fprintf(stderr, "Cannot allocate %u bytes of memory.\n", (unsigned int)nNewBufferSize); Exit(0); } memcpy(pNewBuffer, *ppBuffer, *pnBufferSize); free(*ppBuffer); } *pnBufferSize = nNewBufferSize; *ppBuffer = pNewBuffer; } void ScanDir(unsigned long nDepth) { DIR *pDir; struct dirent *pDE; size_t nCurrentPathLength; struct stat st; size_t nEscapedSize; if (nDepth >= MAX_PATH_DEPTH) { fprintf(stderr, "Max path depth of reached \"%u\"\n", (unsigned int)MAX_PATH_DEPTH); Exit(1); } nCurrentPathLength = strlen(pszPathBuffer); pDir = opendir(pszPathBuffer); if (pDir == NULL) { fprintf(stderr, "Cannot open \"%s\"\n", pszPathBuffer); Exit(1); } if (pDir) { while ((pDE = readdir(pDir)) != NULL) { if (strcmp(pDE->d_name, ".") == 0) continue; if (strcmp(pDE->d_name, "..") == 0) continue; MaybeEnlargeBuffer(&pszPathBuffer, &nPathBufferSize, nCurrentPathLength + pDE->d_namlen + 1); memcpy(pszPathBuffer + nCurrentPathLength, pDE->d_name, pDE->d_namlen); pszPathBuffer[nCurrentPathLength + pDE->d_namlen] = 0; if (lstat(pszPathBuffer, &st) != 0) { fprintf(stderr, "Cannot stat() %s. Error is %d (%s)\n", pszPathBuffer, errno, strerror(errno)); } pszPathBuffer[nCurrentPathLength] = 0; MaybeEnlargeBuffer(&pszEscapeBuffer1, &nEscapeBuffer1Size, (nCurrentPathLength - nMountPrefixLength)*2+1); nEscapedSize = mysql_real_escape_string( pMYSQL, pszEscapeBuffer1, pszPathBuffer + nMountPrefixLength, nCurrentPathLength - nMountPrefixLength); MaybeEnlargeBuffer(&pszEscapeBuffer2, &nEscapeBuffer2Size, pDE->d_namlen*2+1); nEscapedSize += mysql_real_escape_string( pMYSQL, pszEscapeBuffer2, pDE->d_name, pDE->d_namlen); MaybeEnlargeBuffer(&pszSQLQuery, &nSQLQueryBufferSize, nEscapedSize + 1024); sprintf(pszSQLQuery, "INSERT INTO mb_files " "(mediaid,size,time,path,name) " "VALUES (%u,%u,%u,'%s','%s%s')", (unsigned int)nMediaID, (unsigned int)((S_ISDIR(st.st_mode))?0:st.st_size), (unsigned int)st.st_ctimespec.tv_sec, pszEscapeBuffer1, pszEscapeBuffer2, (S_ISDIR(st.st_mode))?"/":""); #ifdef DUMMY_SQL_QUERIES printf("MySQL query \"%s\"\n", pszSQLQuery); #else if (mysql_query(pMYSQL, pszSQLQuery) != 0) { fprintf(stderr, "Failed to execute query \"%s\" Error: %s\n", pszSQLQuery, mysql_error(pMYSQL)); Exit(1); } #endif memcpy(pszPathBuffer + nCurrentPathLength, pDE->d_name, pDE->d_namlen); pszPathBuffer[nCurrentPathLength + pDE->d_namlen] = 0; #ifdef PRINT_FILENAMES printf("%s", pszPathBuffer + nMountPrefixLength); #endif nTotalFiles++; if (S_ISDIR(st.st_mode)) { #ifdef PRINT_FILENAMES printf("/\n"); #else printf("/"); #endif fflush(stdout); memcpy(pszPathBuffer + nCurrentPathLength + pDE->d_namlen, "/", 2); ScanDir(nDepth + 1); } else { nTotalSize += st.st_size; #ifdef PRINT_FILENAMES printf("\n"); #else printf("."); #endif fflush(stdout); } } closedir(pDir); } } void Help(char *arg0) { char *pszExecutable; pszExecutable = strrchr(arg0, '/'); if (pszExecutable == NULL) { pszExecutable = arg0; } else { pszExecutable++; } printf("Usage:\n"); printf("[]%s [options]\n", pszExecutable); printf(" Options can be:\n"); printf(" -h - MySQL server host, default is \"%s\"\n", pszHost); printf(" -u - MySQL user, default is \"%s\"\n", pszUser); printf(" -p [mysql_pass] - MySQL password, default is \"%s\"\n", pszPass); printf(" -b - MySQL database, default is \"%s\"\n", pszDB); printf(" -m - command to mount media, default is \"%s\"\n", pszMountMediaCommand); printf(" -n - command to unmount, default is \"%s\"\n", pszUnmountMediaCommand); printf(" -d - where media is mounted, default is \"%s\"\n", pszMountDir); Exit(0); } int main( int argc, char ** argv ) { time_t timeAdded; int i; size_t nTitleSize; printf("Adding media to MediaBase\n"); printf("=========================\n"); /* Process options from command line */ for (i = 1; i < argc ; i++) { if (strcmp(argv[i],"-h") == 0) { i++; if (i < argc) { pszHost = argv[i]; } else { fprintf(stderr, "Missing parameter of -h option\n"); Help(argv[0]); } } else if (strcmp(argv[i],"-u") == 0) { i++; if (i < argc) { pszUnmountMediaCommand = argv[i]; } else { fprintf(stderr, "Missing parameter of -u option\n"); Help(argv[0]); } } else if (strcmp(argv[i],"-p") == 0) { if (i+1 < argc && argv[i+1][0] != '-') { i++; pszPass = argv[i]; } else { AskForPassword(); pszPass = strPass; } } else if (strcmp(argv[i],"-b") == 0) { i++; if (i < argc) { pszDB = argv[i]; } else { fprintf(stderr, "Missing parameter of -b option\n"); Help(argv[0]); } } else if (strcmp(argv[i],"-m") == 0) { i++; if (i < argc) { pszMountMediaCommand = argv[i]; } else { fprintf(stderr, "Missing parameter of -m option\n"); Help(argv[0]); } } else if (strcmp(argv[i],"-n") == 0) { i++; if (i < argc) { pszUnmountMediaCommand = argv[i]; } else { fprintf(stderr, "Missing parameter of -n option\n"); Help(argv[0]); } } else if (strcmp(argv[i],"-d") == 0) { i++; if (i < argc) { pszMountDir = argv[i]; } else { fprintf(stderr, "Missing parameter of -d option\n"); Help(argv[0]); } } else if (strcmp(argv[i],"-h") == 0) { Help(argv[0]); } else { fprintf(stderr, "Unknown option \"%s\"\n", argv[i]); Help(argv[0]); } } printf("NOTE: Currently audio media is not supported.\n"); MaybeEnlargeBuffer(&pszSQLQuery, &nSQLQueryBufferSize, MAX_TITLE_SIZE + 1024); pMYSQL = mysql_init(NULL); if (pMYSQL == NULL) { fprintf(stderr, "Cannot create MYSQL object. Error is \"%s\"\n", mysql_error(pMYSQL)); Exit(1); } if (mysql_real_connect(pMYSQL, pszHost, pszUser, pszPass, pszDB, 0, NULL, 0) == NULL) { fprintf(stderr, "Failed to connect to database. Error: %s\n", mysql_error(pMYSQL)); Exit(1); } nMountPrefixLength = strlen(pszMountDir); MaybeEnlargeBuffer(&pszPathBuffer, &nPathBufferSize, nMountPrefixLength + 2); memcpy(pszPathBuffer, pszMountDir, nMountPrefixLength); Loop: memcpy(pszPathBuffer + nMountPrefixLength, "/", 2); printf("--> Please insert media and enter title.\n"); ReadTitle(); nTitleSize = strlen(strTitle); MaybeEnlargeBuffer(&pszEscapeBuffer1, &nEscapeBuffer1Size, nTitleSize*2+1); mysql_real_escape_string(pMYSQL, pszEscapeBuffer1, strTitle, nTitleSize); MountMedia(); nTotalFiles = 0UL; nTotalSize = 0ULL; printf("--> Processing media ...\n"); sprintf(pszSQLQuery, "INSERT INTO mb_media (name,type,comment) VALUES ('%s',%u,'')", pszEscapeBuffer1, (unsigned int)MB_T_DATA); #ifdef DUMMY_SQL_QUERIES printf("MySQL query \"%s\"\n", pszSQLQuery); #else if (mysql_query(pMYSQL, pszSQLQuery) != 0) { fprintf(stderr, "Failed to execute query \"%s\" Error: %s\n", pszSQLQuery, mysql_error(pMYSQL)); Exit(1); } nMediaID = mysql_insert_id(pMYSQL); if (nMediaID == 0ULL) { fprintf(stderr, "Invalid media ID 0 after media INSERT\n"); Exit(1); } #endif ScanDir(0); printf("\n"); timeAdded = time(NULL); sprintf(pszSQLQuery, "UPDATE mb_media SET added=%u, info1=%u, info2=%u WHERE mediaid = %u", (unsigned int)timeAdded, (unsigned int)nTotalFiles, (unsigned int)nTotalSize, (unsigned int)nMediaID); #ifdef DUMMY_SQL_QUERIES printf("MySQL query \"%s\"\n", pszSQLQuery); #else if (mysql_query(pMYSQL, pszSQLQuery) != 0) { fprintf(stderr, "Failed to execute query \"%s\" Error: %s\n", pszSQLQuery, mysql_error(pMYSQL)); Exit(1); } #endif UnmountMedia(); printf("--> SUCCESS - Media added.\n"); printf("Media title: %s\n", strTitle); printf("Media ID: %u\n", (unsigned int)nMediaID); printf("Added: %s", ctime(&timeAdded)); printf("Total files: %u\n", (unsigned int)nTotalFiles); printf("Total size: %u\n", (unsigned int)nTotalSize); goto Loop; }