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/*
23 * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <errno.h>
32#include <sys/types.h>
33#include <ctype.h>
34#include <string.h>
35#include <strings.h>
36#include <thread.h>
37#include <synch.h>
38#include "libfsmgt.h"
39
40/*
41 * Private datastructures.
42 */
43typedef struct dfstab_entry {
44	struct dfstab_entry *next;
45	char    *path;
46	char    *resource;
47	char    *fstype;
48	char    *options;
49	char    *description;
50} dfstab_entry_t;
51
52static const char *whitespace = " \t";
53static mutex_t dfstab_lock = DEFAULTMUTEX;
54
55/*
56 * Private functions
57 */
58static dfstab_entry_t *get_dfstab_ents(int *);
59static void free_dfstab_list(dfstab_entry_t *);
60static dfstab_entry_t *dfstab_line_to_dfstab_entry(char *, int *);
61static char *create_share_cmd(dfstab_entry_t *, char *, int *);
62static dfstab_entry_t *change_dfstab_ent(dfstab_entry_t *,
63	dfstab_entry_t *, int *);
64static void add_entry_to_dfstab(dfstab_entry_t *, int *);
65
66
67static dfstab_entry_t *
68get_dfstab_ents(int *err)
69{
70	dfstab_entry_t *dfstablist, *headptr, *tailptr = NULL;
71	FILE *dfp;		/* fp for dfs list */
72	static char cmd[BUFSIZE];
73	*err = 0;
74
75	if ((dfp = fopen(DFSTAB, "r")) != NULL) {
76		char *share_cmd;
77		(void) mutex_lock(&dfstab_lock);
78		while ((share_cmd =
79		    fileutil_getline(dfp, cmd, BUFSIZE)) != NULL) {
80			if ((dfstablist =
81			    dfstab_line_to_dfstab_entry(share_cmd, err)) !=
82			    NULL) {
83				if (tailptr == NULL) {
84					headptr = dfstablist;
85					tailptr = dfstablist;
86				} else {
87					tailptr->next = dfstablist;
88					tailptr = dfstablist;
89				}
90				dfstablist = dfstablist->next;
91			} else {
92				free(share_cmd);
93				break;
94			}
95			free(share_cmd);
96		}
97		if (tailptr == NULL) {
98			headptr = tailptr;
99		}
100		(void) mutex_unlock(&dfstab_lock);
101		fclose(dfp);
102	} else {
103		*err = errno;
104		(void) fprintf(stderr, "%s: cannot open %s\n", cmd, DFSTAB);
105		headptr = NULL;
106	}
107	return (headptr);
108} /* get_dfstab_ents */
109
110static void
111add_entry_to_dfstab(dfstab_entry_t *list, int *err)
112{
113	FILE *dfp;		/* fp for dfs list */
114
115	if ((dfp = fopen(DFSTAB, "a")) != NULL) {
116		char *share_cmd;
117		if ((share_cmd = create_share_cmd(list, NULL, err)) != NULL) {
118			(void) mutex_lock(&dfstab_lock);
119			fprintf(dfp, "%s", share_cmd);
120			fclose(dfp);
121			(void) mutex_unlock(&dfstab_lock);
122			free(share_cmd);
123		} else {
124			*err = errno;
125		}
126	} else {
127		*err = errno;
128	}
129
130} /* add_entry_to_dfstab */
131
132static void
133free_dfstab_list(dfstab_entry_t *headp)
134{
135	dfstab_entry_t *tmp = headp;
136
137	while (headp != NULL) {
138		tmp = headp->next;
139		if (headp->path != NULL) {
140			free(headp->path);
141		}
142		if (headp->resource != NULL) {
143			free(headp->resource);
144		}
145		if (headp->fstype != NULL) {
146			free(headp->fstype);
147		}
148		if (headp->options != NULL) {
149			free(headp->options);
150		}
151		if (headp->description != NULL) {
152			free(headp->description);
153		}
154		headp->next = NULL;
155		free(headp);
156		headp = tmp;
157	}
158} /* free_dfstab_list */
159
160static char *
161create_share_cmd(dfstab_entry_t *new_entry, char *temp_line, int *err)
162{
163	char tempstr[BUFSIZE];
164	char *cmd, *ret_val;
165
166	cmd = (char *)calloc((size_t)1, BUFSIZE);
167	if (cmd == NULL) {
168		*err = errno;
169		return (NULL);
170	}
171	sprintf(cmd, "share ");
172	if (new_entry->fstype) {
173		sprintf(tempstr, "-F %s ", new_entry->fstype);
174		strlcat(cmd, tempstr, BUFSIZE);
175	}
176	if (new_entry->options) {
177		sprintf(tempstr, "-o %s ", new_entry->options);
178		strlcat(cmd, tempstr, BUFSIZE);
179	}
180	if (new_entry->description) {
181		sprintf(tempstr, "-d %s ",
182		    new_entry->description);
183		strlcat(cmd, tempstr, BUFSIZE);
184	}
185	sprintf(tempstr, "%s\n", new_entry->path);
186	strlcat(cmd, tempstr, BUFSIZE);
187	if (temp_line != NULL && strchr(temp_line, '#')) {
188		sprintf(tempstr, " %s", strchr(temp_line, '#'));
189		strlcat(cmd, tempstr, BUFSIZE);
190	}
191	ret_val = strdup(cmd);
192	free(cmd);
193	return (ret_val);
194} /* create_share_cmd */
195
196/*
197 * dfstab_line_to_dfstab_entry - parses a line from dfstab and fills in
198 * the fields of a dfstab_entry_t structure
199 * Parameters:
200 * char *cmd - the share command or dfstab line to be parsed
201 * int *err - a pointer for returning any error codes encountered
202 */
203static dfstab_entry_t *
204dfstab_line_to_dfstab_entry(char *cmd, int *err)
205{
206
207	dfstab_entry_t *dfstablist;
208	extern char *optarg;
209	extern int optind;
210	int c, argcount = 0;
211	char *temp_str;
212	char *arglist[LINESZ];
213
214	c = 0;
215	optind = 1;
216
217	temp_str = strdup(cmd);
218	if (temp_str == NULL) {
219		*err = ENOMEM;
220		return (NULL);
221	}
222
223	for (arglist[argcount] = strtok(temp_str, whitespace);
224	    arglist[argcount] != NULL; /* CSTYLED */) {
225		arglist[++argcount] = strtok(NULL, whitespace);
226	}
227	argcount--;
228	dfstablist =
229	    (dfstab_entry_t *)calloc((size_t)1,
230	    sizeof (dfstab_entry_t));
231	if (dfstablist == NULL) {
232		*err = ENOMEM;
233		free(temp_str);
234		return (NULL);
235	}
236	while ((c = getopt(argcount, arglist, "F:d:o:")) != -1) {
237		switch (c) {
238		case 'F':
239					/* file system type */
240					/* at most one -F */
241			*err |= (dfstablist->fstype != NULL);
242			dfstablist->fstype = strdup(optarg);
243			if (dfstablist->fstype == NULL) {
244				*err = ENOMEM;
245				free_dfstab_list(dfstablist);
246				free(temp_str);
247				return (NULL);
248			}
249			break;
250		case 'd':		/* description */
251					/* at most one -d */
252			*err |= (dfstablist->description != NULL);
253			dfstablist->description = strdup(optarg);
254			if (dfstablist->description == NULL) {
255				*err = ENOMEM;
256				free_dfstab_list(dfstablist);
257				free(temp_str);
258				return (NULL);
259			}
260			break;
261		case 'o':		/* fs specific options */
262					/* at most one - o */
263			*err |= (dfstablist->options != NULL);
264			dfstablist->options = strdup(optarg);
265			if (dfstablist->options == NULL) {
266				*err = ENOMEM;
267				free_dfstab_list(dfstablist);
268				free(temp_str);
269				return (NULL);
270			}
271			break;
272		case '?':
273			*err = 1;
274			break;
275		}
276	}
277	if (dfstablist->fstype == NULL) {
278		FILE *fp;
279
280		if ((fp = fopen(DFSTYPES, "r")) == NULL) {
281			(void) fprintf(stderr, "%s: cannot open %s\n",
282			    cmd, DFSTYPES);
283			free_dfstab_list(dfstablist);
284			free(temp_str);
285			return (NULL);
286		}
287		(void) mutex_lock(&dfstab_lock);
288		dfstablist->fstype = strdup(fileutil_getfs(fp));
289		(void) mutex_unlock(&dfstab_lock);
290		fclose(fp);
291	}
292	dfstablist->path = strdup(arglist[argcount]);
293	if (dfstablist->path == NULL) {
294		*err = ENOMEM;
295		free_dfstab_list(dfstablist);
296		free(temp_str);
297		return (NULL);
298	}
299	free(temp_str);
300	return (dfstablist);
301} /* dfstab_line_to_dfstab_entry */
302
303static dfstab_entry_t *
304change_dfstab_ent(
305	dfstab_entry_t *old_entry,
306	dfstab_entry_t *new_entry,
307	int *err)
308{
309
310	FILE *fp;
311	dfstab_entry_t *temp_list, *ret_val;
312	char cmd[BUFSIZE];
313	char **temp_dfstab = NULL;
314	int line_found = 0;
315
316	if ((fp = fopen(DFSTAB, "r")) != NULL) {
317		char *share_cmd;
318		int count = 0;
319		(void) mutex_lock(&dfstab_lock);
320		while (fgets(cmd, BUFSIZE, fp) != NULL) {
321			if ((share_cmd =
322			    fileutil_get_cmd_from_string(cmd)) == NULL) {
323				if (!fileutil_add_string_to_array(
324				    &temp_dfstab, cmd, &count, err)) {
325					ret_val = NULL;
326					line_found = 0;
327					break;
328				}
329				continue;
330			}
331			if ((temp_list =
332			    dfstab_line_to_dfstab_entry(share_cmd, err)) ==
333			    NULL) {
334				free(share_cmd);
335				ret_val = NULL;
336				break;
337			}
338			if (strcmp(old_entry->path,
339			    temp_list->path) == 0) {
340				char *new_cmd = NULL;
341				line_found = 1;
342				if (new_entry != NULL && (new_cmd =
343				    create_share_cmd(new_entry, cmd,
344				    err)) != NULL) {
345					if (!fileutil_add_string_to_array(
346					    &temp_dfstab, new_cmd, &count,
347					    err)) {
348						ret_val = NULL;
349						line_found = 0;
350						free(share_cmd);
351						free(new_cmd);
352						break;
353					}
354					free(new_cmd);
355				}
356			} else {
357				if (!fileutil_add_string_to_array(
358				    &temp_dfstab, cmd, &count, err)) {
359					free(share_cmd);
360					ret_val = NULL;
361					line_found = 0;
362					break;
363				}
364			}
365			free_dfstab_list(temp_list);
366			free(share_cmd);
367		}
368		fclose(fp);
369
370		if (line_found && temp_dfstab != NULL) {
371			if ((fp = fopen(DFSTAB, "w")) != NULL) {
372				int i;
373				for (i = 0; i < count; i++) {
374					fprintf(fp, "%s", temp_dfstab[i]);
375				}
376				fclose(fp);
377				(void) mutex_unlock(&dfstab_lock);
378				ret_val = get_dfstab_ents(err);
379				fileutil_free_string_array(temp_dfstab, count);
380			} else {
381				*err = errno;
382				(void) mutex_unlock(&dfstab_lock);
383				fileutil_free_string_array(temp_dfstab, count);
384				ret_val = NULL;
385			}
386		} else {
387			(void) mutex_unlock(&dfstab_lock);
388			if (temp_dfstab != NULL) {
389				fileutil_free_string_array(temp_dfstab, count);
390			}
391			ret_val = NULL;
392		}
393	} else {
394		*err = errno;
395		ret_val = NULL;
396	}
397	return (ret_val);
398} /* change_dfstab_ent */
399
400/*
401 * Public accessor functions.
402 */
403
404/*
405 * fs_add_DFStab_ent - adds an entry to dfstab and to the list of dfstab
406 * entries. Returns a pointer to the head of the dfstab entry list.
407 * Parameters:
408 * char *cmd - the same command to be added to dstab
409 * int *err - an error pointer for retruning any errors
410 */
411fs_dfstab_entry_t
412fs_add_DFStab_ent(char *cmd, int *err)
413{
414	dfstab_entry_t *dfstab_ent;
415
416	dfstab_ent = dfstab_line_to_dfstab_entry(cmd, err);
417	if (dfstab_ent == NULL) {
418		*err = errno;
419		return (NULL);
420	}
421	add_entry_to_dfstab(dfstab_ent, err);
422	if (*err != 0) {
423		free_dfstab_list(dfstab_ent);
424		return (NULL);
425	}
426	free_dfstab_list(dfstab_ent);
427	return (get_dfstab_ents(err));
428}
429
430/*
431 * set_DFStab_ent - adds an entry to dfstab and to the list of dfstab entries.
432 * returns a pointer to the head of the dfstab entry list.
433 */
434fs_dfstab_entry_t
435fs_set_DFStab_ent(
436	char *path,
437	char *fstype,
438	char *options,
439	char *description,
440	int *err)
441{
442
443	dfstab_entry_t *new_entry;
444	new_entry = (dfstab_entry_t *)calloc((size_t)1,
445	    sizeof (dfstab_entry_t));
446	if (new_entry == NULL) {
447		*err = ENOMEM;
448		return (NULL);
449	}
450	if (path != NULL) {
451		new_entry->path = strdup(path);
452	} else {
453		*err = EINVAL;
454		free_dfstab_list(new_entry);
455		return (NULL);
456	}
457	if (fstype != NULL) {
458		new_entry->fstype = strdup(fstype);
459	} else {
460		FILE *fp;
461
462		if ((fp = fopen(DFSTYPES, "r")) == NULL) {
463			/* change this to error handler */
464			(void) fprintf(stderr, "cannot open %s\n",
465			    DFSTYPES);
466			free_dfstab_list(new_entry);
467			return (NULL);
468		}
469		(void) mutex_lock(&dfstab_lock);
470		new_entry->fstype = strdup(fileutil_getfs(fp));
471		(void) mutex_unlock(&dfstab_lock);
472		fclose(fp);
473	}
474	if (options != NULL) {
475		new_entry->options = strdup(options);
476	}
477	if (description != NULL) {
478		new_entry->description = strdup(description);
479	}
480	add_entry_to_dfstab(new_entry, err);
481	if (*err != 0) {
482		free_dfstab_list(new_entry);
483		return (NULL);
484	}
485	free_dfstab_list(new_entry);
486	return (get_dfstab_ents(err));
487} /* set_DFStab_ent */
488
489/*
490 * Accessor function for path element of dfstab entry.
491 */
492char *
493fs_get_DFStab_ent_Path(void *entry)
494{
495	dfstab_entry_t *entryptr = (dfstab_entry_t *)entry;
496	if (entryptr == NULL) {
497		return (NULL);
498	}
499	return (entryptr->path);
500} /* get_DFStab_ent_Path */
501
502/*
503 * Accessor function for fstype element of dfstab entry.
504 */
505char *
506fs_get_DFStab_ent_Fstype(void *entry)
507{
508	dfstab_entry_t *entryptr = (dfstab_entry_t *)entry;
509	if (entryptr == NULL) {
510		return (NULL);
511	}
512	return (entryptr->fstype);
513}
514
515/*
516 * Accessor function for options element of dfstab entry.
517 */
518char *
519fs_get_DFStab_ent_Options(void *entry)
520{
521	dfstab_entry_t *entryptr = (dfstab_entry_t *)entry;
522	if (entryptr == NULL) {
523		return (NULL);
524	}
525	return (entryptr->options);
526}
527
528/*
529 * Accessor function for description element of dfstab entry.
530 */
531char *
532fs_get_DFStab_ent_Desc(void *entry)
533{
534	dfstab_entry_t *entryptr = (dfstab_entry_t *)entry;
535	if (entryptr == NULL) {
536		return (NULL);
537	}
538	return (entryptr->description);
539}
540
541/*
542 * Accessor function for resource element of dfstab entry.
543 */
544char *
545fs_get_DFStab_ent_Res(void *entry)
546{
547	dfstab_entry_t *entryptr = (dfstab_entry_t *)entry;
548	if (entryptr == NULL) {
549		return (NULL);
550	}
551	return (entryptr->resource);
552}
553
554
555/*
556 * Calls get_dfstab_ents to create the list of dfstab
557 * entries and returns that list.
558 */
559fs_dfstab_entry_t
560fs_get_DFStab_ents(int *err)
561{
562	dfstab_entry_t *list;
563	list = get_dfstab_ents(err);
564	return (list);
565}
566
567/*
568 * Retrives and returns the next entry in the list.
569 */
570fs_dfstab_entry_t
571fs_get_DFStab_ent_Next(void *list)
572{
573	dfstab_entry_t *listptr = (dfstab_entry_t *)list;
574	if (listptr == NULL) {
575		return (NULL);
576	}
577	return (listptr->next);
578}
579
580/*
581 * Retrives and returns a share command based on the dfstab entry passed in.
582 */
583char *
584fs_get_Dfstab_share_cmd(fs_dfstab_entry_t dfstab_ent, int *err)
585{
586	char *share_cmd;
587	if (dfstab_ent == NULL) {
588		return (NULL);
589	}
590	share_cmd = create_share_cmd((dfstab_entry_t *)dfstab_ent, NULL, err);
591	return (share_cmd);
592} /* fs_get_Dfstab_share_cmd */
593
594/*
595 * edit_DFStab_ent - changes an entry in dfstab.
596 */
597fs_dfstab_entry_t
598fs_edit_DFStab_ent(char *old_cmd, char *new_cmd, int *err)
599{
600	dfstab_entry_t *old_dfstabent, *new_dfstabent, *ret_val;
601
602	if ((old_dfstabent =
603	    dfstab_line_to_dfstab_entry(old_cmd, err)) == NULL) {
604		return (NULL);
605	}
606	if ((new_dfstabent =
607	    dfstab_line_to_dfstab_entry(new_cmd, err)) == NULL) {
608		return (NULL);
609	}
610	if ((ret_val =
611	    change_dfstab_ent(old_dfstabent, new_dfstabent, err)) == NULL) {
612		return (NULL);
613	}
614	free_dfstab_list(old_dfstabent);
615	free_dfstab_list(new_dfstabent);
616	return (ret_val);
617}
618
619/*
620 * del_DFStab_ent - deletes an entry in dfstab.
621 */
622fs_dfstab_entry_t
623fs_del_DFStab_ent(char *del_cmd, int *err)
624{
625	dfstab_entry_t *del_dfstabent, *ret_val;
626
627	if ((del_dfstabent =
628	    dfstab_line_to_dfstab_entry(del_cmd, err)) == NULL) {
629		return (NULL);
630	}
631	if ((ret_val =
632	    change_dfstab_ent(del_dfstabent, NULL, err)) == NULL) {
633		return (NULL);
634	}
635	free_dfstab_list(del_dfstabent);
636	return (ret_val);
637}
638
639/*
640 * del_All_DFStab_ents_with_Path - deletes all duplicate entries with
641 * the specified path.
642 */
643fs_dfstab_entry_t
644fs_del_All_DFStab_ents_with_Path(char *path, int *err)
645{
646	dfstab_entry_t del_dfstabent, *ret_val;
647
648	if (path != NULL) {
649		if ((del_dfstabent.path = strdup(path)) != NULL) {
650			if ((ret_val = change_dfstab_ent(&del_dfstabent,
651			    NULL, err)) == NULL) {
652				ret_val = NULL;
653			}
654			free(del_dfstabent.path);
655		} else {
656			*err = ENOMEM;
657			ret_val = NULL;
658		}
659	} else {
660		*err = EINVAL;
661		ret_val = NULL;
662	}
663	return (ret_val);
664}
665
666
667int
668fs_check_for_duplicate_DFStab_paths(char *path, int *err)
669{
670	dfstab_entry_t *dfstablist;
671	int count = 0;
672
673	*err = 0;
674	if (path == NULL) {
675		count = -1;
676	}
677	dfstablist = get_dfstab_ents(err);
678	if (dfstablist != NULL) {
679		while (dfstablist != NULL) {
680			if (strcmp(dfstablist->path, path) == 0) {
681				count++;
682			}
683			dfstablist = dfstablist->next;
684		}
685
686		free_dfstab_list(dfstablist);
687	} else {
688		if (err != 0)
689			count = *err;
690		else
691			count = 0;
692	}
693	return (count);
694}
695
696void
697fs_free_DFStab_ents(void *list)
698{
699	dfstab_entry_t *headp = (dfstab_entry_t *)list;
700	free_dfstab_list(headp);
701}
702
703/*
704 * used for debugging only
705 */
706void
707fs_print_dfstab_entries(void *list)
708{
709	while (list != NULL) {
710
711		if (fs_get_DFStab_ent_Fstype(list) != NULL)
712			printf("fstype: %s", fs_get_DFStab_ent_Fstype(list));
713		if (fs_get_DFStab_ent_Desc(list) != NULL)
714			printf(" description: %s",
715			    fs_get_DFStab_ent_Desc(list));
716		if (fs_get_DFStab_ent_Options(list) != NULL)
717			printf(" options: %s",
718			    fs_get_DFStab_ent_Options(list));
719		if (fs_get_DFStab_ent_Path(list) != NULL)
720			printf(" shared path is: %s\n",
721			    fs_get_DFStab_ent_Path(list));
722		list = (void *)fs_get_DFStab_ent_Next(list);
723	}
724
725}
726