xref: /illumos-gate/usr/src/lib/libadm/common/ckpath.c (revision 87c723434df4be9c0f7ef119567cb6e2da776a36)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  * Copyright (c) 1996-1998, 2001 by Sun Microsystems, Inc.
28  * All rights reserved.
29  */
30 /*
31  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
32  */
33 
34 /*LINTLIBRARY*/
35 
36 #include <stdio.h>
37 #include <ctype.h>
38 #include <string.h>
39 #include <limits.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include "valtools.h"
43 #include <stdlib.h>
44 #include <fcntl.h>
45 #include <unistd.h>
46 #include "libadm.h"
47 
48 #define	E_SYNTAX	"does not meet suggested filename syntax standard"
49 #define	E_READ		"is not readable"
50 #define	E_WRITE		"is not writable"
51 #define	E_EXEC		"is not executable"
52 #define	E_CREAT		"cannot be created"
53 #define	E_ABSOLUTE	"must begin with a slash (/)"
54 #define	E_RELATIVE	"must not begin with a slash (/)"
55 #define	E_EXIST		"does not exist"
56 #define	E_NEXIST	"must not already exist"
57 #define	E_BLK		"must specify a block special device"
58 #define	E_CHR		"must specify a character special device"
59 #define	E_DIR		"must specify a directory"
60 #define	E_REG		"must be a regular file"
61 #define	E_NONZERO	"must be a file of non-zero length"
62 
63 #define	H_READ		"must be readable"
64 #define	H_WRITE		"must be writable"
65 #define	H_EXEC		"must be executable"
66 #define	H_CREAT		"will be created if it does not exist"
67 #define	H_ABSOLUTE	E_ABSOLUTE
68 #define	H_RELATIVE	E_RELATIVE
69 #define	H_EXIST		"must already exist"
70 #define	H_NEXIST	"must not already exist"
71 #define	H_BLK		E_BLK
72 #define	H_CHR		E_CHR
73 #define	H_DIR		E_DIR
74 #define	H_REG		E_REG
75 #define	H_NONZERO	E_NONZERO
76 
77 #define	MSGSIZ	1024
78 #define	STDHELP \
79 	"A pathname is a filename, optionally preceded by parent directories."
80 
81 static char	*errstr;
82 static char	*badset = "*?[]{}()<> \t'`\"\\|^";
83 
84 static void
85 addhlp(char *msg, char *text)
86 {
87 	static int count;
88 
89 	if (text == NULL) {
90 		count = 0;
91 		return;
92 	}
93 	if (!count++)
94 		(void) strcat(msg, " The pathname you enter:");
95 	(void) strcat(msg, "\\n\\t-\\ ");
96 	(void) strcat(msg, text);
97 }
98 
99 static char *
100 sethlp(int pflags)
101 {
102 	char	*msg;
103 
104 	msg = calloc(MSGSIZ, sizeof (char));
105 	addhlp(msg, NULL); /* initialize count */
106 	(void) strcpy(msg, STDHELP);
107 
108 	if (pflags & P_EXIST)
109 		addhlp(msg, H_EXIST);
110 	else if (pflags & P_NEXIST)
111 		addhlp(msg, H_NEXIST);
112 
113 	if (pflags & P_ABSOLUTE)
114 		addhlp(msg, H_ABSOLUTE);
115 	else if (pflags & P_RELATIVE)
116 		addhlp(msg, H_RELATIVE);
117 
118 	if (pflags & P_READ)
119 		addhlp(msg, H_READ);
120 	if (pflags & P_WRITE)
121 		addhlp(msg, H_WRITE);
122 	if (pflags & P_EXEC)
123 		addhlp(msg, H_EXEC);
124 	if (pflags & P_CREAT)
125 		addhlp(msg, H_CREAT);
126 
127 	if (pflags & P_BLK)
128 		addhlp(msg, H_BLK);
129 	else if (pflags & P_CHR)
130 		addhlp(msg, H_CHR);
131 	else if (pflags & P_DIR)
132 		addhlp(msg, H_DIR);
133 	else if (pflags & P_REG)
134 		addhlp(msg, H_REG);
135 
136 	if (pflags & P_NONZERO)
137 		addhlp(msg, H_NONZERO);
138 
139 	return (msg);
140 }
141 
142 int
143 ckpath_stx(int pflags)
144 {
145 	if (((pflags & P_ABSOLUTE) && (pflags & P_RELATIVE)) ||
146 	    ((pflags & P_NEXIST) && (pflags &
147 		(P_EXIST|P_NONZERO|P_READ|P_WRITE|P_EXEC))) ||
148 	    ((pflags & P_CREAT) && (pflags & (P_EXIST|P_NEXIST|P_BLK|P_CHR))) ||
149 	    ((pflags & P_BLK) && (pflags & (P_CHR|P_REG|P_DIR|P_NONZERO))) ||
150 	    ((pflags & P_CHR) && (pflags & (P_REG|P_DIR|P_NONZERO))) ||
151 	    ((pflags & P_DIR) && (pflags & P_REG))) {
152 		return (1);
153 	}
154 	return (0);
155 }
156 
157 int
158 ckpath_val(char *path, int pflags)
159 {
160 	struct stat64 status;
161 	int	fd;
162 	char	*pt;
163 
164 	if ((pflags & P_RELATIVE) && (*path == '/')) {
165 		errstr = E_RELATIVE;
166 		return (1);
167 	}
168 	if ((pflags & P_ABSOLUTE) && (*path != '/')) {
169 		errstr = E_ABSOLUTE;
170 		return (1);
171 	}
172 	if (stat64(path, &status)) {
173 		if (pflags & P_EXIST) {
174 			errstr = E_EXIST;
175 			return (1);
176 		}
177 		for (pt = path; *pt; pt++) {
178 			if (!isprint((unsigned char)*pt) ||
179 				strchr(badset, *pt)) {
180 				errstr = E_SYNTAX;
181 				return (1);
182 			}
183 		}
184 		if (pflags & P_CREAT) {
185 			if (pflags & P_DIR) {
186 				if ((mkdir(path, 0755)) != 0) {
187 					errstr = E_CREAT;
188 					return (1);
189 				}
190 			} else {
191 				if ((fd = creat(path, 0644)) < 0) {
192 					errstr = E_CREAT;
193 					return (1);
194 				}
195 				(void) close(fd);
196 			}
197 		}
198 		return (0);
199 	} else if (pflags & P_NEXIST) {
200 		errstr = E_NEXIST;
201 		return (1);
202 	}
203 	if ((status.st_mode & S_IFMT) == S_IFREG) {
204 		/* check non zero status */
205 		if ((pflags & P_NONZERO) && (status.st_size < 1)) {
206 			errstr = E_NONZERO;
207 			return (1);
208 		}
209 	}
210 	if ((pflags & P_CHR) && ((status.st_mode & S_IFMT) != S_IFCHR)) {
211 		errstr = E_CHR;
212 		return (1);
213 	}
214 	if ((pflags & P_BLK) && ((status.st_mode & S_IFMT) != S_IFBLK)) {
215 		errstr = E_BLK;
216 		return (1);
217 	}
218 	if ((pflags & P_DIR) && ((status.st_mode & S_IFMT) != S_IFDIR)) {
219 		errstr = E_DIR;
220 		return (1);
221 	}
222 	if ((pflags & P_REG) && ((status.st_mode & S_IFMT) != S_IFREG)) {
223 		errstr = E_REG;
224 		return (1);
225 	}
226 	if ((pflags & P_READ) && !(status.st_mode & S_IREAD)) {
227 		errstr = E_READ;
228 		return (1);
229 	}
230 	if ((pflags & P_WRITE) && !(status.st_mode & S_IWRITE)) {
231 		errstr = E_WRITE;
232 		return (1);
233 	}
234 	if ((pflags & P_EXEC) && !(status.st_mode & S_IEXEC)) {
235 		errstr = E_EXEC;
236 		return (1);
237 	}
238 	return (0);
239 }
240 
241 void
242 ckpath_err(int pflags, char *error, char *input)
243 {
244 	char	buffer[2048];
245 	char	*defhlp;
246 
247 	if (input) {
248 		if (ckpath_val(input, pflags)) {
249 			(void) snprintf(buffer, sizeof (buffer),
250 			    "Pathname %s.", errstr);
251 			puterror(stdout, buffer, error);
252 			return;
253 		}
254 	}
255 	defhlp = sethlp(pflags);
256 	puterror(stdout, defhlp, error);
257 	free(defhlp);
258 }
259 
260 void
261 ckpath_hlp(int pflags, char *help)
262 {
263 	char	*defhlp;
264 
265 	defhlp = sethlp(pflags);
266 	puthelp(stdout, defhlp, help);
267 	free(defhlp);
268 }
269 
270 int
271 ckpath(char *pathval, int pflags, char *defstr, char *error, char *help,
272 	char *prompt)
273 {
274 	char	*defhlp,
275 		input[MAX_INPUT],
276 		buffer[256];
277 
278 	if ((pathval == NULL) || ckpath_stx(pflags))
279 		return (2); /* usage error */
280 
281 	if (!prompt) {
282 		if (pflags & P_ABSOLUTE)
283 			prompt = "Enter an absolute pathname";
284 		else if (pflags & P_RELATIVE)
285 			prompt = "Enter a relative pathname";
286 		else
287 			prompt = "Enter a pathname";
288 	}
289 	defhlp = sethlp(pflags);
290 
291 start:
292 	putprmpt(stderr, prompt, NULL, defstr);
293 	if (getinput(input)) {
294 		free(defhlp);
295 		return (1);
296 	}
297 
298 	if (strlen(input) == 0) {
299 		if (defstr) {
300 			(void) strcpy(pathval, defstr);
301 			free(defhlp);
302 			return (0);
303 		}
304 		puterror(stderr, NULL, "Input is required.");
305 		goto start;
306 	}
307 	if (strcmp(input, "?") == 0) {
308 		puthelp(stderr, defhlp, help);
309 		goto start;
310 	}
311 	if (ckquit && (strcmp(input, "q") == 0)) {
312 		free(defhlp);
313 		return (3);
314 	}
315 
316 	if (ckpath_val(input, pflags)) {
317 		(void) snprintf(buffer, sizeof (buffer),
318 		    "Pathname %s.", errstr);
319 		puterror(stderr, buffer, error);
320 		goto start;
321 	}
322 	(void) strcpy(pathval, input);
323 	free(defhlp);
324 	return (0);
325 }
326