/* * Save the offsets we've reached for each disk to a file, so we can start * at that position next time the daemon is started. */ void writeoffsets(struct disk *disks, const char *save_file) { FILE *fp; struct disk *dp; if ((fp = fopen(save_file, "w")) == NULL) { syslog(LOG_NOTICE, "open %s failed: %m", save_file); return; } if (debug) fprintf(stderr, "#\tposition/size\tdays\trate\terrors\tintvl\tnext\n"); for (dp = disks; dp->device != NULL; dp++) if (strcmp(dp->device, "*") != 0) { fprintf(fp, "%s " QD "\n", dp->device, (quad_t)dseek(dp, 0, SEEK_CUR)); if (debug) { fprintf(stderr, "%s " QD "\n", dp->device, (quad_t)dseek(dp, 0, SEEK_CUR)); fprintf(stderr, "#\t" QD "\t%d\t%d\t%d\t" QD "\t" QD "\n", (quad_t)dp->size, dp->days, dp->rate, dp->errors, dp->interval, dp->next); } } fclose(fp); }
/* * Read the next chunk from the specified disk, retrying if necessary. */ void readchunk(struct disk *dp, char *buf) { ssize_t n; int s; dp->next = dp->interval; n = read(dp->fd, buf, READ_SIZE); if (n == 0) { eof: syslog(LOG_INFO, "reached end of %s with %d errors", dp->device, dp->errors); dseek(dp, 0, SEEK_SET); dp->errors = 0; return; } else if (n > 0) return; /* * Read error, retry in smaller chunks. */ logreaderror(dp, READ_SIZE); for (s = 0; s < READ_SIZE; s += 512) { n = read(dp->fd, buf, 512); if (n == 0) goto eof; else if (n < 0) { /* log the error and seek past it. */ logreaderror(dp, 512); dseek(dp, 512, SEEK_CUR); } } }
/* asqlDbfDseek() * append record *************************************************************************/ _declspec(dllexport) long asqlDbfDseek(TS_CLIENT_CURSOR *tscc, void *df, \ long recNo, \ char cFromWhere, \ EXCHNG_BUF_INFO *exbuf ) { TS_COM_PROPS tscp; char lpszResponse[4096]; memset(&tscp, 0, sizeof(TS_COM_PROPS)); while( tscc != NULL ) { if( tscc->p == (void *)df ) goto agdr_dfTrueR; tscc = tscc->pNext; } df = NULL; agdr_dfTrueR: tscp.packetType = 'R'; tscp.msgType = 'E'; tscp.len = 0; if( df == NULL ) { tscp.lp = -1; memcpy( lpszResponse, &tscp, sizeof(TS_COM_PROPS)); SrvWriteExchngBuf(exbuf, lpszResponse, sizeof(TS_COM_PROPS)); return -1; } switch( cFromWhere ) { case 'E': dseek((dFILE *)df, recNo, dSEEK_END); break; case 'C': dseek((dFILE *)df, recNo, dSEEK_CUR); break; //case 'S': default: dseek((dFILE *)df, recNo, dSEEK_SET); break; } tscp.msgType = 'D'; tscp.lp = 0; memcpy(lpszResponse, &tscp, sizeof(TS_COM_PROPS)); SrvWriteExchngBuf(exbuf, lpszResponse, sizeof(TS_COM_PROPS)); return 0; } //end of asqlDbfDseek()
/* asqlGetDbfRec() * *************************************************************************/ _declspec(dllexport) long asqlGetDbfRec(TS_CLIENT_CURSOR *tscc, void *df, \ long recNo, \ EXCHNG_BUF_INFO *exbuf ) { RECPROPS recprops; TS_COM_PROPS tscp; char lpszResponse[4096]; memset(&tscp, 0, sizeof(TS_COM_PROPS)); while( tscc != NULL ) { if( tscc->p == (void *)df ) goto agdr_dfTrue; tscc = tscc->pNext; } df = NULL; agdr_dfTrue: if( df == NULL || recNo <= 0 ) { tscp.packetType = 'R'; tscp.msgType = 'E'; tscp.len = 0; tscp.lp = -1; memcpy(lpszResponse, &tscp, sizeof(TS_COM_PROPS)); SrvWriteExchngBuf(exbuf, lpszResponse, 4096); return -1; } //to consider the view 2000.6.24 //((dFILE *)df)->rec_p = recNo; dseek((dFILE *)df, recNo-1, dSEEK_SET); if( get1rec((dFILE *)df) == NULL ) { tscp.packetType = 'R'; tscp.msgType = 'E'; tscp.len = 0; tscp.lp = -2; memcpy(lpszResponse, &tscp, sizeof(TS_COM_PROPS)); SrvWriteExchngBuf(exbuf, lpszResponse, 4096); return -2; } tscp.packetType = 'R'; tscp.msgType = 'D'; tscp.len = sizeof(RECPROPS)+((dFILE *)df)->rec_len; tscp.lp = 0; memcpy(lpszResponse, &tscp, sizeof(TS_COM_PROPS)); recprops.iPhyRecNum = ((dFILE *)df)->rec_p; recprops.bDeleteFlag = ((dFILE *)df)->rec_buf[0] - ' '; memcpy(&lpszResponse[sizeof(TS_COM_PROPS)], &recprops, sizeof(RECPROPS)); memcpy(&lpszResponse[sizeof(TS_COM_PROPS)+sizeof(RECPROPS)], ((dFILE *)df)->rec_buf, ((dFILE *)df)->rec_len); SrvWriteExchngBuf(exbuf, lpszResponse, sizeof(TS_COM_PROPS)+tscp.len); return 0; } //end of asqlGetDbfRec()
/* * Read the offsets written by writeoffsets(). */ void readoffsets(struct disk *disks, const char *save_file) { FILE *fp; struct disk *dp; char *space, buf[1024]; if ((fp = fopen(save_file, "r")) == NULL) { if (debug > 1 && errno == ENOENT) fprintf(stderr, "open %s failed: %s [continuing]\n", save_file, strerror(errno)); if (errno != ENOENT) syslog(LOG_NOTICE, "open %s failed: %m", save_file); return; } while (fgets(buf, sizeof buf, fp) != NULL) { if ((space = strchr(buf, ' ')) == NULL) continue; *space = '\0'; for (dp = disks; dp->device != NULL && strcmp(dp->device, buf) != 0; dp++) ; /* nothing */ if (dp->device != NULL) { if (debug) fprintf(stderr, "%s: seek %s", buf, space + 1); dseek(dp, (off_t)strtoq(space + 1, NULL, 0), SEEK_SET); } } fclose(fp); if (debug) fprintf(stderr, "readoffsets: done\n"); }
/* asqlAppDbfRec() * append record *************************************************************************/ _declspec(dllexport) long asqlAppDbfRec(TS_CLIENT_CURSOR *tscc, void *df, \ LPSTR sRecBuf, \ EXCHNG_BUF_INFO *exbuf ) { TS_COM_PROPS tscp; char lpszResponse[4096]; memset(&tscp, 0, sizeof(TS_COM_PROPS)); while( tscc != NULL ) { if( tscc->p == (void *)df ) goto agdr_dfTrueR; tscc = tscc->pNext; } df = NULL; agdr_dfTrueR: tscp.packetType = 'R'; tscp.msgType = 'E'; tscp.len = 0; if( df == NULL ) { tscp.lp = -1; memcpy( lpszResponse, &tscp, sizeof(TS_COM_PROPS)); SrvWriteExchngBuf(exbuf, lpszResponse, sizeof(TS_COM_PROPS)); return -1; } memcpy(((dFILE *)df)->rec_buf, sRecBuf, ((dFILE *)df)->rec_len); //lock it to avoid other thread move to the end for appending wmtDbfLock((dFILE *)df); dseek((dFILE *)df, 0, dSEEK_END); //1999.12.21 absSyncDfBh( (dFILE *)df ); if( put1rec( (dFILE *)df ) == NULL ) { //error tscp.lp = -4; } else { tscp.msgType = 'D'; tscp.lp = 0; } wmtDbfUnLock((dFILE *)df); memcpy(lpszResponse, &tscp, sizeof(TS_COM_PROPS)); SrvWriteExchngBuf(exbuf, lpszResponse, sizeof(TS_COM_PROPS)); return 0; } //end of asqlAppDbfRec()
/* asqlPutDbfRec() * *************************************************************************/ _declspec(dllexport) long asqlPutDbfRec(TS_CLIENT_CURSOR *tscc, void *df, \ long recNo, \ LPSTR recBuf, \ EXCHNG_BUF_INFO *exbuf ) { TS_COM_PROPS tscp; char lpszResponse[4096]; memset(&tscp, 0, sizeof(TS_COM_PROPS)); while( tscc != NULL ) { if( tscc->p == (void *)df ) goto agdr_dfTrueR; tscc = tscc->pNext; } df = NULL; agdr_dfTrueR: tscp.packetType = 'R'; tscp.msgType = 'E'; tscp.len = 0; if( df == NULL || recNo <= 0 ) { tscp.lp = -1; memcpy(lpszResponse, &tscp, sizeof(TS_COM_PROPS)); SrvWriteExchngBuf(exbuf, lpszResponse, 4096); return -1; } memcpy(((dFILE *)df)->rec_buf, recBuf, ((dFILE *)df)->rec_len); //((dFILE *)df)->rec_p = recNo; dseek((dFILE *)df, recNo-1, dSEEK_SET); //1999.12.21 absSyncDfBh( (dFILE *)df ); if( put1rec( (dFILE *)df ) == NULL ) { //error tscp.lp = ((dFILE *)df)->error; } else { tscp.msgType = 'D'; tscp.lp = 0; } memcpy(lpszResponse, &tscp, sizeof(TS_COM_PROPS)); SrvWriteExchngBuf(exbuf, lpszResponse, sizeof(TS_COM_PROPS)); return 0; } //end of asqlPutDbfRec()
/* * Set the process title so it's easy to see using ps(1) how much has been * done. */ void updateproctitle(struct disk *disks) { struct disk *dp; char *bp, *p; static char *buf; static size_t bufsize; size_t size; int inc, ret; double percent; bp = buf; size = bufsize; for (dp = disks; dp->device != NULL; dp++) { p = dp->device; if (strcmp(p, "*") == 0) continue; if (strncmp(p, _PATH_DEV, sizeof _PATH_DEV - 1) == 0) p += sizeof _PATH_DEV - 1; percent = 100 * (double)dseek(dp, 0, SEEK_CUR) / dp->size; if ((ret = snprintf(bp, size, "%s %.2f%%, ", p, percent)) < 0) ret = 0; if ((size_t)ret >= size) { inc = ((ret + 1023) >> 10) << 10; size += inc; bufsize += inc; if ((buf = reallocf(buf, bufsize)) == NULL) { /* Not fatal. */ syslog(LOG_NOTICE, "reallocf failure: %m"); bufsize = 0; return; } bp = buf + bufsize - size; ret = snprintf(bp, size, "%s %.2f%%, ", p, percent); if (ret < 0) ret = 0; } bp += ret; size -= ret; }
//#pragma argsused short PD_style _ASK_AppRec( OpndType *lpOpnd, short ParaNum, short *OpndTop, \ short *CurState ) { dFILE *tdf; int i; extern WSToMT FromToStru fFrTo; if( *CurState == 0 || *CurState == LASTWORKTIMEOFACTION ) { *OpndTop -= ParaNum; return 0; } if( xIsOpndField(&lpOpnd[0]) == 0 ) { i = xGetOpndLong(&lpOpnd[0]) - 1; if( i < 0 || i >= fFrTo.cSouDbfNum ) { ErrorSet.xERROR = iRefTabelErr; sprintf(ErrorSet.string, "apprec(%d)", i); return 1; } tdf = fFrTo.cSouFName[i]; } else { tdf = ((dFIELDWHENACTION *)lpOpnd[0].oval)->pTargetDfile; if( tdf == NULL ) return 1; } #ifdef WSToMT //lock it to avoid other thread move to the end for appending wmtDbfLock(tdf); #endif dseek(tdf, 0, dSEEK_END); if( fFrTo.phuf != NULL ) { tdf->rec_buf[0] = '*'; if( put1rec( tdf ) == NULL ) { wmtDbfUnLock(tdf); ErrorSet.xERROR = iFailFunCall; sprintf(ErrorSet.string, "calrec(%d)", tdf->error); return 1; } wmtDbfUnLock(tdf); tdf->rec_buf[0] = ' '; fseek(fFrTo.phuf, -4, SEEK_CUR); fwrite(&tdf, sizeof(dFILE *), 1, fFrTo.phuf); fwrite(&(tdf->rec_p), sizeof(long), 1, fFrTo.phuf); fwrite(tdf->rec_buf, tdf->rec_len, 1, fFrTo.phuf); fwrite("\0\0\0\0", sizeof(dFILE *), 1, fFrTo.phuf); } else { if( put1rec( tdf ) == NULL ) { wmtDbfUnLock(tdf); ErrorSet.xERROR = iFailWriteRec; sprintf(ErrorSet.string, "calrec(%d)", tdf->error); return 1; } } #ifdef WSToMT wmtDbfUnLock(tdf); #endif *OpndTop -= ParaNum; /* maintain the opnd stack */ return( 0 ); } /* end of function _ASK_AppRec() */
/* asqlBlobMemFetch() * *************************************************************************/ _declspec(dllexport) long asqlBlobMemFetch(TS_CLIENT_CURSOR *tscc, \ LPCSTR lpszUser, \ LPCSTR lpszUserDir,\ void *df, \ long recNo, \ LPSTR fieldName, \ EXCHNG_BUF_INFO *exbuf ) { TS_COM_PROPS tscp; unsigned short iw; char buf[4096]; char *sp; long memSize; memset(&tscp, 0, sizeof(TS_COM_PROPS)); while( tscc != NULL ) { if( tscc->p == (void *)df ) goto agdr_dfTrueR; tscc = tscc->pNext; } df = NULL; agdr_dfTrueR: tscp.packetType = 'R'; tscp.msgType = 'E'; tscp.len = 0; if( df == NULL || recNo <= 0 ) { tscp.lp = -1; SrvWriteExchngBuf(exbuf, &tscp, sizeof(TS_COM_PROPS)); return -1; } iw = GetFldid((dFILE *)df, fieldName); if( iw == 0xFFFF ) { tscp.lp = -4; SrvWriteExchngBuf(exbuf, &tscp, sizeof(TS_COM_PROPS)); return -4; } //((dFILE *)df)->rec_p = recNo; dseek((dFILE *)df, recNo-1, dSEEK_SET); if( get1rec((dFILE *)df) == NULL ) { tscp.lp = -4; SrvWriteExchngBuf(exbuf, &tscp, sizeof(TS_COM_PROPS)); return -4; } sp = blobToMem((dFILE *)df, iw, &memSize); if( sp != NULL ) { TS_COM_PROPS tscp1; // //tscp.leftPacket = '\1'; //no use: there are any other packet to transmit //tscp.endPacket = '\1'; //not end, DONNOT GIVE UP tscp1.packetType = 'R'; tscp1.msgType = 'B'; //tscp.lp = 0; SrvWriteExchngBufEx(exbuf, &tscp1, sp, memSize, 0); //come from readBtreeData(), free it with its function //free(sp); freeBlobMem((dFILE *)df, sp); //send a 'D' packet tscp.msgType = 'D'; tscp.lp = 0; SrvWriteExchngBuf(exbuf, &tscp, sizeof(TS_COM_PROPS)); return 0; } tscp.lp = -5; memcpy(buf, &tscp, sizeof(TS_COM_PROPS)); SrvWriteExchngBuf(exbuf, buf, sizeof(TS_COM_PROPS)); return -5; } //end of asqlBlobMemFetch()
/* asqlBlobPut() * *************************************************************************/ _declspec(dllexport) long asqlBlobPut(TS_CLIENT_CURSOR *tscc, LPCSTR lpszUser, \ LPCSTR lpszUserDir,\ void *df, \ long recNo, \ LPSTR fieldName, \ EXCHNG_BUF_INFO *exbuf ) { TS_COM_PROPS tscp; unsigned short iw; char buf[4096]; char szCn[128]; // int i; memset(&tscp, 0, sizeof(TS_COM_PROPS)); while( tscc != NULL ) { if( tscc->p == (void *)df ) goto agdr_dfTrueR; tscc = tscc->pNext; } df = NULL; agdr_dfTrueR: tscp.packetType = 'R'; tscp.msgType = 'E'; tscp.len = 0; if( df == NULL || recNo <= 0 ) { tscp.lp = -1; memcpy(buf, &tscp, sizeof(TS_COM_PROPS)); SrvWriteExchngBuf(exbuf, buf, sizeof(TS_COM_PROPS)); return -1; } iw = GetFldid((dFILE *)df, fieldName); if( iw == 0xFFFF ) { tscp.lp = -4; memcpy(buf, &tscp, sizeof(TS_COM_PROPS)); SrvWriteExchngBuf(exbuf, buf, sizeof(TS_COM_PROPS)); return -4; } if( lServerAsRunning ) { /*i = 32; GetComputerName(szCn, &i); i = MAXPATH; if( GetUserHomeDir(szCn, lpszUser, buf, &i) != 0 ) { tscp.packetType = 'R'; tscp.msgType = 'E'; tscp.len = 4096-sizeof(TS_COM_PROPS); tscp.lp = 0; memcpy(buf, &tscp, sizeof(TS_COM_PROPS)); strcpy(&buf[sizeof(TS_COM_PROPS)], "ERR:4 INF:No Thread service"); SrvWriteExchngBuf(exbuf, buf, 4096); return 4; }*/ strZcpy(buf, lpszUserDir, MAXPATH); beSurePath(buf); sprintf(szCn, "%s.DTM", fieldName); makefilename(buf, buf, szCn); } else { sprintf(buf, "%s.DTM", fieldName); } wmtDbfLock((dFILE *)df); //((dFILE *)df)->rec_p = recNo; dseek((dFILE *)df, recNo-1, dSEEK_SET); if( get1rec((dFILE *)df) == NULL ) { wmtDbfUnLock((dFILE *)df); tscp.lp = -4; memcpy(buf, &tscp, sizeof(TS_COM_PROPS)); SrvWriteExchngBuf(exbuf, buf, 4096); return -4; } if( (tscp.lp=dbtFromFile((dFILE *)df, iw, buf)) >= 0 ) { tscp.msgType = 'D'; } wmtDbfUnLock((dFILE *)df); memcpy(buf, &tscp, sizeof(TS_COM_PROPS)); SrvWriteExchngBuf(exbuf, buf, tscp.len+sizeof(TS_COM_PROPS)); return 0; } //end of asqlBlobPut()
/* asqlBlobMemPut() * *************************************************************************/ _declspec(dllexport) long asqlBlobMemPut(TS_CLIENT_CURSOR *tscc, \ LPCSTR lpszUser, \ LPCSTR lpszUserDir,\ void *df, \ long recNo, \ LPSTR fieldName, \ EXCHNG_BUF_INFO *exbuf ) { TS_COM_PROPS tscp; unsigned short iw; char *sp; long memSize; BOOL pbIfEnd; memset(&tscp, 0, sizeof(TS_COM_PROPS)); while( tscc != NULL ) { if( tscc->p == (void *)df ) goto agdr_dfTrueR; tscc = tscc->pNext; } df = NULL; agdr_dfTrueR: if( SrvReadExchngBufEx(exbuf, &sp, &memSize, &pbIfEnd) != 0 ) { tscp.lp = -5; SrvWriteExchngBuf(exbuf, &tscp, sizeof(TS_COM_PROPS)); return -5; } tscp.packetType = 'R'; tscp.msgType = 'E'; tscp.len = 0; if( df == NULL || recNo <= 0 ) { HANDLE hDataBuf; hDataBuf = LocalHandle(sp); LocalUnlock( hDataBuf ); LocalFree( hDataBuf ); tscp.lp = -1; SrvWriteExchngBuf(exbuf, &tscp, sizeof(TS_COM_PROPS)); return -1; } iw = GetFldid((dFILE *)df, fieldName); if( iw == 0xFFFF ) { HANDLE hDataBuf; hDataBuf = LocalHandle(sp); LocalUnlock( hDataBuf ); LocalFree( hDataBuf ); tscp.lp = -4; SrvWriteExchngBuf(exbuf, &tscp, sizeof(TS_COM_PROPS)); return -4; } //((dFILE *)df)->rec_p = recNo; dseek((dFILE *)df, recNo-1, dSEEK_SET); if( get1rec((dFILE *)df) == NULL ) { HANDLE hDataBuf; hDataBuf = LocalHandle(sp); LocalUnlock( hDataBuf ); LocalFree( hDataBuf ); tscp.lp = -4; SrvWriteExchngBuf(exbuf, &tscp, sizeof(TS_COM_PROPS)); return -4; } //2000.7.21 /* if( memSize < 0 ) { } else { blobFromMem((dFILE *)df, iw, sp, memSize); }*/ if( memSize >= 0 ) { blobFromMem((dFILE *)df, iw, sp, memSize); } { /////////////////////// HANDLE hDataBuf; hDataBuf = LocalHandle(sp); LocalUnlock( hDataBuf ); LocalFree( hDataBuf ); } tscp.msgType = 'D'; tscp.lp = 0; SrvWriteExchngBuf(exbuf, &tscp, sizeof(TS_COM_PROPS)); return 0; } //end of asqlBlobMemPut()
/* * Report a read error, logging how many bytes were trying to be read, which * sector they were being read from, and try to also find out what that sector * is used for. */ void logreaderror(struct disk *dp, int nbytes) { quad_t secno; off_t saved_offset; char newdev[512]; #ifdef DIOCGDINFO int fd, slice, part; struct dos_partition *dos; struct disklabel label; char buf[512]; #else /* DIOCGDINFO */ static size_t geomSize = 0; static char * geomConf = NULL; char * cp; static size_t partLen = 31; static char *part = NULL; quad_t relsec = -1; char *typefld = NULL; #endif /* DIOCGDINFO */ saved_offset = dseek(dp, 0, SEEK_CUR); secno = (quad_t)saved_offset / dp->secsize; dp->errors++; syslog(LOG_NOTICE, "error reading %d bytes from sector " QD " on %s", nbytes, secno, dp->device); #ifdef DIOCGDINFO /* * First, find out which slice it's in. To do this, we seek to the * start of the disk, read the first sector, and go through the DOS * slice table. */ if (dseek(dp, 0, SEEK_SET) == -1) { syslog(LOG_NOTICE, "could not seek to start of disk: %m"); exit(EXIT_FAILURE); } if (read(dp->fd, buf, sizeof buf) != sizeof buf) { dseek(dp, saved_offset, SEEK_SET); return; } /* seek back to where we were */ if (dseek(dp, saved_offset, SEEK_SET) == -1) { syslog(LOG_NOTICE, "could not seek to previous position" "after reading first sector: %m"); exit(EXIT_FAILURE); } // TODO: should validate DOS partition table (vs GPT or dedicated) dos = (struct dos_partition *)&buf[DOSPARTOFF]; for (slice = 0; slice < NDOSPART; slice++) if (dos[slice].dp_start <= secno && secno < dos[slice].dp_start + dos[slice].dp_size) break; if (slice == NDOSPART) { syslog(LOG_NOTICE, "sector " QD " on %s doesn't appear " "to be within any DOS slice", secno, dp->device); return; } /* Make secno relative to this slice */ secno -= dos[slice].dp_start; snprintf(newdev, sizeof newdev, "%ss%d", dp->device, slice + 1); syslog(LOG_DEBUG, "bad sector seems to be within %s", newdev); /* Check the type of that partition. */ if (dos[slice].dp_typ != DOSPTYP_386BSD) { /* If not a BSD slice, we can't do much more. */ syslog(LOG_NOTICE, "last bad sector is sector " QD " on device %s, type %02x", secno, newdev, dos[slice].dp_typ); return; } if ((fd = open(newdev, O_RDONLY)) < 0) { syslog(LOG_NOTICE, "open %s failure: %m", newdev); return; } /* Try to read the disklabel from that device. */ if (ioctl(fd, DIOCGDINFO, &label) < 0) { syslog(LOG_NOTICE, "DIOCGDINFO on %s failed: %m", newdev); return; } /* Check which partition this sector is in. */ for (part = 0; part < MAXPARTITIONS; part++) if (part != 2 && /* skip 'c' partition */ label.d_partitions[part].p_offset <= secno && secno < label.d_partitions[part].p_offset + label.d_partitions[part].p_size) break; if (part == MAXPARTITIONS) { syslog(LOG_NOTICE, "sector " QD " on %s doesn't appear " "to be within any BSD partition", secno, newdev); return; } secno -= label.d_partitions[part].p_offset; snprintf(newdev, sizeof newdev, "%ss%d%c", dp->device, slice + 1, 'a' + part); syslog(LOG_DEBUG, "bad sector seems to be within %s", newdev); if (label.d_partitions[part].p_fstype != FS_BSDFFS) { /* Again, if not a BSD partition, can't do much. */ syslog(LOG_NOTICE, "last bad sector is sector " QD " on device %s, type %s", secno, newdev, fstypename(label.d_partitions[part].p_fstype)); return; } #else /* DIOCGDINFO */ if (geomSize == 0) { sysctlbyname("kern.geom.conftxt", NULL, &geomSize, NULL, 0); if (geomSize <= 0) { printf("sysctlbyname() returned size = %d\n", geomSize); geomSize = 0; exit(EXIT_FAILURE); } geomConf = malloc(geomSize); if (geomConf == NULL) { printf("malloc(%d) returned NULL\n", geomSize); geomSize = 0; exit(EXIT_FAILURE); } if (sysctlbyname("kern.geom.conftxt", geomConf, &geomSize, NULL, 0) != 0) { perror("sysctlbyname()"); geomSize = 0; free(geomConf); geomConf = NULL; exit(EXIT_FAILURE); } } if (part == NULL) part = malloc(partLen + 1); for ( cp = geomConf ; *cp ; ++cp ) { // find line "0 DISK " matching current disk, using // strncmp because where cp points is not null-terminated // (All DISK lines, and only DISK lines, are at level 0.) // Magic numbers: 7 == strlen("0 DISK "); 5 == strlen("/dev/") if (strncmp(cp, "0 DISK ", 7) == 0 && strncmp(&cp[7], &dp->device[5], strlen(dp->device) - 5) == 0 && cp[7 + strlen(dp->device) - 5] == ' ') { for (;;) { // scan to end of line while (cp[1] && *cp != '\n') ++cp; ++cp; // start of next line // Find PART line containing the failed sector; // must be on same disk => stop upon finding // another DISK line. If more than one matching // PART -- due to nested geoms -- use the last // (innermost). if (*cp == '\0' || *cp == '0') break; // end of current DISK's entries // scan to end of level number while (cp[1] && *cp != ' ') ++cp; if (strncmp(cp, " PART ", 6) == 0) { char *pp = &cp[6]; int pl = strchr(pp, ' ') - pp; quad_t mediasize, offset; long secsize; cp = pp + pl; // cp -> mediasize mediasize = strtoq(cp, &cp, 10); secsize = strtol(cp, &cp, 10); mediasize /= secsize; cp = strchr(cp, 'o') + 1; offset = strtoq(cp, &cp, 10) / secsize; if (secno >= offset && (secno - offset) < mediasize) { if (pl > partLen) { part = realloc(part, pl+1); partLen = pl; } strncpy(part, pp, pl); part[pl] = '\0'; relsec = secno - offset; typefld = cp + 1; } } } } // scan to end of line while (cp[1] && *cp != '\n') ++cp; } //// printf("part %s, relsec %qd, typefld %p: %.27s\n", //// part, relsec, typefld, typefld); secno = relsec; strncpy(newdev, part, sizeof(newdev) - 1); newdev[sizeof(newdev) - 1] = '\0'; // paranoia #endif /* DIOCGDINFO */ syslog(LOG_NOTICE, "last bad sector is sector " QD " on 4.2BSD filesystem %s", secno, newdev); /* * XXX: todo: find out which file on the BSD filesystem uses this * sector... */ }