]> git.zerfleddert.de Git - micropolis/blob - src/tclx/src/tclxchmd.c
Import Micropolis from http://www.donhopkins.com/home/micropolis/
[micropolis] / src / tclx / src / tclxchmd.c
1 /*
2 * tclXchmod.c --
3 *
4 * Chmod, chown and chgrp Tcl commands.
5 *-----------------------------------------------------------------------------
6 * Copyright 1992 Karl Lehenbauer and Mark Diekhans.
7 *
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation for any purpose and without fee is hereby granted, provided
10 * that the above copyright notice appear in all copies. Karl Lehenbauer and
11 * Mark Diekhans make no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
13 * implied warranty.
14 *-----------------------------------------------------------------------------
15 * $Id: tclXchmod.c,v 2.0 1992/10/16 04:50:26 markd Rel $
16 *-----------------------------------------------------------------------------
17 */
18
19 #include "tclxint.h"
20
21 /*
22 * Prototypes of internal functions.
23 */
24 static int
25 ConvSymMode _ANSI_ARGS_((Tcl_Interp *interp,
26 char *symMode,
27 int modeVal));
28
29 \f
30 /*
31 *-----------------------------------------------------------------------------
32 *
33 * ConvSymMode --
34 * Parse and convert symbolic file permissions as specified by chmod(C).
35 *
36 * Parameters:
37 * o interp - Pointer to the current interpreter, error messages will be
38 * returned in the result.
39 * o symMode - The symbolic permissions to parse.
40 * o modeVal - The existing permissions value on a file.
41 *
42 * Results:
43 * The new permissions, or -1 if invalid permissions where supplied.
44 *
45 *-----------------------------------------------------------------------------
46 */
47 static int
48 ConvSymMode (interp, symMode, modeVal)
49 Tcl_Interp *interp;
50 char *symMode;
51 int modeVal;
52
53 {
54 int user, group, other;
55 char operator, *scanPtr;
56 int rwxMask, ugoMask, setUID, sticky, locking;
57 int newMode;
58
59 scanPtr = symMode;
60
61 while (*scanPtr != '\0') {
62 user = group = other = FALSE;
63
64 /*
65 * Scan who field.
66 */
67 while (! ((*scanPtr == '+') ||
68 (*scanPtr == '-') ||
69 (*scanPtr == '='))) {
70 switch (*scanPtr) {
71 case 'a':
72 user = group = other = TRUE;
73 break;
74 case 'u':
75 user = TRUE;
76 break;
77 case 'g':
78 group = TRUE;
79 break;
80 case 'o':
81 other = TRUE;
82 break;
83 default:
84 goto invalidMode;
85 }
86 scanPtr++;
87 }
88
89 /*
90 * If none where specified, that means all.
91 */
92
93 if (! (user || group || other))
94 user = group = other = TRUE;
95
96 operator = *scanPtr++;
97
98 /*
99 * Decode the permissions
100 */
101
102 rwxMask = 0;
103 setUID = sticky = locking = FALSE;
104
105 /*
106 * Scan permissions field
107 */
108 while (! ((*scanPtr == ',') || (*scanPtr == 0))) {
109 switch (*scanPtr) {
110 case 'r':
111 rwxMask |= 4;
112 break;
113 case 'w':
114 rwxMask |= 2;
115 break;
116 case 'x':
117 rwxMask |= 1;
118 break;
119 case 's':
120 setUID = TRUE;
121 break;
122 case 't':
123 sticky = TRUE;
124 break;
125 case 'l':
126 locking = TRUE;
127 break;
128 default:
129 goto invalidMode;
130 }
131 scanPtr++;
132 }
133
134 /*
135 * Build mode map of specified values.
136 */
137
138 newMode = 0;
139 ugoMask = 0;
140 if (user) {
141 newMode |= rwxMask << 6;
142 ugoMask |= 0700;
143 }
144 if (group) {
145 newMode |= rwxMask << 3;
146 ugoMask |= 0070;
147 }
148 if (other) {
149 newMode |= rwxMask;
150 ugoMask |= 0007;
151 }
152 if (setUID && user)
153 newMode |= 04000;
154 if ((setUID || locking) && group)
155 newMode |= 02000;
156 if (sticky)
157 newMode |= 01000;
158
159 /*
160 * Add to cumulative mode based on operator.
161 */
162
163 if (operator == '+')
164 modeVal |= newMode;
165 else if (operator == '-')
166 modeVal &= ~newMode;
167 else if (operator == '=')
168 modeVal |= (modeVal & ugoMask) | newMode;
169 if (*scanPtr == ',')
170 scanPtr++;
171 }
172
173 return modeVal;
174
175 invalidMode:
176 Tcl_AppendResult (interp, "invalid file mode \"", symMode, "\"",
177 (char *) NULL);
178 return -1;
179 }
180 \f
181 /*
182 *-----------------------------------------------------------------------------
183 *
184 * Tcl_ChmodCmd --
185 * Implements the TCL chmod command:
186 * chmod mode filelist
187 *
188 * Results:
189 * Standard TCL results, may return the UNIX system error message.
190 *
191 *-----------------------------------------------------------------------------
192 */
193 int
194 Tcl_ChmodCmd (clientData, interp, argc, argv)
195 ClientData clientData;
196 Tcl_Interp *interp;
197 int argc;
198 char **argv;
199 {
200 int idx, modeVal, fileArgc, absMode;
201 char **fileArgv;
202 struct stat fileStat;
203
204 if (argc != 3) {
205 Tcl_AppendResult (interp, tclXWrongArgs, argv [0],
206 " mode filelist", (char *) NULL);
207 return TCL_ERROR;
208 }
209
210 if (isdigit (argv [1][0])) {
211 if (Tcl_GetInt (interp, argv [1], &modeVal) != TCL_OK)
212 return TCL_ERROR;
213 absMode = TRUE;
214 } else
215 absMode = FALSE;
216
217 if (Tcl_SplitList (interp, argv [2], &fileArgc, &fileArgv) != TCL_OK)
218 return TCL_ERROR;
219
220 for (idx = 0; idx < fileArgc; idx++) {
221 if (!absMode) {
222 if (stat (fileArgv [idx], &fileStat) != 0)
223 goto fileError;
224 modeVal = ConvSymMode (interp, argv [1], fileStat.st_mode & 07777);
225 if (modeVal < 0)
226 goto errorExit;
227 }
228 if (chmod (fileArgv [idx], (unsigned short) modeVal) < 0)
229 goto fileError;
230 }
231
232 exitPoint:
233 ckfree ((char *) fileArgv);
234 return TCL_OK;
235
236 fileError:
237 /*
238 * Error accessing file, assumes file name is fileArgv [idx].
239 */
240 Tcl_AppendResult (interp, fileArgv [idx], ": ", Tcl_UnixError (interp),
241 (char *) NULL);
242
243 errorExit:
244 ckfree ((char *) fileArgv);
245 return TCL_ERROR;
246 }
247 \f
248 /*
249 *-----------------------------------------------------------------------------
250 *
251 * Tcl_ChownCmd --
252 * Implements the TCL chown command:
253 * chown owner filelist
254 * chown {owner group} filelist
255 *
256 * Results:
257 * Standard TCL results, may return the UNIX system error message.
258 *
259 *-----------------------------------------------------------------------------
260 */
261 int
262 Tcl_ChownCmd (clientData, interp, argc, argv)
263 ClientData clientData;
264 Tcl_Interp *interp;
265 int argc;
266 char **argv;
267 {
268 int idx, ownArgc, fileArgc;
269 char **ownArgv, **fileArgv = NULL;
270 struct stat fileStat;
271 int useOwnerGrp, chGroup, ownerId, groupId;
272 struct passwd *passwdPtr;
273 struct group *groupPtr;
274 int result = TCL_ERROR;
275
276 if (argc != 3) {
277 Tcl_AppendResult (interp, tclXWrongArgs, argv [0],
278 " owner|{owner group} filelist", (char *) NULL);
279 return TCL_ERROR;
280 }
281
282 if (Tcl_SplitList (interp, argv[1], &ownArgc, &ownArgv) != TCL_OK)
283 return TCL_ERROR;
284 if ((ownArgc < 1) || (ownArgc > 2)) {
285 interp->result = "owner arg should be: owner or {owner group}";
286 goto exitPoint;
287 }
288 if (ownArgc == 2) {
289 useOwnerGrp = (ownArgv [1][0] == '\0');
290 chGroup = TRUE;
291 } else
292 chGroup = FALSE;
293
294 /*
295 * Get the owner id, either convert the name or use it as an integer.
296 */
297 passwdPtr = getpwnam (ownArgv [0]);
298 if (passwdPtr != NULL)
299 ownerId = passwdPtr->pw_uid;
300 else {
301 if (!Tcl_StrToInt (ownArgv [0], 10, &ownerId)) {
302 Tcl_AppendResult (interp, "unknown user id: ", ownArgv [0],
303 (char *) NULL);
304 goto exitPoint;
305 }
306 }
307 /*
308 * Get the group id, this is either the specified id or name, or the
309 * if associated with the specified user.
310 */
311 if (chGroup) {
312 if (useOwnerGrp) {
313 if (passwdPtr == NULL) {
314 passwdPtr = getpwuid (ownerId);
315 if (passwdPtr != NULL) {
316 Tcl_AppendResult (interp, "unknown user id: ",
317 ownArgv [0], (char *) NULL);
318 goto exitPoint;
319 }
320 }
321 groupId = passwdPtr->pw_gid;
322 } else {
323 groupPtr = getgrnam (ownArgv [1]);
324 if (groupPtr != NULL)
325 groupId = groupPtr->gr_gid;
326 else {
327 if (!Tcl_StrToInt (ownArgv [1], 10, &groupId)) {
328 Tcl_AppendResult (interp, "unknown group id: ",
329 ownArgv [1], (char *) NULL);
330 goto exitPoint;
331 }
332 }
333 }
334 }
335 if (Tcl_SplitList (interp, argv [2], &fileArgc, &fileArgv) != TCL_OK)
336 goto exitPoint;
337
338 for (idx = 0; idx < fileArgc; idx++) {
339 if (!chGroup) {
340 if (stat (fileArgv [idx], &fileStat) != 0) {
341 Tcl_AppendResult (interp, fileArgv [idx], ": ",
342 Tcl_UnixError (interp), (char *) NULL);
343 goto exitPoint;
344 }
345 groupId = fileStat.st_gid;
346 }
347
348 if (chown (fileArgv[idx], ownerId, groupId) < 0) {
349 Tcl_AppendResult (interp, fileArgv [idx], ": ",
350 Tcl_UnixError (interp), (char *) NULL);
351 goto exitPoint;
352 }
353
354 } /* Modify each file */
355
356 result = TCL_OK;
357 exitPoint:
358 ckfree ((char *) ownArgv);
359 if (fileArgv != NULL)
360 ckfree ((char *) fileArgv);
361 return result;
362 }
363 \f
364 /*
365 *-----------------------------------------------------------------------------
366 *
367 * Tcl_ChgrpCmd --
368 * Implements the TCL chgrp command:
369 * chgrp group filelist
370 *
371 * Results:
372 * Standard TCL results, may return the UNIX system error message.
373 *
374 *-----------------------------------------------------------------------------
375 */
376 int
377 Tcl_ChgrpCmd (clientData, interp, argc, argv)
378 ClientData clientData;
379 Tcl_Interp *interp;
380 int argc;
381 char **argv;
382 {
383 int idx, fileArgc, groupId, result = TCL_ERROR;
384 char **fileArgv;
385 struct stat fileStat;
386 struct group *groupPtr;
387
388 if (argc < 3) {
389 Tcl_AppendResult (interp, tclXWrongArgs, argv [0],
390 " group filelist", (char *) NULL);
391 return TCL_ERROR;
392 }
393
394 groupPtr = getgrnam (argv [1]);
395 if (groupPtr != NULL)
396 groupId = groupPtr->gr_gid;
397 else {
398 if (!Tcl_StrToInt (argv [1], 10, &groupId)) {
399 Tcl_AppendResult (interp, "unknown group id: ", argv [1],
400 (char *) NULL);
401 return TCL_ERROR;
402 }
403 }
404 if (Tcl_SplitList (interp, argv [2], &fileArgc, &fileArgv) != TCL_OK)
405 return TCL_ERROR;
406
407 for (idx = 0; idx < fileArgc; idx++) {
408 if ((stat (fileArgv [idx], &fileStat) != 0) ||
409 (chown (fileArgv[idx], fileStat.st_uid, groupId) < 0)) {
410 Tcl_AppendResult (interp, fileArgv [idx], ": ",
411 Tcl_UnixError (interp), (char *) NULL);
412 goto exitPoint;
413 }
414 } /* Modify each file */
415
416 result = TCL_OK;
417 exitPoint:
418 ckfree ((char *) fileArgv);
419 return result;
420 }
Impressum, Datenschutz