2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: fsDialog.c /main/6 1996/10/08 11:58:08 mustafa $ */
24 /************************************<+>*************************************
25 ****************************************************************************
29 * COMPONENT_NAME: Desktop File Manager (dtfile)
31 * Description: Containes routines to handle contents of dtfile.config
33 * FUNCTIONS: configFileName
44 * (c) Copyright 1993, 1994, 1995 Hewlett-Packard Company
45 * (c) Copyright 1993, 1994, 1995 International Business Machines Corp.
46 * (c) Copyright 1993, 1994, 1995 Sun Microsystems, Inc.
47 * (c) Copyright 1993, 1994, 1995 Novell, Inc.
49 ****************************************************************************
50 ************************************<+>*************************************/
52 /*---------------------------------------------------------------------------------
54 * fsDialogAvailable (String path, dtFSData *fsDialogData)
56 * For the file specified by path, determine if there is a properties
57 * dialog specific to the file system that the file is on.
58 * For example, if the file is in AFS there might be a dialog to edit
59 * the Access Control List. fsDialogData is filled if there is a dialog.
60 * path must not include host:
62 * If any errors are encountered, FALSE is returned and no other action is taken
63 * or message displayed.
65 *--------------------------------------------------------------------------------*/
74 #include <Dt/UserMsg.h> /* for DtSimpleError */
83 /*-----------------------------------------------------
84 * Configuration file search order is:
86 * $DTFSCONFIG (meant to be used for debugging)
87 * $HOME/CONFIGFILENAME
88 * SYSCONFIGFILEDIR/CONFIGFILENAME
89 * DEFCONFIGFILEDIR/$LANG/CONFIGFILENAME
90 * DEFCONFIGFILEDIR/C/CONFIGFILENAME
92 * The function configFileName() determines the correct
93 * name. It will apply $LANG where appropriate.
95 *-----------------------------------------------------*/
97 #define SYSCONFIGFILEDIR CDE_CONFIGURATION_TOP "/config"
98 #define DEFCONFIGFILEDIR CDE_INSTALLATION_TOP "/config"
99 #define CONFIGFILENAME "dtfile.config"
100 #define DEFCONFIGFILENAME CDE_INSTALLATION_TOP "/config/C/dtfile.config"
102 /*--------------------------------------------------------
103 Platform-specific includes required for getFSType()
104 *--------------------------------------------------------*/
110 #include <sys/types.h>
111 #include <sys/statvfs.h>
118 /*----------------------
120 *----------------------*/
123 char g_errorMessage[EMSGMAX];
126 /*--------------------
128 *--------------------*/
130 static void getFSType (const String path,
133 static void readConfigFile (const String fsType,
134 const String platform,
135 dtFSData * fsDialogData,
136 Boolean * dialogAvailable);
137 static String configFileName (void);
138 static void readFSID (FILE * fptr,
140 const String platform,
142 static void readDialogData (FILE * fptr,
144 Boolean * dialogAvailable,
145 dtFSData * fsDialogData);
146 static int readLine (FILE * fptr, String line);
147 static int stricmp (const String s1, const String s2);
148 static String strip (String s);
149 static Boolean configFileOK(void);
152 /*----------------------
154 *----------------------*/
157 fsDialogAvailable (const String path, dtFSData *fsDialogData)
160 char fsType[MAXLINELENGTH], platform[MAXLINELENGTH];
161 Boolean dialogAvailable;
163 DPRINTF(("fsDialogAvailble: checking path \"%s\"\n",path));
164 if ( ! configFileOK())
167 getFSType(path, fsType, platform);
168 DPRINTF((" fsType=\"%s\"\n platform=\"%s\"\n",fsType,platform));
170 if (strlen(fsType) == 0)
174 readConfigFile(fsType, platform, fsDialogData, &dialogAvailable);
177 strcpy (fsDialogData->path,path);
179 return dialogAvailable;
185 /*--------------------------------------------------------------------------------
189 * is the configuration file accessible?
191 *------------------------------------------------------------------------------*/
202 fname = configFileName();
203 err = stat(fname, &buf);
204 DPRINTF((" config file \"%s\" stat ret=%i\n",fname,err));
210 msg1 = GETMESSAGE(21, 22, "Cannot open file manager configuration file: ");
211 msg2 = strerror(errno);
212 sprintf(g_errorMessage,"%s%s\n %s\n",msg1,fname,msg2);
213 _DtSimpleError (application_name, DtError, NULL, g_errorMessage, NULL);
217 } /* end configFileOK */
220 /*--------------------------------------------------------------------------------
224 * Do the platform-specific work required to determine what type of file system
225 * the file defined by path is on. Return strings defining the file system type
226 * and the platform. Any errors result in a fsType set to the null string.
228 * Both fsType and platform are allocated by the caller
230 * The strings used in platform and fsType must match those used in
231 * the configuration file.
233 *--------------------------------------------------------------------------------*/
235 static void getFSType(const String path,
244 strncpy(platform,"aix",MAXLINELENGTH);
245 if (lstat(path, &buf) == 0)
246 sprintf(fsType,"%i",buf.st_vfstype);
248 strncpy(fsType,"",MAXLINELENGTH);
255 strncpy(platform,"sunos",MAXLINELENGTH);
256 if (statvfs(path, &buf) == 0)
257 strncpy(fsType,buf.f_basetype,MAXLINELENGTH);
259 strncpy(fsType,"",MAXLINELENGTH);
266 strncpy(platform,"hpux",MAXLINELENGTH);
267 if (statfs(path, &buf) == 0)
268 sprintf(fsType,"%li",buf.f_fsid[1]);
270 strncpy(fsType,"",MAXLINELENGTH);
274 strncpy(platform,"unknown",MAXLINELENGTH);
275 strncpy(fsType, "",MAXLINELENGTH);
276 #endif /* unknown platform */
280 } /* end getFSType */
283 /*--------------------------------------------------------------------------------
287 * Given the platform and type of file system, read the configuration file to
288 * determine if there is a file-system specific dialog. If there is, fill
289 * fsDialogData. If there is no file or if the file has no entry for
290 * platform:fsType, dialogAvailable is set to FALSE.
292 * The configuration file consists of two parts. The first is a list of entries
293 * (ending with "end") of the form
295 * platform:file-system-type=file-system-id
297 * where platform is one of the strings from getFSType(), file-system-type is
298 * a (platform-dependent) string identifying the type of file system, and
299 * file-system-id is a string used in the configuration file to identify the
300 * file system. The second part of the file consists of lists of attributes
301 * (in the form name = value, one per line) for each of the file system id's.
302 * Blank lines and lines beginning with * are ignored as is case. A example
305 * -------------------------------------------------
306 * * sample dtfs configuration file
313 * afs: buttonlabel = Change AFS ACL ...
314 * fsDialog = modAttrAFS
315 * warning = File system access may be further restriced by AFS ACLs
317 * nfs: buttonLabel = Change NFS attributes ...
318 * fsDialog = <configuration-location>/bin/modNFSAttr
319 * -------------------------------------------------
321 *--------------------------------------------------------------------------------*/
324 readConfigFile(const String fsType,
325 const String platform,
326 dtFSData * fsDialogData,
327 Boolean * dialogAvailable)
329 char fsID[MAXLINELENGTH];
331 String fname, msg1, msg2;
334 *dialogAvailable = FALSE;
336 fname = configFileName();
337 fptr = fopen(fname,"r");
340 msg1 = GETMESSAGE(21, 22, "Cannot open file manager configuration file: ");
341 msg2 = strerror(errno);
342 sprintf(g_errorMessage,"%s%s\n %s\n",msg1,fname,msg2);
343 _DtSimpleError (application_name, DtError, NULL, g_errorMessage, NULL);
347 readFSID(fptr, fsType, platform, fsID);
348 DPRINTF((" fsID=\"%s\"\n",fsID));
350 readDialogData(fptr, fsID, dialogAvailable, fsDialogData);
352 /* make sure that a dialog program has been specified or execl will do unfortunate things */
353 if (strlen(fsDialogData->fsDialogProgram) == 0)
355 *dialogAvailable = FALSE;
356 if (strlen(fsDialogData->buttonLabel) != 0)
358 msg1 = XtNewString(GETMESSAGE(21, 29, "No value was provided for the fsDialog field in dtfile's configuration file"));
359 _DtSimpleError (application_name, DtError, NULL, msg1, NULL);
367 } /* end readConfigFile */
370 /*--------------------------------------------------------------------------------
374 * return the name of the configuration file which defines file-system
375 * specific dialogs ... a hierarchy of names is searched until a file
376 * is found ... no checking is done to see if it can be read
378 *------------------------------------------------------------------------------*/
387 static char fn[MAX_PATH]=""; /* remember name once its been determined */
390 if (strlen(fn) != 0) return fn; /* has filename been determined already? */
392 for (i=0; i < 4; i++)
396 case 0: /* file name $DTFSCONFIG */
397 if ( (s=getenv("DTFSCONFIG")) != NULL) /* a convenience for debugging */
398 strncpy(fn,s,MAX_PATH);
399 else /* DTFSCONFIG not defined */
403 case 1: /* $HOME/dtfile.config */
404 if ( (s=getenv("HOME")) != NULL)
406 strncpy(fn,s,MAX_PATH);
408 strncat(fn,CONFIGFILENAME,MAX_PATH-strlen(fn)-1);
410 else /* $HOME not defined */
414 case 2: /* SYSCONFIGFILEDIR, e.g. /etc/dt/config/dtfile.config */
415 strncpy(fn,SYSCONFIGFILEDIR,MAX_PATH);
417 strncat(fn,CONFIGFILENAME,MAX_PATH-strlen(fn)-1);
420 case 3: /* DEFCONFIGFILEDIR, e.g. /usr/dt/config/C/dtfile.config */
421 strncpy(fn,DEFCONFIGFILEDIR,MAX_PATH);
423 if ( (s=getenv("LANG")) != NULL)
425 strncat(fn,s,MAX_PATH-strlen(fn)-1);
430 strncat(fn,"C",MAX_PATH-strlen(fn)-1);
433 strncat(fn,CONFIGFILENAME,MAX_PATH-strlen(fn)-1);
437 err = stat(fn, &buf);
438 DPRINTF((" config file \"%s\" stat ret=%i\n",fn,err));
440 if (err == 0) /* file is found */
443 } /* end loop over possible config files */
445 /* didn't find any of the files (this should never, ever happen) */
446 /* return the name of the factory default (case 3 above) which should always be there */
448 strncpy(fn,DEFCONFIGFILENAME,MAX_PATH);
452 } /* end configFileName */
455 /*--------------------------------------------------------------------------------
459 * get the file-system identifier from the configuration file
461 * fptr refers to an open configuration file
462 * fsType and platform identify the platfrom (aix, hpux, sunos, etc)
463 * and file-system type (afs, nfs, dfs, etc.)
464 * fsID is filled by matching platform:fsType with with information in the
465 * file and reading the id; the string comparisons are case insensitive
466 * if there is more than one match, the last fsID found will be returned;
467 * if no match is found, fsID is returned as ""
468 * upon conclusion, the file is positioned past the "end" record
470 *------------------------------------------------------------------------------*/
473 readFSID ( FILE * fptr,
475 const String platform,
479 char line[MAXLINELENGTH];
480 String pform, type, id;
482 String lineIn, lineOut;
487 while ( (lineLength=readLine(fptr,line)) != EOF &&
488 stricmp(line,"end") != 0 )
490 /* readLine has changed all white space to blanks ... now remove
491 the blanks as they are not significant here */
492 for (lineIn = lineOut = line; *lineIn != '\0'; lineIn++)
500 pform = strtok(line,":");
501 type = strtok(NULL,"=");
502 id = strtok(NULL," ");
503 if (stricmp(pform,platform)==0 && stricmp(type,fsType)==0)
504 strncpy(fsID,id,MAXLINELENGTH);
512 /*--------------------------------------------------------------------------------
516 * fill dtFSData with information from the configuration file; set
519 * fsID is a file-system identifier defined, in the configuration file,
520 * by a platform:file-system-type pair. The configuration file is
521 * searched from its current position until a definition section
522 * for fsID is found. The string comparison is case insensitive; if more
523 * than one match is found, the last in the file is used. The fields in
524 * dtFSData are initialized (e.g. string fields are set to "") if no
525 * matches are found or if no match is found for a particular field.
526 * Upon conclusion, the file is positioned at EOF.
528 *------------------------------------------------------------------------------*/
531 readDialogData( FILE * fptr,
533 Boolean * dialogAvailable,
534 dtFSData * fsDialogData)
539 String s, id, token1, token2;
541 char line[MAXLINELENGTH];
544 *dialogAvailable = FALSE;
546 /* initialize fields in fsDialogData */
547 strcpy(fsDialogData->buttonLabel,"");
548 strcpy(fsDialogData->fsDialogProgram,"");
549 strcpy(fsDialogData->warningMessage,"");
550 fsDialogData->dismissStdPermissionDialog = FALSE;
552 if (strlen(fsID) == 0)
555 /* loop over lines in the file; note that readLine is called
556 from within the loop except for the first pass */
557 for (lineLength=readLine(fptr,line); lineLength != EOF; )
559 id = strtok(line,":");
560 if (stricmp(id,fsID) == 0)
562 /* a section matching the input fsID has been found */
563 *dialogAvailable = TRUE;
564 token1 = strtok(NULL," =");
565 s = strchr(token1,'\0') + 1; /* first character after token1 */
566 token2 = &s[strspn(s," =")]; /* first non-blank, non-= after token1 */
567 /* loop to get data for fields in fsDialogData */
568 while(strchr(token1,':') == NULL && lineLength != EOF)
570 if (stricmp(token1,"buttonlabel") == 0)
571 strncpy(fsDialogData->buttonLabel,token2,MAXLINELENGTH);
572 else if (stricmp(token1,"warning") == 0)
574 strncpy(fsDialogData->warningMessage,token2,MAXLINELENGTH);
576 else if (stricmp(token1,"fsdialog") == 0)
577 strncpy(fsDialogData->fsDialogProgram,token2,MAXLINELENGTH);
578 else if (stricmp(token1,"dismiss") == 0)
579 fsDialogData->dismissStdPermissionDialog = (stricmp(token2,"yes") == 0);
582 msg1 = GETMESSAGE(21, 24, "Unknown field label in file manager configuration file: ");
583 sprintf(g_errorMessage,"%s\"%s\"\n",msg1,token1);
584 _DtSimpleError (application_name, DtWarning, NULL, g_errorMessage, NULL);
586 lineLength = readLine(fptr,line);
587 if (lineLength != EOF)
589 token1 = strtok(line," =");
590 s = strchr(token1,'\0') + 1;
591 token2 = &s[strspn(s," =")];
597 /* the current line does not match fsID ... get next line */
598 lineLength = readLine(fptr,line);
602 if ( ! *dialogAvailable )
604 msg1 = GETMESSAGE(21, 25, "No information found in file manager configuration file for file-system identifier");
605 sprintf(g_errorMessage,"%s \"%s\"\n",msg1,fsID);
606 _DtSimpleError (application_name, DtError, NULL, g_errorMessage, NULL);
609 } /* end readDialogData */
612 /*--------------------------------------------------------------------------------
616 * read a line from the stream pointed to by fptr and return it in line
617 * line is allocated by the caller
619 * blank lines and lines starting with * are skipped
620 * leading and trailing white space is removed
621 * imbedded white space characters are changed to blanks
622 * imbedded "\n" is changed to space, newline
623 * the length of the line or EOF (on end-of-file or error) is returned
625 *------------------------------------------------------------------------------*/
628 readLine(FILE * fptr, String line)
631 const char commentChar = '#';
632 char myLine[MAXLINELENGTH];
638 if ( fgets(myLine,MAXLINELENGTH,fptr) == NULL)
642 s = strip(myLine); /* remove leading & trailing whitespace */
643 if ((len=strlen(s)) != 0 && s[0] != commentChar)
645 /* change imbedded white space characters to spaces */
646 for (i=0; i<len; i++)
650 /* change any imbedded "\n" to space followed by newline */
651 while ( (t=strstr(s,"\\n")) != NULL )
653 *t = ' '; /* space */
654 *(t+1) = '\n'; /* new line */
657 strncpy(line,s,MAXLINELENGTH);
666 /*--------------------------------------------------------------------------------
670 * compare strings ignoring case, return value as in strcmp
672 *------------------------------------------------------------------------------*/
675 stricmp(const String s1, const String s2)
680 for (i=0; tolower(s1[i]) == tolower(s2[i]); i++)
684 return (tolower(s1[i]) > tolower(s2[i])) ? +1 : -1;
689 /*--------------------------------------------------------------------------------
693 * remove trailing white space by inserting \0
694 * return a pointer to the first non-white space character
695 *------------------------------------------------------------------------------*/
703 for (i=(strlen(s)-1); isspace(s[i]) && i>=0; i--)
707 for (i=0; isspace(s[i]); i++)
720 main(int argc, char **argv)
729 strcpy(pwd, argv[1]);
733 getcwd(pwd,sizeof(pwd));
736 printf("testing file \"%s\"\n",pwd);
737 test = fsDialogAvailable(pwd, &data);
740 printf("dialog is available\n");
741 printf(" buttonLabel=\"%s\"\n",data.buttonLabel);
742 printf(" fsDialogProgram=\"%s\"\n",data.fsDialogProgram);
746 printf("dialog not available\n");