1 /*
2     OWFS -- One-Wire filesystem
3     OWHTTPD -- One-Wire Web Server
4     Written 2003 Paul H Alfille
5     email: paul.alfille@gmail.com
6     Released under the GPL
7     See the header file: ow.h for full attribution
8     1wire/iButton system from Dallas Semiconductor
9 */
10 
11 /* ow_opt -- owlib specific command line options processing */
12 
13 
14 #include <config.h>
15 #include "owfs_config.h"
16 #include "ow.h"
17 
ReadAliasFile(const ASCII * file)18 GOOD_OR_BAD ReadAliasFile(const ASCII * file)
19 {
20 	FILE *alias_file_pointer ;
21 
22 	/* getline parameters. allocated and reallocated by getline. use free rather than owfree */
23 	char * alias_line = NULL ;
24 	size_t alias_line_length ;
25 	int line_number = 0;
26 
27 	/* try to open file for reading */
28 	alias_file_pointer = fopen(file, "r");
29 	if ( alias_file_pointer == NULL ) {
30 		ERROR_DEFAULT("Cannot process alias file %s", file);
31 		return gbBAD;
32 	}
33 
34 	/* read each line and parse */
35 	while (getline(&alias_line, &alias_line_length, alias_file_pointer) >= 0) {
36 		++line_number;
37 		BYTE sn[SERIAL_NUMBER_SIZE] ;
38 		char * a_line = alias_line ; // pointer within the line
39 		char * sn_char = NULL ; // pointer to serial number
40 		char * name_char = NULL ; // pointer to alias name
41 
42 		while ( a_line ) {
43 			sn_char = strsep( &a_line, "/ \t=\n");
44 			if ( strlen(sn_char)>0 ) {
45 				// non delim char
46 				break ;
47 			}
48 		}
49 
50 		if ( Parse_SerialNumber(sn_char, sn) != sn_valid ) {
51 			LEVEL_CALL("Problem parsing device name in alias file %s:%d",file,line_number) ;
52 			continue ;
53 		}
54 
55 		if ( a_line ) {
56 			a_line += strspn(a_line," \t=") ;
57 		}
58 		while ( a_line ) {
59 			name_char = strsep( &a_line, "\n");
60 			size_t len = strlen(name_char) ;
61 			if ( len > 0 ) {
62 				while ( len>0 ) {
63 					if ( name_char[len-1] != ' ' && name_char[len-1] != '\t' ) {
64 						break ;
65 					}
66 					name_char[--len] = '\0'  ;
67 				}
68 				Test_and_Add_Alias( name_char, sn) ;
69 				break ;
70 			}
71 		}
72 	}
73 	if ( alias_line != NULL ) {
74 		free(alias_line) ; // not owfree since allocated by getline
75 	}
76 	fclose(alias_file_pointer);
77 	return gbGOOD;
78 }
79 
80 /* Name is a null-terminated string */
81 /* sn is an 8-byte serial number */
82 /* 1. Trims name
83  * 2. Checks name length
84  * 3. Refuses reserved words
85  * 4. Refuses path separator (/)
86  * 5. Removes any old assignments to name or serial number
87  * 6. Add new alias
88  * */
Test_and_Add_Alias(char * name,BYTE * sn)89 GOOD_OR_BAD Test_and_Add_Alias( char * name, BYTE * sn )
90 {
91 	BYTE sn_stored[SERIAL_NUMBER_SIZE] ;
92 	size_t len ;
93 
94 	// Parse off initial spaces
95 	while ( name[0] == ' ' ) {
96 		++name ;
97 	}
98 
99 	// parse off trailing spaces
100 	for ( len = strlen(name) ; len > 0 && name[len-1]==' ' ; ) {
101 		-- len ;
102 		name[len] = '\0' ;
103 	}
104 
105 	// zero length allowed -- will delete this entry.
106 
107 	// Check length
108 	if ( len > PROPERTY_LENGTH_ALIAS ) {
109 		LEVEL_CALL("Alias too long: sn=" SNformat ", Alias=%s, Length=%d, Max length=%d", SNvar(sn), name,  (int) len, PROPERTY_LENGTH_ALIAS ) ;
110 		return gbBAD ;
111 	}
112 
113 	// Reserved word?
114 	if ( strcmp( name, "interface" )==0
115 	|| strcmp( name, "settings" )==0
116 	|| strcmp( name, "uncached" )==0
117 	|| strcmp( name, "unaliased" )==0
118 	|| strcmp( name, "text" )==0
119 	|| strcmp( name, "alarm" )==0
120 	|| strcmp( name, "statistics" )==0
121 	|| strcmp( name, "simultaneous" )==0
122 	|| strcmp( name, "structure" )==0
123 	|| strncmp( name, "bus.", 4 )==0
124 	) {
125 		LEVEL_CALL("Alias attempts to redefine reserved filename: %s",name ) ;
126 		return gbBAD ;
127 	}
128 
129 	// No path separator allowed in name
130 	if ( strchr( name, '/' ) ) {
131 		LEVEL_CALL("Alias contains confusing path separator \'/\': %s",name ) ;
132 		return gbBAD ;
133 	}
134 
135 	// Is there another assignment for this alias name already?
136 	if ( GOOD( Cache_Get_Alias_SN( name, sn_stored ) ) ) {
137 		if ( memcmp( sn, sn_stored, SERIAL_NUMBER_SIZE ) == 0 ) {
138 			// repeat assignment
139 			return gbGOOD ;
140 		}
141 		// delete old serial number
142 		LEVEL_CALL("Alias %s reassigned from "SNformat" to "SNformat,name,SNvar(sn_stored),SNvar(sn)) ;
143 		Cache_Del_Alias(sn_stored) ;
144 	}
145 
146 	// Delete any prior assignments for this serial number
147 	Cache_Del_Alias(sn) ;
148 
149 	// Now add
150 	return Cache_Add_Alias( name, sn) ;
151 }
152 
FS_dir_entry_aliased(void (* dirfunc)(void *,const struct parsedname *),void * v,const struct parsedname * pn)153 void FS_dir_entry_aliased(void (*dirfunc) (void *, const struct parsedname *), void *v, const struct parsedname *pn)
154 {
155 	if ( ( pn->state & ePS_unaliased ) == 0 ) {
156 		// Want alias substituted
157 		struct parsedname s_pn_copy ;
158 		struct parsedname * pn_copy = & s_pn_copy ;
159 
160 		ASCII path[PATH_MAX+3] ;
161 		ASCII * path_pointer = path ; // current location in original path
162 
163 		// Shallow copy
164 		memcpy( pn_copy, pn, sizeof(struct parsedname) ) ;
165 		pn_copy->path[0] = '\0' ;
166 
167 		// path copy to use for separation
168 		strcpy( path, pn->path ) ;
169 
170 		// copy segments of path (delimitted by "/") to copy
171 		while( path_pointer != NULL ) {
172 			ASCII * path_segment = strsep( &path_pointer, "/" ) ;
173 			BYTE sn[SERIAL_NUMBER_SIZE] ;
174 
175 			if ( PATH_MAX < strlen(pn_copy->path) + strlen(path_segment) ) {
176 				// too long, just use initial copy
177 				strcpy( pn_copy->path, pn->path ) ;
178 				break ;
179 			}
180 
181 			//test this segment for serial number
182 			if ( Parse_SerialNumber(path_segment,sn) == sn_valid ) {
183 				//printf("We see serial number in path "SNformat"\n",SNvar(sn)) ;
184 				// now test for alias
185 				ASCII * name = Cache_Get_Alias( sn ) ;
186 				if ( name != NULL ) {
187 					//printf("It's aliased to %s\n",name);
188 					// now test for room
189 					if ( PATH_MAX < strlen(pn_copy->path) + strlen(name) ) {
190 						// too long, just use initial copy
191 						strcpy( pn_copy->path, pn->path ) ;
192 						owfree(name) ;
193 						break ;
194 					}
195 					// overwrite serial number with alias name
196 					strcat( pn_copy->path, name ) ;
197 					owfree( name ) ;
198 				} else {
199 					strcat( pn_copy->path, path_segment ) ;
200 				}
201 			} else {
202 				strcat( pn_copy->path, path_segment ) ;
203 			}
204 
205 			if ( path_pointer != NULL ) {
206 				strcat( pn_copy->path, "/" ) ;
207 			}
208 			//LEVEL_DEBUG( "Alias path so far: %s",pn_copy->path ) ;
209 		}
210 
211 		if ( dirfunc != NULL ) {
212 			DIRLOCK;
213 			dirfunc(v, pn_copy);
214 			DIRUNLOCK;
215 		}
216 	} else {
217 		// Don't want alias substituted
218 		if ( dirfunc != NULL ) {
219 			DIRLOCK;
220 			dirfunc(v, pn);
221 			DIRUNLOCK;
222 		}
223 	}
224 }
225