/* * chkfontpath - utility for manipulating X Font Server font paths * * Copyright (C) 1998-2003 Red Hat, Inc. * Author: Preston Brown * * 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 library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include /* For variadic functions */ #include #include #include #include #include #include #include #include #define XFS_CONFIGFILE "/etc/X11/fs/config" #define XFS_CONFIGBACKUP "/etc/X11/fs/config-" #define XFS_PIDFILE "/var/run/xfs.pid" #define XFS_SUBSYSLOCK "/var/lock/subsys/xfs" static char *progName; static const char **fpList; static int fpCount; static int quiet; static int firstdir; void fatalerror(const char *format, ...) { va_list args; if(!quiet) { va_start(args, format); vfprintf(stderr, format, args); va_end(args); } exit((quiet) ? EXIT_SUCCESS : EXIT_FAILURE); } void readFontPath(void) { FILE *f; char buf[251]; char *s, *p, *q; int catFlag = 0; int noFirstLine = 0; if (NULL == (f = fopen(XFS_CONFIGFILE, "r"))) fatalerror("%s: error opening %s\n", progName, XFS_CONFIGFILE); while ((q = s = fgets(buf, sizeof(buf)-1, f)) != NULL) { /* strip leading white space */ while (isblank(*s)) s++; /* strip trailing white space */ p = s + strlen(s); while (p > s && isspace(p[-1])) p--; *p = '\n'; *(p+1) = '\0'; /* skip all comment lines */ if (*s == '#') continue; /* find the catalogue line */ if (strstr(s, "catalogue") && !catFlag) { catFlag = 1; if (NULL == (p = strchr(s, '='))) fatalerror("%s: error locating '=' after catalogue token\n", progName); p++; while (isblank(*p)) p++; s = p; } #ifdef DEBUG printf("catFlag: %d, q: %c, string: %s\n", (catFlag?1:0),*q, q); #endif if (catFlag) { if ((s[0] == '\n') && (fpCount == 0)) { /* situation where no path on same line as catalogue */ noFirstLine = 1; continue; } if (!isblank(*q) && noFirstLine) { /* *in the case where there are no font paths, a non-blank line * indicates the beginning of a new directive, so we need to leave * catalogue mode. */ catFlag = 0; continue; } } if (catFlag) { fpCount++; p = strdup(s); if (p[strlen(p)-1] == '\n') p[strlen(p)-1] = '\0'; if (p[strlen(p)-1] == ',') p[strlen(p)-1] = '\0'; if (NULL == (fpList = (const char **) realloc(fpList, sizeof(char *) * fpCount))) { fprintf(stderr, "chkfontpath: realloc() failed in readFontPath()\n"); exit(EXIT_FAILURE); } fpList[fpCount - 1] = p; } if (catFlag && (s[strlen(s)-2] != ',')) catFlag = 0; } fclose(f); } void writeNewConfig(void) { FILE *f, *f1; char buf[250]; char *s, *p; int catFlag = 0, i; struct stat sb; stat(XFS_CONFIGFILE, &sb); if (NULL == (f = fopen(XFS_CONFIGFILE, "r"))) fatalerror("%s: error opening %s for reading\n", progName, XFS_CONFIGFILE); if (NULL == (f1 = fopen(XFS_CONFIGBACKUP, "w"))) fatalerror("%s: error opening %s for writing\n", progName, XFS_CONFIGBACKUP); while ((s = fgets(buf, sizeof(buf), f)) != NULL) { p = s; /* strip leading white space */ while (isblank(*s)) s++; /* skip all comment lines */ if (*s == '#') { fputs(s, f1); continue; } if (strstr(s, "catalogue") && !catFlag) { catFlag = 1; p = strchr(s, '='); if (NULL == (p = strchr(s, '='))) fatalerror("%s: error locating '=' after catalog token\n", progName); for (i = 1; i <= fpCount; i++) { if (i == 1) fprintf(f1, "catalogue = %s",fpList[0]); else fprintf(f1, "\t%s",fpList[i-1]); if (i == fpCount) fprintf(f1, "\n"); else fprintf(f1, ",\n"); } } if (!catFlag) fputs(s, f1); if (catFlag && (s[0] == '\n' || s[strlen(s)-2] != ',')) { catFlag = 0; } } fclose(f); fclose(f1); unlink(XFS_CONFIGFILE); rename(XFS_CONFIGBACKUP, XFS_CONFIGFILE); chmod(XFS_CONFIGFILE, sb.st_mode); } void addDir(const char *newDir) { int i, last = -1; int firstType, secondType; int first = -1, second = -1; int type, prefixLen, fixDirLen; FILE *f; char *fontsdir; char *fixDir = strdup(newDir); fixDirLen = strlen(fixDir); if (fixDir[fixDirLen - 1] == '/') { fixDir[fixDirLen - 1] = '\0'; fixDirLen--; } if (fixDirLen > 10 && !strcmp(fixDir + fixDirLen - 9, ":unscaled")) { fixDir[fixDirLen - 9] = '\0'; fixDirLen -= 9; } if (fixDir[0] != '/') fatalerror("%s: font directories must be absolute, not adding %s\n", progName, fixDir); fontsdir = (char *) malloc(sizeof(char *) * (strlen(fixDir) + 12)); sprintf(fontsdir, "%s/fonts.dir", fixDir); if (NULL == (f = fopen(fontsdir, "r"))) fatalerror("%s: error opening %s, unwilling to add path\n", progName, fontsdir); fclose(f); free(fontsdir); prefixLen = strrchr(fixDir, '/') + 1 - fixDir; if (!strcmp (fixDir + prefixLen, "misc")) { firstType = 0; secondType = 3; } else if (!strcmp (fixDir + prefixLen, "75dpi")) { firstType = 1; secondType = 5; } else if (!strcmp (fixDir + prefixLen, "100dpi")) { firstType = 2; secondType = 6; } else { firstType = 100; secondType = 4; } for (i = 0; i < fpCount; i++) { if (strncmp(fpList[i], fixDir, prefixLen) != 0) continue; if (strncmp(fpList[i], fixDir, fixDirLen) == 0 && (fpList[i][fixDirLen] == '\0' || strcmp(fpList[i] + fixDirLen, ":unscaled") == 0)) { fatalerror("%s: %s already in list\n",progName, fixDir); } last = i; if (!strcmp (fpList[i] + prefixLen, "misc:unscaled")) type = 0; else if (!strcmp (fpList[i] + prefixLen, "75dpi:unscaled")) type = 1; else if (!strcmp (fpList[i] + prefixLen, "100dpi:unscaled")) type = 2; else if (!strcmp (fpList[i] + prefixLen, "misc")) type = 3; else if (!strcmp (fpList[i] + prefixLen, "75dpi")) type = 5; else if (!strcmp (fpList[i] + prefixLen, "100dpi")) type = 6; else type = 4; if (first == -1 && firstType < type) first = i; if (second == -1 && secondType < type) second = i; } if (last == -1) last = fpCount; else last++; if (first == -1 && firstType < 10) first = last; if (second == -1) second = last; if (firstdir) { if (firstType < 10) first = 0; second = 0; } fpCount += (firstType < 10) ? 2 : 1; fpList = (const char **) realloc(fpList, sizeof(char *) * fpCount); if (firstType < 10) { char *unspecDir; memmove(fpList + first + 1, fpList + first, sizeof(char *) * (fpCount - 1 - first)); unspecDir = (char *) malloc(fixDirLen + 11); sprintf(unspecDir, "%s:unscaled", fixDir); fpList[first] = unspecDir; second++; } memmove(fpList + second + 1, fpList + second, sizeof(char *) * (fpCount - 1 - second)); fpList[second] = fixDir; } void removeDir(const char *delDir) { int found = 0; int i; char *newDir = strdup(delDir); int newDirLen; if (newDir[strlen(newDir)-1] == '/') newDir[strlen(newDir)-1] = '\0'; newDirLen = strlen(newDir); for (i = 0; i < fpCount; i++) { if (strncmp(fpList[i], newDir, newDirLen) == 0 && (fpList[i][newDirLen] == '\0' || strcmp(fpList[i] + newDirLen, ":unscaled") == 0)) { found = 1; if (i < fpCount-1) memmove(fpList + i, fpList + i + 1, sizeof(char *) * (fpCount-i-1)); fpCount--; i--; } } if (!found) fatalerror("%s: %s not found in list\n",progName, newDir); free(newDir); } #define MAXPIDBUF 32 void restartXfs(void) { struct stat st; FILE *pidfile; pid_t pid; char buf[MAXPIDBUF]; /* Make sure /proc is mounted, and /sbin/pidof exists */ if ((stat("/proc/version", &st) == 0) && (stat("/sbin/pidof", &st) == 0)) { system("kill -USR1 `/sbin/pidof xfs` >/dev/null 2>&1"); /* If not, then test if xfs subsystem is locked, and there is a pid file */ } else if ((stat(XFS_SUBSYSLOCK, &st) == 0) && (stat(XFS_PIDFILE, &st) == 0)) { if (NULL != (pidfile = fopen(XFS_PIDFILE, "r"))) { fgets(buf, sizeof(buf), pidfile); fclose(pidfile); if(NULL != buf) pid = (pid_t) atol(buf); if(pid > 1) kill(pid, SIGUSR1); } } } void listPaths(void) { int i; if (fpCount == 0) printf("No directories currently in font path."); else { printf("Current directories in font path:\n"); for (i = 0; i < fpCount; i++) printf("%d: %s\n",i+1, fpList[i]); } } void listFP(void) { int i; if (fpCount == 0) fprintf(stderr, "Font path is currently empty."); else { for (i = 0; i < fpCount; i++) printf("%s\n", fpList[i]); } } int main(int argc, const char **argv) { int rc, list = 0, listfp = 0, help = 0; poptContext optCon; char *newDir = NULL, *delDir = NULL; const struct poptOption options[] = { { "add", 'a', POPT_ARG_STRING, &newDir, 0, "add directory to font path", "name of directory to add" }, { "remove", 'r', POPT_ARG_STRING, &delDir, 0, "remove directory from font path", "name of directory to remove" }, { "list", 'l', 0, &list, 0, "list all directories in font path", NULL }, { "listfp", 'm', 0, &listfp, 0, "display list of font path elements in machine parseable form", NULL }, { "quiet", 'q', 0, &quiet, 0, "quiet operation; don't print anything to the screen", NULL }, { "first", 'f', 0, &firstdir, 0, "--add puts the directory first (not last) in the path", NULL }, { "help", 'h', 0, &help, 0, "show this help", NULL }, { 0, 0, 0, 0, 0, NULL, NULL } }; setlocale(LC_ALL, ""); progName = basename((char *) argv[0]); if (*progName == '/') progName++; optCon = poptGetContext(progName, argc, argv, options, 0); poptReadDefaultConfig(optCon, 1); if ((rc = poptGetNextOpt(optCon)) < -1) { fprintf(stderr, "%s: bad argument %s: %s\n", progName, poptBadOption(optCon, POPT_BADOPTION_NOALIAS), poptStrerror(rc)); poptPrintUsage(optCon, stdout, 0); exit(1); } if (poptGetArg(optCon)) { fprintf(stderr, "%s: unexpected argument\n", progName); poptPrintUsage(optCon, stdout, 0); exit(1); } if (help) { poptPrintHelp(optCon, stdout, 0); exit(0); } poptFreeContext(optCon); readFontPath(); if (argc == 1 || listfp ) listFP(); if ( list ) listPaths(); if (newDir != NULL) { addDir(newDir); } if (delDir != NULL) { removeDir(delDir); } if (newDir != NULL || delDir != NULL) { writeNewConfig(); restartXfs(); } return 0; }