1 | /* Created by: Robert French |
---|
2 | * |
---|
3 | * $Source: /afs/dev.mit.edu/source/repository/athena/bin/attach/util.c,v $ |
---|
4 | * $Author: ghudson $ |
---|
5 | * |
---|
6 | * Copyright (c) 1988 by the Massachusetts Institute of Technology. |
---|
7 | */ |
---|
8 | |
---|
9 | static char *rcsid_util_c = "$Header: /afs/dev.mit.edu/source/repository/athena/bin/attach/util.c,v 1.23 1997-04-01 01:01:43 ghudson Exp $"; |
---|
10 | |
---|
11 | #include "attach.h" |
---|
12 | |
---|
13 | #include <sys/stat.h> |
---|
14 | #include <fcntl.h> |
---|
15 | #include <pwd.h> |
---|
16 | #include <grp.h> |
---|
17 | #include <signal.h> |
---|
18 | #ifdef HESIOD |
---|
19 | #include <hesiod.h> |
---|
20 | #endif |
---|
21 | |
---|
22 | #define TOKSEP " \t\r\n" |
---|
23 | |
---|
24 | #ifdef ultrix |
---|
25 | #define max(a,b) (((a) > (b)) ? (a) : (b)) |
---|
26 | #endif |
---|
27 | |
---|
28 | extern int sys_nerr; |
---|
29 | extern char *sys_errlist[]; |
---|
30 | |
---|
31 | char exp_hesline[BUFSIZ]; /* Place to store explicit */ |
---|
32 | char *exp_hesptr[2]; /* ``hesiod'' entry */ |
---|
33 | char *abort_msg = "Operation aborted\n"; |
---|
34 | |
---|
35 | static missarg(); |
---|
36 | |
---|
37 | /* |
---|
38 | * These routines provide a way of locking out interrupts during |
---|
39 | * critical sections of code. After the critical sections of code are |
---|
40 | * executed, if a SIGTERM or SIGINT had arrived before, the program |
---|
41 | * terminates then. |
---|
42 | */ |
---|
43 | |
---|
44 | int caught_signal = 0; |
---|
45 | static int in_critical_code_p = 0; |
---|
46 | |
---|
47 | #ifdef POSIX |
---|
48 | static sigset_t osigmask; |
---|
49 | #else |
---|
50 | static int osigmask; |
---|
51 | #endif |
---|
52 | |
---|
53 | /* |
---|
54 | * Signal handler for SIGTERM & SIGINT |
---|
55 | */ |
---|
56 | sig_catch sig_trap() |
---|
57 | { |
---|
58 | if (in_critical_code_p) { |
---|
59 | caught_signal++; |
---|
60 | return; |
---|
61 | } |
---|
62 | terminate_program(); |
---|
63 | } |
---|
64 | |
---|
65 | /* |
---|
66 | * Enter critical section of code |
---|
67 | */ |
---|
68 | start_critical_code() |
---|
69 | { |
---|
70 | #ifdef POSIX |
---|
71 | sigset_t mysigmask; |
---|
72 | |
---|
73 | sigemptyset(&mysigmask); |
---|
74 | sigaddset(&mysigmask, SIGTSTP); |
---|
75 | sigaddset(&mysigmask, SIGTTIN); |
---|
76 | sigaddset(&mysigmask, SIGTTOU); |
---|
77 | |
---|
78 | if (in_critical_code_p++ == 0) |
---|
79 | sigprocmask(SIG_BLOCK, &mysigmask, &osigmask); |
---|
80 | #else |
---|
81 | if (in_critical_code_p++ == 0) |
---|
82 | osigmask=sigblock(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU)); |
---|
83 | #endif |
---|
84 | } |
---|
85 | |
---|
86 | /* |
---|
87 | * Exit critical section of code |
---|
88 | */ |
---|
89 | end_critical_code() |
---|
90 | { |
---|
91 | if (--in_critical_code_p == 0) { |
---|
92 | if (caught_signal) |
---|
93 | terminate_program(); |
---|
94 | #ifdef POSIX |
---|
95 | sigprocmask(SIG_SETMASK, &osigmask, (sigset_t *)0); |
---|
96 | #else |
---|
97 | sigsetmask(osigmask); |
---|
98 | #endif |
---|
99 | } |
---|
100 | } |
---|
101 | |
---|
102 | /* |
---|
103 | * terminate the program |
---|
104 | */ |
---|
105 | terminate_program() |
---|
106 | { |
---|
107 | exit(ERR_INTERRUPT); |
---|
108 | } |
---|
109 | |
---|
110 | /* |
---|
111 | * LOCK the mtab - wait for it if it's already locked |
---|
112 | */ |
---|
113 | |
---|
114 | /* |
---|
115 | * Unfortunately, mount and umount don't honor lock files, so these |
---|
116 | * locks are only valid for other attach processes. |
---|
117 | */ |
---|
118 | |
---|
119 | static int mtab_lock_fd = -1; |
---|
120 | |
---|
121 | lock_mtab() |
---|
122 | { |
---|
123 | char *lockfn; |
---|
124 | #ifdef POSIX |
---|
125 | struct flock fl; |
---|
126 | #endif |
---|
127 | |
---|
128 | if (mtab_lock_fd < 0) { |
---|
129 | if (!(lockfn = malloc(strlen(mtab_fn)+6))) { |
---|
130 | fprintf(stderr, "Can't malloc lockfile filename.\n"); |
---|
131 | fprintf(stderr, abort_msg); |
---|
132 | exit(ERR_FATAL); |
---|
133 | } |
---|
134 | (void) strcpy(lockfn, mtab_fn); |
---|
135 | (void) strcat(lockfn, ".lock"); |
---|
136 | mtab_lock_fd = open(lockfn, O_CREAT|O_RDWR, 0644); |
---|
137 | if (mtab_lock_fd < 0) { |
---|
138 | fprintf(stderr,"Can't open %s: %s\n", lockfn, |
---|
139 | sys_errlist[errno]); |
---|
140 | fprintf(stderr, abort_msg); |
---|
141 | exit(ERR_FATAL); |
---|
142 | } |
---|
143 | } |
---|
144 | #ifdef POSIX |
---|
145 | fl.l_type = F_WRLCK; |
---|
146 | fl.l_whence = SEEK_SET; |
---|
147 | fl.l_start = 0; |
---|
148 | fl.l_len = 0; |
---|
149 | fl.l_pid = getpid(); |
---|
150 | fcntl(mtab_lock_fd, F_SETLKW, &fl); |
---|
151 | #else |
---|
152 | flock(mtab_lock_fd, LOCK_EX); |
---|
153 | #endif |
---|
154 | } |
---|
155 | |
---|
156 | /* |
---|
157 | * UNLOCK the mtab |
---|
158 | */ |
---|
159 | unlock_mtab() |
---|
160 | { |
---|
161 | close(mtab_lock_fd); |
---|
162 | mtab_lock_fd = -1; |
---|
163 | } |
---|
164 | |
---|
165 | /* |
---|
166 | * Convert a string type to a filesystem type entry |
---|
167 | */ |
---|
168 | struct _fstypes *get_fs(s) |
---|
169 | char *s; |
---|
170 | { |
---|
171 | int i; |
---|
172 | |
---|
173 | if (s && *s) { |
---|
174 | for (i=0;fstypes[i].name;i++) { |
---|
175 | if (!strcasecmp(fstypes[i].name, s)) |
---|
176 | return (&fstypes[i]); |
---|
177 | } |
---|
178 | } |
---|
179 | return (NULL); |
---|
180 | } |
---|
181 | |
---|
182 | /* Return the preference of a hesiod line, or -1 if the filesystem type |
---|
183 | * does not admit a preference field. */ |
---|
184 | static int get_preference(hesline) |
---|
185 | char *hesline; |
---|
186 | { |
---|
187 | char *p; |
---|
188 | int i; |
---|
189 | |
---|
190 | p = strchr(hesline, ' '); |
---|
191 | if (p == NULL || (p - hesline == 3 && strncasecmp(hesline, "MUL", 3) == 0)) |
---|
192 | return (-1); |
---|
193 | |
---|
194 | /* FS type okay; return the value of the fifth field. */ |
---|
195 | while (isspace(*p)) |
---|
196 | p++; |
---|
197 | for (i = 2; i < 5; i++) { |
---|
198 | while (*p && !isspace(*p)) |
---|
199 | p++; |
---|
200 | while (isspace(*p)) |
---|
201 | p++; |
---|
202 | } |
---|
203 | return ((*p) ? atoi(p) : 0); |
---|
204 | } |
---|
205 | |
---|
206 | /* Reorder non-MUL entries in increasing order of their preference |
---|
207 | * fields (fifth field), if present. Anything with no preference field is |
---|
208 | * assumed to have preference 0. This sort has to be stable, so that we |
---|
209 | * don't break DNS ordering if we happen to have it. (That is, don't |
---|
210 | * replace this function with a call to qsort(), at least until you're sure |
---|
211 | * nobody is going to be relying on DNS ordering.) |
---|
212 | * |
---|
213 | * Note that lower preference is better, and anything with no preference |
---|
214 | * field will have the best preference. Hopefully any hesiod response that |
---|
215 | * uses preference fields will use them everywhere. */ |
---|
216 | static void sort_hesiod_data(hes) |
---|
217 | char **hes; |
---|
218 | { |
---|
219 | char **p1, **p2, **slot, *p; |
---|
220 | int pref, pref2; |
---|
221 | |
---|
222 | /* This doesn't need to be fast; do an insertion sort. */ |
---|
223 | for (p1 = hes; *p1; p1++) { |
---|
224 | p = *p1; |
---|
225 | pref = get_preference(p); |
---|
226 | if (pref == -1) |
---|
227 | continue; |
---|
228 | slot = p1; |
---|
229 | for (p2 = p1 - 1; p2 >= hes; p2--) { |
---|
230 | pref2 = get_preference(*p2); |
---|
231 | if (pref2 == -1) |
---|
232 | continue; |
---|
233 | /* If we have the right slot for p, stop. */ |
---|
234 | if (pref2 <= pref) |
---|
235 | break; |
---|
236 | /* Otherwise, shift the slot down one position. */ |
---|
237 | *slot = *p2; |
---|
238 | slot = p2; |
---|
239 | } |
---|
240 | *slot = p; |
---|
241 | } |
---|
242 | } |
---|
243 | |
---|
244 | /* |
---|
245 | * Build a Hesiod line either from a Hesiod query or internal frobbing |
---|
246 | * if explicit is set. |
---|
247 | */ |
---|
248 | char **build_hesiod_line(name) |
---|
249 | char *name; |
---|
250 | { |
---|
251 | char **realhes; |
---|
252 | struct _fstypes *fsp; |
---|
253 | |
---|
254 | if (!explicit) { |
---|
255 | realhes = conf_filsys_resolve(name); |
---|
256 | #ifdef HESIOD |
---|
257 | if (!realhes || !*realhes) |
---|
258 | realhes = hes_resolve(name, "filsys"); |
---|
259 | #endif |
---|
260 | if (!realhes || !*realhes) |
---|
261 | fprintf(stderr, "%s: Can't resolve name\n", name); |
---|
262 | else |
---|
263 | sort_hesiod_data(realhes); |
---|
264 | return (realhes); |
---|
265 | } |
---|
266 | |
---|
267 | fsp = get_fs(filsys_type ? filsys_type : "NFS"); |
---|
268 | if (!fsp) |
---|
269 | return (NULL); |
---|
270 | if (!fsp->explicit) { |
---|
271 | fprintf(stderr, "Explicit definitions for type %s not allowed\n", |
---|
272 | filsys_type); |
---|
273 | return (NULL); |
---|
274 | } |
---|
275 | |
---|
276 | return ((fsp->explicit)(name)); |
---|
277 | } |
---|
278 | |
---|
279 | /* |
---|
280 | * Parse a Hesiod record |
---|
281 | * |
---|
282 | * Returns 0 on success, -1 on failure |
---|
283 | */ |
---|
284 | int parse_hes(hes, at, errorname) |
---|
285 | char *hes, *errorname; |
---|
286 | struct _attachtab *at; |
---|
287 | { |
---|
288 | char *cp, *t; |
---|
289 | struct hostent *hent; |
---|
290 | int type; |
---|
291 | |
---|
292 | memset(at, 0, sizeof(struct _attachtab)); |
---|
293 | |
---|
294 | if (!*hes) |
---|
295 | goto bad_hes_line; |
---|
296 | |
---|
297 | |
---|
298 | at->fs = get_fs(strtok(hes, TOKSEP)); |
---|
299 | if (!at->fs) |
---|
300 | goto bad_hes_line; |
---|
301 | type = at->fs->type; |
---|
302 | |
---|
303 | if (type & TYPE_ERR) { |
---|
304 | strncpy(at->hostdir, strtok(NULL, ""), sizeof(at->hostdir)); |
---|
305 | return(0); |
---|
306 | } |
---|
307 | |
---|
308 | if (!(cp = strtok(NULL, (type & TYPE_MUL) ? "" : TOKSEP))) |
---|
309 | goto bad_hes_line; |
---|
310 | strcpy(at->hostdir, cp); |
---|
311 | |
---|
312 | if (type & ~(TYPE_UFS | TYPE_AFS | TYPE_MUL)) { |
---|
313 | if (!(cp = strtok(NULL, TOKSEP))) |
---|
314 | goto bad_hes_line; |
---|
315 | strcpy(at->host, cp); |
---|
316 | } else |
---|
317 | strcpy(at->host, "localhost"); |
---|
318 | |
---|
319 | if (type & TYPE_MUL) { |
---|
320 | t = at->hostdir; |
---|
321 | while (t = strchr(t,' ')) |
---|
322 | *t = ','; |
---|
323 | at->mode = '-'; |
---|
324 | strcpy(at->mntpt, "localhost"); |
---|
325 | } else { |
---|
326 | |
---|
327 | if (!(cp = strtok(NULL, TOKSEP))) |
---|
328 | goto bad_hes_line; |
---|
329 | at->mode = *cp; |
---|
330 | if (at->mode == 'x') |
---|
331 | at->mode = 'w'; /* Backwards compatibility */ |
---|
332 | if (at->fs->good_flags) { |
---|
333 | if (!strchr(at->fs->good_flags, at->mode)) |
---|
334 | goto bad_hes_line; /* Bad attach mode */ |
---|
335 | } |
---|
336 | |
---|
337 | if (!(cp = strtok(NULL, TOKSEP))) |
---|
338 | goto bad_hes_line; |
---|
339 | strcpy(at->mntpt, cp); |
---|
340 | } |
---|
341 | |
---|
342 | if (type & ~(TYPE_UFS | TYPE_AFS | TYPE_MUL)) { |
---|
343 | hent = gethostbyname(at->host); |
---|
344 | if (!hent) { |
---|
345 | fprintf(stderr,"%s: Can't resolve host %s\n",errorname, |
---|
346 | at->host); |
---|
347 | fprintf(stderr, abort_msg); |
---|
348 | return(-1); |
---|
349 | } |
---|
350 | #ifdef POSIX |
---|
351 | memmove(&at->hostaddr[0].s_addr, hent->h_addr_list[0], 4); |
---|
352 | #else |
---|
353 | bcopy(hent->h_addr_list[0], &at->hostaddr[0].s_addr, 4); |
---|
354 | #endif |
---|
355 | strcpy(at->host, hent->h_name); |
---|
356 | } else |
---|
357 | at->hostaddr[0].s_addr = (long) 0; |
---|
358 | return(0); |
---|
359 | |
---|
360 | bad_hes_line: |
---|
361 | fprintf(stderr,"Badly formatted filesystem definition\n"); |
---|
362 | fprintf(stderr, abort_msg); |
---|
363 | return(-1); |
---|
364 | } |
---|
365 | |
---|
366 | /* |
---|
367 | * Make the directories necessary for a mount point - set the number |
---|
368 | * of directories created in the attachtab structure |
---|
369 | */ |
---|
370 | int make_mntpt(at) |
---|
371 | struct _attachtab *at; |
---|
372 | { |
---|
373 | char bfr[BUFSIZ],*ptr; |
---|
374 | int oldmask; |
---|
375 | struct stat statbuf; |
---|
376 | |
---|
377 | strcpy(bfr, at->mntpt); |
---|
378 | if (at->fs->flags & AT_FS_PARENTMNTPT) { |
---|
379 | ptr = strrchr(bfr, '/'); |
---|
380 | if (ptr) |
---|
381 | *ptr = 0; |
---|
382 | else |
---|
383 | return(SUCCESS); |
---|
384 | } |
---|
385 | |
---|
386 | if (!stat(bfr, &statbuf)) { |
---|
387 | if ((statbuf.st_mode & S_IFMT) == S_IFDIR) |
---|
388 | return (SUCCESS); |
---|
389 | fprintf(stderr, "%s: %s is not a directory\n", at->hesiodname, |
---|
390 | at->mntpt); |
---|
391 | return (FAILURE); |
---|
392 | } |
---|
393 | |
---|
394 | oldmask = umask(022); |
---|
395 | |
---|
396 | ptr = bfr+1; /* Pass initial / */ |
---|
397 | |
---|
398 | at->rmdir = 0; |
---|
399 | |
---|
400 | while (ptr && *ptr) { |
---|
401 | strcpy(bfr, at->mntpt); |
---|
402 | ptr = strchr(ptr, '/'); |
---|
403 | if (ptr) |
---|
404 | *ptr++ = '\0'; |
---|
405 | if (debug_flag) |
---|
406 | printf("Making directory %s (%s)\n", bfr, ptr ? ptr : ""); |
---|
407 | if (mkdir(bfr, 0777)) { |
---|
408 | if (errno == EEXIST) |
---|
409 | continue; |
---|
410 | fprintf(stderr, "%s: Can't create directory %s: %s\n", |
---|
411 | at->hesiodname, bfr, sys_errlist[errno]); |
---|
412 | umask(oldmask); |
---|
413 | return (FAILURE); |
---|
414 | } |
---|
415 | else |
---|
416 | at->rmdir++; |
---|
417 | } |
---|
418 | umask(oldmask); |
---|
419 | return (SUCCESS); |
---|
420 | } |
---|
421 | |
---|
422 | /* |
---|
423 | * Delete a previously main mountpoint |
---|
424 | */ |
---|
425 | int rm_mntpt(at) |
---|
426 | struct _attachtab *at; |
---|
427 | { |
---|
428 | char bfr[BUFSIZ], *ptr; |
---|
429 | |
---|
430 | strcpy(bfr, at->mntpt); |
---|
431 | ptr = bfr; |
---|
432 | |
---|
433 | if (at->fs->flags & AT_FS_PARENTMNTPT) { |
---|
434 | ptr = strrchr(bfr, '/'); |
---|
435 | if (ptr) |
---|
436 | *ptr = 0; |
---|
437 | else |
---|
438 | return(SUCCESS); |
---|
439 | } |
---|
440 | while (at->rmdir--) { |
---|
441 | if (debug_flag) |
---|
442 | printf("Deleting directory %s (%s)\n", bfr, ptr ? ptr : ""); |
---|
443 | if (rmdir(bfr)) { |
---|
444 | if (errno != ENOENT) { |
---|
445 | fprintf(stderr, |
---|
446 | "%s: Can't remove directory %s: %s\n", |
---|
447 | at->hesiodname, ptr, |
---|
448 | sys_errlist[errno]); |
---|
449 | return (FAILURE); |
---|
450 | } |
---|
451 | } |
---|
452 | ptr = strrchr(bfr, '/'); |
---|
453 | if (ptr) |
---|
454 | *ptr = '\0'; |
---|
455 | else |
---|
456 | return (SUCCESS); |
---|
457 | } |
---|
458 | return (SUCCESS); |
---|
459 | } |
---|
460 | |
---|
461 | /* |
---|
462 | * Internal spiffed up getopt |
---|
463 | */ |
---|
464 | char internal_getopt(arg, cl) |
---|
465 | char *arg; |
---|
466 | struct command_list *cl; |
---|
467 | { |
---|
468 | int i; |
---|
469 | |
---|
470 | for (i=0;cl[i].small;i++) { |
---|
471 | if (cl[i].large && !strcmp(cl[i].large, arg)) |
---|
472 | return (cl[i].small[1]); |
---|
473 | if (!strcmp(cl[i].small, arg)) |
---|
474 | return (cl[i].small[1]); |
---|
475 | } |
---|
476 | return ('?'); |
---|
477 | } |
---|
478 | |
---|
479 | /* |
---|
480 | * Format a hesiod name into a name in /var/athena...including replacing / |
---|
481 | * with @, etc. |
---|
482 | */ |
---|
483 | make_temp_name(filename, name) |
---|
484 | char *filename; |
---|
485 | char *name; |
---|
486 | { |
---|
487 | strcpy(filename, "/var/athena/attach_"); |
---|
488 | filename = filename+strlen(filename); |
---|
489 | |
---|
490 | while (*name) { |
---|
491 | if (*name == '/') |
---|
492 | *filename++ = '@'; |
---|
493 | else |
---|
494 | *filename++ = *name; |
---|
495 | name++; |
---|
496 | } |
---|
497 | *filename = '\0'; |
---|
498 | } |
---|
499 | |
---|
500 | /* |
---|
501 | * Check to see if a filesystem is really being frobbed with by |
---|
502 | * another attach process. |
---|
503 | */ |
---|
504 | |
---|
505 | int really_in_use(name) |
---|
506 | char *name; |
---|
507 | { |
---|
508 | int fd, ret; |
---|
509 | char filename[BUFSIZ]; |
---|
510 | #ifdef POSIX |
---|
511 | struct flock fl; |
---|
512 | #endif |
---|
513 | |
---|
514 | make_temp_name(filename, name); |
---|
515 | |
---|
516 | if (debug_flag) |
---|
517 | printf("Checking lock on %s\n", filename); |
---|
518 | |
---|
519 | fd = open(filename, O_RDWR, 0644); |
---|
520 | if (!fd) |
---|
521 | return (0); |
---|
522 | |
---|
523 | #ifdef POSIX |
---|
524 | fl.l_type = F_WRLCK; |
---|
525 | fl.l_whence = SEEK_SET; |
---|
526 | fl.l_start = 0; |
---|
527 | fl.l_len = 0; |
---|
528 | fl.l_pid = getpid(); |
---|
529 | ret = (fcntl(fd, F_SETLK, &fl)==-1 && errno == EAGAIN); |
---|
530 | #else |
---|
531 | ret = (flock(fd, LOCK_EX | LOCK_NB) == -1 && errno == EWOULDBLOCK); |
---|
532 | #endif |
---|
533 | |
---|
534 | close(fd); |
---|
535 | return (ret); |
---|
536 | } |
---|
537 | |
---|
538 | /* |
---|
539 | * Mark a filesystem as being frobbed with |
---|
540 | */ |
---|
541 | |
---|
542 | void mark_in_use(name) |
---|
543 | char *name; |
---|
544 | { |
---|
545 | static int fd; |
---|
546 | static char filename[BUFSIZ]; |
---|
547 | #ifdef POSIX |
---|
548 | struct flock fl; |
---|
549 | #endif |
---|
550 | |
---|
551 | if (!name) { |
---|
552 | if (debug_flag) |
---|
553 | printf("Removing lock on %s\n", filename); |
---|
554 | close(fd); |
---|
555 | unlink(filename); |
---|
556 | return; |
---|
557 | } |
---|
558 | |
---|
559 | make_temp_name(filename, name); |
---|
560 | |
---|
561 | if (debug_flag) |
---|
562 | printf("Setting lock on %s: ", filename); |
---|
563 | |
---|
564 | /* |
---|
565 | * Unlink the old file in case someone else already has a lock on |
---|
566 | * it...we'll override them with our new file. |
---|
567 | */ |
---|
568 | unlink(filename); |
---|
569 | fd = open(filename, O_CREAT|O_RDWR, 0644); |
---|
570 | if (!fd) { |
---|
571 | fprintf(stderr,"Can't open %s: %s\n", filename, |
---|
572 | sys_errlist[errno]); |
---|
573 | fprintf(stderr, abort_msg); |
---|
574 | exit(ERR_FATAL); |
---|
575 | } |
---|
576 | |
---|
577 | if (debug_flag) |
---|
578 | printf("%d\n", fd); |
---|
579 | |
---|
580 | #ifdef POSIX |
---|
581 | fl.l_type = F_WRLCK; |
---|
582 | fl.l_whence = SEEK_SET; |
---|
583 | fl.l_start = 0; |
---|
584 | fl.l_len = 0; |
---|
585 | fl.l_pid = getpid(); |
---|
586 | fcntl(fd, F_SETLKW, &fl); |
---|
587 | #else |
---|
588 | flock(fd, LOCK_EX); |
---|
589 | #endif |
---|
590 | } |
---|
591 | |
---|
592 | #ifdef DEBUG |
---|
593 | /* |
---|
594 | * Dump used file descriptors...useful for debugging |
---|
595 | */ |
---|
596 | |
---|
597 | fd_dump() |
---|
598 | { |
---|
599 | int i; |
---|
600 | char b; |
---|
601 | |
---|
602 | printf("FD's in use: "); |
---|
603 | for (i=0;i<64;i++) |
---|
604 | if (read(i,&b,0) >= 0) |
---|
605 | printf("%d ",i); |
---|
606 | printf("\n"); |
---|
607 | } |
---|
608 | #endif |
---|
609 | |
---|
610 | /* |
---|
611 | * String comparison for filesystem names - case insensitive for hesiod, |
---|
612 | * sensitive for explicit. |
---|
613 | */ |
---|
614 | |
---|
615 | int hescmp(at, s) |
---|
616 | struct _attachtab *at; |
---|
617 | char *s; |
---|
618 | { |
---|
619 | if (at->explicit) |
---|
620 | return (strcmp(at->hesiodname, s)); |
---|
621 | return (strcasecmp(at->hesiodname, s)); |
---|
622 | } |
---|
623 | |
---|
624 | /* |
---|
625 | * Check to see if we have root priv's; give an error if we don't. |
---|
626 | */ |
---|
627 | void check_root_privs(progname) |
---|
628 | char *progname; |
---|
629 | { |
---|
630 | if (!real_uid || !effective_uid || (debug_flag)) |
---|
631 | return; |
---|
632 | fprintf(stderr, |
---|
633 | "%s must be setuid to root for this operation to succeed.\n", |
---|
634 | progname); |
---|
635 | exit(ERR_FATAL); |
---|
636 | /* NOTREACHED */ |
---|
637 | } |
---|
638 | |
---|
639 | void add_options(mopt, string) |
---|
640 | struct mntopts *mopt; |
---|
641 | char *string; |
---|
642 | { |
---|
643 | char *next, *arg, *str, *orig_str; |
---|
644 | |
---|
645 | orig_str = str = strdup(string); |
---|
646 | while (str && *str) { |
---|
647 | next = strchr(str, ','); |
---|
648 | if (next) { |
---|
649 | *next++ = '\0'; |
---|
650 | } |
---|
651 | arg = strchr(str, '='); |
---|
652 | if (arg) |
---|
653 | *arg++ = '\0'; |
---|
654 | if (!strcmp(str, "ro")) { |
---|
655 | mopt->flags |= M_RDONLY; |
---|
656 | #if defined(ultrix) && defined(NFS) |
---|
657 | if (mopt->type == MOUNT_NFS) { |
---|
658 | mopt->tsa.nfs.gfs_flags |= M_RONLY; |
---|
659 | mopt->tsa.nfs.flags |= NFSMNT_RONLY; |
---|
660 | } |
---|
661 | #endif /* ultrix && NFS */ |
---|
662 | } else if (!strcmp(str, "rw")) { |
---|
663 | #ifdef ultrix |
---|
664 | mopt->flags &= ~M_RDONLY; |
---|
665 | mopt->tsa.nfs.gfs_flags &= ~M_RONLY; |
---|
666 | mopt->tsa.nfs.flags &= ~NFSMNT_RONLY; |
---|
667 | #else /* !ultrix */ |
---|
668 | mopt->flags &= ~M_RDONLY; |
---|
669 | #endif /* ultrix */ |
---|
670 | } |
---|
671 | #ifdef ultrix |
---|
672 | /* process other ultrix options */ |
---|
673 | else if (!strcmp(str, "force")) { |
---|
674 | #ifdef NFS |
---|
675 | if (mopt->type == MOUNT_NFS) |
---|
676 | mopt->tsa.nfs.gfs_flags |= M_FORCE; |
---|
677 | else |
---|
678 | #endif /* NFS */ |
---|
679 | if (mopt->type == MOUNT_UFS) |
---|
680 | mopt->tsa.ufs.ufs_flags |= M_FORCE; |
---|
681 | } else if (!strcmp(str, "sync")) { |
---|
682 | #ifdef NFS |
---|
683 | if (mopt->type == MOUNT_NFS) |
---|
684 | mopt->tsa.nfs.gfs_flags |= M_SYNC; |
---|
685 | else |
---|
686 | #endif /* NFS */ |
---|
687 | if (mopt->type == MOUNT_UFS) |
---|
688 | mopt->tsa.ufs.ufs_flags |= M_SYNC; |
---|
689 | } else if (!strcmp(str, "pgthresh")) { |
---|
690 | int pgthresh; |
---|
691 | |
---|
692 | if (!arg) { |
---|
693 | missarg("pgthresh"); |
---|
694 | continue; |
---|
695 | } |
---|
696 | pgthresh = atoi(arg); |
---|
697 | pgthresh = max (pgthresh, MINPGTHRESH/PGUNITS); |
---|
698 | #ifdef NFS |
---|
699 | if (mopt->type == MOUNT_NFS) { |
---|
700 | mopt->tsa.nfs.pg_thresh = pgthresh; |
---|
701 | mopt->tsa.nfs.flags |= NFSMNT_PGTHRESH; |
---|
702 | } else |
---|
703 | #endif /* NFS */ |
---|
704 | if (mopt->type == MOUNT_UFS) |
---|
705 | mopt->tsa.ufs.ufs_pgthresh = pgthresh; |
---|
706 | } else if (!strcmp(str, "quota")) { |
---|
707 | if (mopt->type == MOUNT_UFS) |
---|
708 | mopt->tsa.ufs.ufs_flags |= M_QUOTA; |
---|
709 | } else if (!strcmp(str, "noexec")) { |
---|
710 | #ifdef NFS |
---|
711 | if (mopt->type == MOUNT_NFS) |
---|
712 | mopt->tsa.nfs.gfs_flags |= M_NOEXEC; |
---|
713 | else |
---|
714 | #endif /* NFS */ |
---|
715 | if (mopt->type == MOUNT_UFS) |
---|
716 | mopt->tsa.ufs.ufs_flags |= M_NOEXEC; |
---|
717 | } else if (!strcmp(str, "nocache")) { |
---|
718 | #ifdef NFS |
---|
719 | if (mopt->type == MOUNT_NFS) |
---|
720 | mopt->tsa.nfs.gfs_flags |= M_NOCACHE; |
---|
721 | else |
---|
722 | #endif /* NFS */ |
---|
723 | if (mopt->type == MOUNT_UFS) |
---|
724 | mopt->tsa.ufs.ufs_flags |= M_NOCACHE; |
---|
725 | } else if (!strcmp(str, "nodev")) { |
---|
726 | #ifdef NFS |
---|
727 | if (mopt->type == MOUNT_NFS) |
---|
728 | mopt->tsa.nfs.gfs_flags |= M_NODEV; |
---|
729 | else |
---|
730 | #endif /* NFS */ |
---|
731 | if (mopt->type == MOUNT_UFS) |
---|
732 | mopt->tsa.ufs.ufs_flags |= M_NODEV; |
---|
733 | } |
---|
734 | #endif /* ultrix */ |
---|
735 | #ifndef AIX |
---|
736 | else if (!strcmp(str, "nosuid")) { |
---|
737 | #ifdef ultrix |
---|
738 | #ifdef NFS |
---|
739 | if (mopt->type == MOUNT_NFS) |
---|
740 | mopt->tsa.nfs.gfs_flags |= M_NOSUID; |
---|
741 | else |
---|
742 | #endif /* NFS */ |
---|
743 | if (mopt->type == MOUNT_UFS) |
---|
744 | mopt->tsa.ufs.ufs_flags |= M_NOSUID; |
---|
745 | #else /* !ultrix */ |
---|
746 | mopt->flags |= M_NOSUID; |
---|
747 | #endif /* ultrix */ |
---|
748 | } |
---|
749 | #endif /* AIX */ |
---|
750 | #ifdef NFS |
---|
751 | else if (mopt->type == MOUNT_NFS) { |
---|
752 | if (!strcmp(str, "soft")) |
---|
753 | mopt->tsa.nfs.flags |= NFSMNT_SOFT; |
---|
754 | else if (!strcmp(str, "hard")) |
---|
755 | mopt->tsa.nfs.flags &= ~NFSMNT_SOFT; |
---|
756 | else if (!strcmp(str, "rsize")) { |
---|
757 | if (!arg) { |
---|
758 | missarg("rsize"); |
---|
759 | } |
---|
760 | mopt->tsa.nfs.rsize = atoi(arg); |
---|
761 | mopt->tsa.nfs.flags |= NFSMNT_RSIZE; |
---|
762 | } else if (!strcmp(str, "wsize")) { |
---|
763 | if (!arg) { |
---|
764 | missarg("wsize"); |
---|
765 | continue; |
---|
766 | } |
---|
767 | mopt->tsa.nfs.wsize = atoi(arg); |
---|
768 | mopt->tsa.nfs.flags |= NFSMNT_WSIZE; |
---|
769 | } else if (!strcmp(str, "timeo")) { |
---|
770 | if (!arg) { |
---|
771 | missarg("timeo"); |
---|
772 | continue; |
---|
773 | } |
---|
774 | mopt->tsa.nfs.timeo = atoi(arg); |
---|
775 | mopt->tsa.nfs.flags |= NFSMNT_TIMEO; |
---|
776 | } else if (!strcmp(str, "retrans")) { |
---|
777 | if (!arg) { |
---|
778 | missarg("retrans"); |
---|
779 | continue; |
---|
780 | } |
---|
781 | mopt->tsa.nfs.retrans = atoi(arg); |
---|
782 | mopt->tsa.nfs.flags |= NFSMNT_RETRANS; |
---|
783 | } else if (!strcmp(str, "port")) { |
---|
784 | if (!arg) { |
---|
785 | missarg("port"); |
---|
786 | continue; |
---|
787 | } |
---|
788 | mopt->nfs_port = atoi(arg); |
---|
789 | } |
---|
790 | #ifdef ultrix |
---|
791 | else if (!strcmp(str, "intr")) { |
---|
792 | mopt->tsa.nfs.flags |= NFSMNT_INT; |
---|
793 | } |
---|
794 | #endif /* ultrix */ |
---|
795 | } |
---|
796 | #endif |
---|
797 | str = next; |
---|
798 | } |
---|
799 | free(orig_str); |
---|
800 | } |
---|
801 | |
---|
802 | static missarg(arg) |
---|
803 | char *arg; |
---|
804 | { |
---|
805 | fprintf(stderr, |
---|
806 | "%s: missing argument to mount option; ignoring.\n", |
---|
807 | arg); |
---|
808 | } |
---|
809 | |
---|
810 | /* |
---|
811 | * Return a string describing the options in the mount options structure |
---|
812 | */ |
---|
813 | char *stropt(mopt) |
---|
814 | struct mntopts mopt; |
---|
815 | { |
---|
816 | static char buff[BUFSIZ]; |
---|
817 | char tmp[80]; |
---|
818 | |
---|
819 | buff[0] = '\0'; |
---|
820 | |
---|
821 | if (mopt.flags & M_RDONLY) |
---|
822 | (void) strcat(buff, ",ro"); |
---|
823 | else |
---|
824 | (void) strcat(buff, ",rw"); |
---|
825 | #ifdef M_NOSUID |
---|
826 | #ifdef ultrix |
---|
827 | #ifdef NFS |
---|
828 | if (mopt.type == MOUNT_NFS && (mopt.tsa.nfs.gfs_flags & M_NOSUID)) |
---|
829 | (void) strcat(buff, ",nosuid"); |
---|
830 | else |
---|
831 | #endif /* NFS */ |
---|
832 | if (mopt.type == MOUNT_UFS && (mopt.tsa.ufs.ufs_flags & M_NOSUID)) |
---|
833 | (void) strcat(buff, ",nosuid"); |
---|
834 | #else /* !ultrix */ |
---|
835 | if (mopt.flags & M_NOSUID) |
---|
836 | (void) strcat(buff, ",nosuid"); |
---|
837 | #endif /* ultrix */ |
---|
838 | #endif /* M_NOSUID */ |
---|
839 | #ifdef NFS |
---|
840 | if (mopt.type == MOUNT_NFS) { |
---|
841 | #ifdef ultrix |
---|
842 | if (mopt.tsa.nfs.gfs_flags & M_FORCE) |
---|
843 | (void) strcat(buff, ",force"); |
---|
844 | if (mopt.tsa.nfs.gfs_flags & M_SYNC) |
---|
845 | (void) strcat(buff, ",force"); |
---|
846 | if (mopt.tsa.nfs.flags & NFSMNT_PGTHRESH) { |
---|
847 | (void) strcat(buff, ",pgthresh="); |
---|
848 | (void) sprintf(tmp, "%d", mopt.tsa.nfs.pg_thresh); |
---|
849 | (void) strcat(buff, tmp); |
---|
850 | } |
---|
851 | if (mopt.tsa.nfs.gfs_flags & M_NOEXEC) |
---|
852 | (void) strcat(buff, ",noexec"); |
---|
853 | if (mopt.tsa.nfs.gfs_flags & M_NOCACHE) |
---|
854 | (void) strcat(buff, ",nocache"); |
---|
855 | if (mopt.tsa.nfs.gfs_flags & M_NODEV) |
---|
856 | (void) strcat(buff, ",nodev"); |
---|
857 | if (mopt.tsa.nfs.flags & NFSMNT_INT) |
---|
858 | (void) strcat(buff, ",intr"); |
---|
859 | #endif /* ultrix */ |
---|
860 | if (mopt.tsa.nfs.flags & NFSMNT_SOFT) |
---|
861 | (void) strcat(buff, ",soft"); |
---|
862 | if (mopt.tsa.nfs.flags & NFSMNT_RSIZE) { |
---|
863 | (void) strcat(buff, ",rsize="); |
---|
864 | (void) sprintf(tmp, "%d", mopt.tsa.nfs.rsize); |
---|
865 | (void) strcat(buff, tmp); |
---|
866 | } |
---|
867 | if (mopt.tsa.nfs.flags & NFSMNT_WSIZE) { |
---|
868 | (void) strcat(buff, ",wsize="); |
---|
869 | (void) sprintf(tmp, "%d", mopt.tsa.nfs.wsize); |
---|
870 | (void) strcat(buff, tmp); |
---|
871 | } |
---|
872 | if (mopt.tsa.nfs.flags & NFSMNT_TIMEO) { |
---|
873 | (void) strcat(buff, ",timeo="); |
---|
874 | (void) sprintf(tmp, "%d", mopt.tsa.nfs.timeo); |
---|
875 | (void) strcat(buff, tmp); |
---|
876 | } |
---|
877 | if (mopt.tsa.nfs.flags & NFSMNT_RETRANS) { |
---|
878 | (void) strcat(buff, ",retrans="); |
---|
879 | (void) sprintf(tmp, "%d", mopt.tsa.nfs.retrans); |
---|
880 | (void) strcat(buff, tmp); |
---|
881 | } |
---|
882 | if (mopt.nfs_port) { |
---|
883 | (void) strcat(buff, ",port="); |
---|
884 | (void) sprintf(tmp, "%d", mopt.nfs_port); |
---|
885 | (void) strcat(buff, tmp); |
---|
886 | } |
---|
887 | } |
---|
888 | #endif /* NFS */ |
---|
889 | #ifdef ultrix |
---|
890 | else if (mopt.type == MOUNT_UFS) { |
---|
891 | if (mopt.tsa.ufs.ufs_flags & M_QUOTA) |
---|
892 | (void) strcat(buff, ",quota"); |
---|
893 | if (mopt.tsa.ufs.ufs_flags & M_FORCE) |
---|
894 | (void) strcat(buff, ",force"); |
---|
895 | if (mopt.tsa.ufs.ufs_flags & M_SYNC) |
---|
896 | (void) strcat(buff, ",force"); |
---|
897 | if (mopt.tsa.ufs.ufs_pgthresh != DEFPGTHRESH) { |
---|
898 | (void) strcat(buff, ",pgthresh="); |
---|
899 | (void) sprintf(tmp, "%d", mopt.tsa.ufs.ufs_pgthresh); |
---|
900 | (void) strcat(buff, tmp); |
---|
901 | } |
---|
902 | if (mopt.tsa.ufs.ufs_flags & M_NOEXEC) |
---|
903 | (void) strcat(buff, ",noexec"); |
---|
904 | if (mopt.tsa.ufs.ufs_flags & M_NOCACHE) |
---|
905 | (void) strcat(buff, ",nocache"); |
---|
906 | if (mopt.tsa.ufs.ufs_flags & M_NODEV) |
---|
907 | (void) strcat(buff, ",nodev"); |
---|
908 | } |
---|
909 | #endif /* ultrix */ |
---|
910 | |
---|
911 | return(buff+1); |
---|
912 | } |
---|
913 | |
---|
914 | /* |
---|
915 | * Display the userid, given a uid (if possible) |
---|
916 | */ |
---|
917 | char *struid(uid) |
---|
918 | int uid; |
---|
919 | { |
---|
920 | struct passwd *pw; |
---|
921 | static char buff[64]; |
---|
922 | |
---|
923 | pw = getpwuid(uid); |
---|
924 | if (pw) |
---|
925 | strncpy(buff, pw->pw_name, sizeof(buff)); |
---|
926 | else |
---|
927 | sprintf(buff, "#%d", uid); |
---|
928 | return(buff); |
---|
929 | } |
---|
930 | |
---|
931 | /* |
---|
932 | * Compare if two hosts are the same |
---|
933 | */ |
---|
934 | int host_compare(host1, host2) |
---|
935 | char *host1; |
---|
936 | char *host2; |
---|
937 | { |
---|
938 | char bfr[BUFSIZ]; |
---|
939 | static char last_host[BUFSIZ] = "********"; |
---|
940 | static struct in_addr sin1, sin2; |
---|
941 | struct hostent *host; |
---|
942 | |
---|
943 | /* |
---|
944 | * Cache the last host1, for efficiency's sake. |
---|
945 | */ |
---|
946 | if (strcmp(host1, last_host)) { |
---|
947 | strcpy(last_host, host1); |
---|
948 | if ((sin1.s_addr = inet_addr(host1)) == -1) { |
---|
949 | if (host = gethostbyname(host1)) |
---|
950 | #ifdef POSIX |
---|
951 | memmove(&sin1, host->h_addr, (sizeof sin1)); |
---|
952 | #else |
---|
953 | bcopy(host->h_addr, &sin1, (sizeof sin1)); |
---|
954 | #endif |
---|
955 | else { |
---|
956 | if (debug_flag) { |
---|
957 | sprintf(bfr, "%s: gethostbyname", |
---|
958 | host1); |
---|
959 | perror(bfr); |
---|
960 | } |
---|
961 | return(!strcmp(host1, host2)); |
---|
962 | } |
---|
963 | } |
---|
964 | } |
---|
965 | if ((sin2.s_addr = inet_addr(host2)) == -1) { |
---|
966 | if (host = gethostbyname(host2)) |
---|
967 | #ifdef POSIX |
---|
968 | memmove(&sin2, host->h_addr, (sizeof sin2)); |
---|
969 | #else |
---|
970 | bcopy(host->h_addr, &sin2, (sizeof sin2)); |
---|
971 | #endif |
---|
972 | else { |
---|
973 | if (debug_flag) { |
---|
974 | sprintf(bfr, "%s: gethostbyname", host2); |
---|
975 | perror(bfr); |
---|
976 | } |
---|
977 | return(!strcmp(host1, host2)); |
---|
978 | } |
---|
979 | } |
---|
980 | return(!memcmp(&sin1, &sin2, (sizeof sin1))); |
---|
981 | } |
---|
982 | |
---|
983 | /* |
---|
984 | * Owner list code, originally written by jfc |
---|
985 | */ |
---|
986 | int clean_attachtab(atp) |
---|
987 | struct _attachtab *atp; |
---|
988 | { |
---|
989 | struct passwd *pw; |
---|
990 | int i; |
---|
991 | for(i=0;i<atp->nowners;i++) |
---|
992 | if(NULL == (pw = getpwuid(atp->owners[i]))) { |
---|
993 | int j; |
---|
994 | /* Unmap */ |
---|
995 | if (atp->fs->type == TYPE_NFS && do_nfsid) { |
---|
996 | if (debug_flag) |
---|
997 | fprintf(stderr, |
---|
998 | "nfs unmap(%s, %d)\n", |
---|
999 | atp->host, atp->owners[i]); |
---|
1000 | (void) nfsid(atp->host, atp->hostaddr[0], |
---|
1001 | MOUNTPROC_KUIDUMAP, 1, |
---|
1002 | atp->hesiodname, 0, atp->owners[i]); |
---|
1003 | } |
---|
1004 | for(j=i+1;j<atp->nowners;j++) |
---|
1005 | atp->owners[j-1] = atp->owners[j]; |
---|
1006 | atp->nowners--; |
---|
1007 | i--; |
---|
1008 | } |
---|
1009 | return atp->nowners; |
---|
1010 | } |
---|
1011 | |
---|
1012 | void add_an_owner(atp,uid) |
---|
1013 | uid_t uid; |
---|
1014 | struct _attachtab *atp; |
---|
1015 | { |
---|
1016 | register int i; |
---|
1017 | for(i=0;i<atp->nowners;i++) |
---|
1018 | if(atp->owners[i] == uid) |
---|
1019 | return; |
---|
1020 | if(atp->nowners < MAXOWNERS) |
---|
1021 | atp->owners[atp->nowners++] = uid; |
---|
1022 | else |
---|
1023 | /* fail silently */; |
---|
1024 | } |
---|
1025 | |
---|
1026 | int is_an_owner(at,uid) |
---|
1027 | uid_t uid; |
---|
1028 | struct _attachtab *at; |
---|
1029 | { |
---|
1030 | register int i; |
---|
1031 | if (!at->nowners) |
---|
1032 | return(1); /* If no one claims it, anyone can have it */ |
---|
1033 | for(i=0;i<at->nowners;i++) |
---|
1034 | if(at->owners[i] == uid) |
---|
1035 | return 1; |
---|
1036 | return 0; |
---|
1037 | } |
---|
1038 | |
---|
1039 | #ifdef ZEPHYR |
---|
1040 | int wants_to_subscribe(at, uid, zero_too) |
---|
1041 | uid_t uid; |
---|
1042 | struct _attachtab *at; |
---|
1043 | int zero_too; /* also true if root ? */ |
---|
1044 | { |
---|
1045 | register int i; |
---|
1046 | |
---|
1047 | for(i = 0;i < at->nowners;i++) |
---|
1048 | if((zero_too && at->owners[i] == 0) || at->owners[i] == uid) |
---|
1049 | return 1; |
---|
1050 | return 0; |
---|
1051 | } |
---|
1052 | #endif |
---|
1053 | |
---|
1054 | int del_an_owner(at,uid) |
---|
1055 | uid_t uid; |
---|
1056 | struct _attachtab *at; |
---|
1057 | { |
---|
1058 | register int i; |
---|
1059 | for(i=0;i<at->nowners;i++) |
---|
1060 | if(at->owners[i] == uid) { |
---|
1061 | --at->nowners; |
---|
1062 | for(;i<at->nowners;i++) |
---|
1063 | at->owners[i] = at->owners[i+1]; |
---|
1064 | return at->nowners; |
---|
1065 | } |
---|
1066 | if(at->nowners == 0) |
---|
1067 | at->owners[0] = -1; |
---|
1068 | return at->nowners; |
---|
1069 | } |
---|
1070 | |
---|
1071 | char *ownerlist(atp) |
---|
1072 | struct _attachtab *atp; |
---|
1073 | { |
---|
1074 | static char ret[256]; |
---|
1075 | int i,len=1; |
---|
1076 | if(atp->nowners == 0) |
---|
1077 | return("{}"); |
---|
1078 | else if(atp->nowners == 1) |
---|
1079 | return struid(atp->owners[0]); |
---|
1080 | |
---|
1081 | ret[0] = '{'; |
---|
1082 | for(i=0;i<atp->nowners;i++) { |
---|
1083 | char *u = struid(atp->owners[i]); |
---|
1084 | int tmp = strlen(u); |
---|
1085 | if(i) |
---|
1086 | ret[len++] = ','; |
---|
1087 | if(len+tmp >= 255) { |
---|
1088 | ret[len++] = '}'; |
---|
1089 | ret[len] = '\0'; |
---|
1090 | return ret; |
---|
1091 | } |
---|
1092 | strcpy(ret+len,u); |
---|
1093 | len += tmp; |
---|
1094 | } |
---|
1095 | ret[len++] = '}'; |
---|
1096 | ret[len] = '\0'; |
---|
1097 | return ret; |
---|
1098 | } |
---|
1099 | |
---|
1100 | |
---|
1101 | int parse_username(s) |
---|
1102 | const char *s; |
---|
1103 | { |
---|
1104 | struct passwd *pw; |
---|
1105 | const char *os = s; |
---|
1106 | |
---|
1107 | pw = getpwnam((char *)s); |
---|
1108 | if (pw) |
---|
1109 | return(pw->pw_uid); |
---|
1110 | else { |
---|
1111 | if (*s == '#') |
---|
1112 | s++; |
---|
1113 | if (isdigit(*s)) |
---|
1114 | return(atoi(s)); |
---|
1115 | fprintf(stderr, "Can't parse username/uid string: %s\n", os); |
---|
1116 | exit(1); |
---|
1117 | /* NOTREACHED */ |
---|
1118 | } |
---|
1119 | } |
---|
1120 | |
---|
1121 | |
---|
1122 | int parse_groupname(s) |
---|
1123 | const char *s; |
---|
1124 | { |
---|
1125 | struct group *gr; |
---|
1126 | |
---|
1127 | gr = getgrnam((char *)s); |
---|
1128 | if (gr) |
---|
1129 | return(gr->gr_gid); |
---|
1130 | else { |
---|
1131 | if (*s == '#') |
---|
1132 | s++; |
---|
1133 | if (isdigit(*s)) |
---|
1134 | return(atoi(s)); |
---|
1135 | fprintf(stderr, "Can't parse groupname/gid string: %s\n", s); |
---|
1136 | exit(1); |
---|
1137 | /* NOTREACHED */ |
---|
1138 | } |
---|
1139 | } |
---|
1140 | |
---|
1141 | |
---|
1142 | char *errstr(e) |
---|
1143 | int e; |
---|
1144 | { |
---|
1145 | if(e < sys_nerr) |
---|
1146 | return sys_errlist[e]; |
---|
1147 | else |
---|
1148 | return "Unknown error"; |
---|
1149 | } |
---|