/* $Id$ * * This is the file attach.c for the Moira Client, which allows users * to quickly and easily maintain most parts of the Moira database. * It Contains: Functions for maintaining data used by Hesiod * to map courses/projects/users to their file systems, * and maintain filesys info. * * Created: 5/4/88 * By: Chris D. Peterson * * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology. * For copying and distribution information, please see the file * . */ #include #include #include #include "defs.h" #include "f_defs.h" #include "globals.h" #include #include #include #include #include #include RCSID("$Header$"); char *canonicalize_cell(char *c); int GetAliasValue(int argc, char **argv, void *retval); void RealDeleteFS(char **info, Bool one_item); char *SortAfter(struct mqelem *elem, int count); void RealDeleteFSAlias(char **info, Bool one_item); #define FS_ALIAS_TYPE "FILESYS" #define LABEL 0 #define MACHINE 1 #define GROUP 2 #define ALIAS 3 #define NO_MACHINE ("[NONE]") #define DEFAULT_TYPE ("AFS") #define DEFAULT_MACHINE DEFAULT_NONE #define DEFAULT_PACK DEFAULT_NONE #define DEFAULT_ACCESS ("w") #define DEFAULT_COMMENTS DEFAULT_COMMENT #define DEFAULT_OWNER (user) #define DEFAULT_OWNERS (user) #define DEFAULT_CREATE DEFAULT_YES #define DEFAULT_L_TYPE ("PROJECT") #define DEFAULT_CELL ("athena.mit.edu") /* Function Name: SetDefaults * Description: sets the default values for filesystem additions. * Arguments: info - an array of char pointers to recieve defaults. * Returns: char ** (this array, now filled). */ static char **SetDefaults(char **info, char *name) { char buf[BUFSIZ]; info[FS_NAME] = strdup(name); info[FS_TYPE] = strdup(DEFAULT_TYPE); info[FS_MACHINE] = strdup(DEFAULT_MACHINE); info[FS_PACK] = strdup(DEFAULT_PACK); sprintf(buf, "/mit/%s", name); info[FS_M_POINT] = strdup(buf); info[FS_ACCESS] = strdup(DEFAULT_ACCESS); info[FS_COMMENTS] = strdup(DEFAULT_COMMENTS); info[FS_OWNER] = strdup(DEFAULT_OWNER); info[FS_OWNERS] = strdup(DEFAULT_OWNERS); info[FS_CREATE] = strdup(DEFAULT_CREATE); info[FS_L_TYPE] = strdup(DEFAULT_L_TYPE); info[FS_MODTIME] = info[FS_MODBY] = info[FS_MODWITH] = info[FS_END] = NULL; return info; } /* Function Name: GetFSInfo * Description: Stores the info in a queue. * Arguments: type - type of information to get. * name - name of the item to get information on. * Returns: a pointer to the first element in the queue. */ static struct mqelem *GetFSInfo(int type, char *name) { int stat; struct mqelem *elem = NULL; char *args[5]; switch (type) { case LABEL: if ((stat = do_mr_query("get_filesys_by_label", 1, &name, StoreInfo, &elem))) { com_err(program_name, stat, " in GetFSInfo"); return NULL; } break; case MACHINE: if ((stat = do_mr_query("get_filesys_by_machine", 1, &name, StoreInfo, &elem))) { com_err(program_name, stat, " in GetFSInfo"); return NULL; } break; case GROUP: if ((stat = do_mr_query("get_filesys_by_group", 1, &name, StoreInfo, &elem))) { com_err(program_name, stat, " in GetFSInfo"); return NULL; } break; case ALIAS: args[ALIAS_NAME] = name; args[ALIAS_TYPE] = FS_ALIAS_TYPE; args[ALIAS_TRANS] = "*"; if ((stat = do_mr_query("get_alias", 3, args, StoreInfo, &elem))) { com_err(program_name, stat, " in get_alias."); return NULL; } } return QueueTop(elem); } /* Function Name: PrintFSAlias * Description: Prints a filesystem alias * Arguments: info - an array contains the strings of info. * Returns: the name of the filesys - used be QueryLoop(). */ static char *PrintFSAlias(char **info) { char buf[BUFSIZ]; sprintf(buf, "Alias: %-25s Filesystem: %s", info[ALIAS_NAME], info[ALIAS_TRANS]); Put_message(buf); return info[ALIAS_NAME]; } static int fsgCount = 1; static void PrintFSGMembers(char **info) { char print_buf[BUFSIZ]; sprintf(print_buf, " %d. Filesystem: %-32s (sort key: %s)", fsgCount++, info[0], info[1]); Put_message(print_buf); } /* Function Name: PrintFSInfo * Description: Prints the filesystem information. * Arguments: info - a pointer to the filesystem information. * Returns: none. */ static char *PrintFSInfo(char **info) { char print_buf[BUFSIZ]; FORMFEED; if (!strcmp(info[FS_TYPE], "FSGROUP") || !strcmp(info[FS_TYPE], "MUL")) { int stat; struct mqelem *elem = NULL; if (!strcmp(info[FS_TYPE], "MUL")) sprintf(print_buf, "%20s Multiple Filesystem: %s", " ", info[FS_NAME]); else sprintf(print_buf, "%20s Filesystem Group: %s", " ", info[FS_NAME]); Put_message(print_buf); sprintf(print_buf, "Comments: %s", info[FS_COMMENTS]); Put_message(print_buf); sprintf(print_buf, MOD_FORMAT, info[FS_MODBY], info[FS_MODTIME], info[FS_MODWITH]); Put_message(print_buf); Put_message("Containing the filesystems (in order):"); if ((stat = do_mr_query("get_fsgroup_members", 1, &info[FS_NAME], StoreInfo, &elem))) { if (stat == MR_NO_MATCH) Put_message(" [no members]"); else com_err(program_name, stat, " in PrintFSInfo"); } else { fsgCount = 1; Loop(QueueTop(elem), PrintFSGMembers); FreeQueue(elem); } } else { sprintf(print_buf, "%20s Filesystem: %s", " ", info[FS_NAME]); Put_message(print_buf); sprintf(print_buf, "Type: %-40s Machine: %-15s", info[FS_TYPE], info[FS_MACHINE]); Put_message(print_buf); sprintf(print_buf, "Default Access: %-2s Packname: %-17s Mountpoint %s ", info[FS_ACCESS], info[FS_PACK], info[FS_M_POINT]); Put_message(print_buf); sprintf(print_buf, "Comments: %s", info[FS_COMMENTS]); Put_message(print_buf); sprintf(print_buf, "User Ownership: %-30s Group Ownership: %s", info[FS_OWNER], info[FS_OWNERS]); Put_message(print_buf); sprintf(print_buf, "Update Fileserver: %-27s Locker Type: %s", atoi(info[FS_CREATE]) ? "ON" : "OFF", info[FS_L_TYPE]); Put_message(print_buf); sprintf(print_buf, MOD_FORMAT, info[FS_MODBY], info[FS_MODTIME], info[FS_MODWITH]); Put_message(print_buf); } return info[FS_NAME]; } char *canonicalize_cell(char *c) { struct stat stbuf; char path[512]; int count; sprintf(path, "/afs/%s", c); if (lstat(path, &stbuf) || !stbuf.st_mode & S_IFLNK) return c; count = readlink(path, path, sizeof(path)); if (count < 1) return c; path[count] = 0; free(c); return strdup(path); } int GetAliasValue(int argc, char **argv, void *retval) { *(char **)retval = strdup(argv[2]); return MR_CONT; } /* Function Name: AskFSInfo. * Description: This function askes the user for information about a * machine and saves it into a structure. * Arguments: info - a pointer the the structure to put the * info into. * name - add a newname field? (T/F) * Returns: none. */ static char **AskFSInfo(char **info, Bool name) { char temp_buf[BUFSIZ], *newname, access_type[32]; int fsgroup = 0, newdefaults = 0; Put_message(""); sprintf(temp_buf, "Changing Attributes of filesystem %s.", info[FS_NAME]); Put_message(temp_buf); Put_message(""); if (name) { newname = strdup(info[FS_NAME]); if (GetValueFromUser("The new name for this filesystem", &newname) == SUB_ERROR) return NULL; } strcpy(temp_buf, info[FS_TYPE]); if (GetTypeFromUser("Filesystem's Type", "filesys", &info[FS_TYPE]) == SUB_ERROR) return NULL; if (!strcasecmp(info[FS_TYPE], "FSGROUP") || !strcasecmp(info[FS_TYPE], "MUL")) fsgroup++; if (strcasecmp(info[FS_TYPE], temp_buf)) newdefaults++; if (fsgroup) { free(info[FS_MACHINE]); info[FS_MACHINE] = strdup(NO_MACHINE); } else { if (!strcasecmp(info[FS_TYPE], "AFS")) { if (!name || newdefaults) { free(info[FS_MACHINE]); info[FS_MACHINE] = strdup(DEFAULT_CELL); } if (GetValueFromUser("Filesystem's Cell", &info[FS_MACHINE]) == SUB_ERROR) return NULL; info[FS_MACHINE] = canonicalize_cell(info[FS_MACHINE]); } else { if (GetValueFromUser("Filesystem's Machine", &info[FS_MACHINE]) == SUB_ERROR) return NULL; info[FS_MACHINE] = canonicalize_hostname(info[FS_MACHINE]); } } if (!fsgroup) { if (!strcasecmp(info[FS_TYPE], "AFS")) { char *path, *args[3], *p; int status, depth; if (GetTypeFromUser("Filesystem's lockertype", "lockertype", &info[FS_L_TYPE]) == SUB_ERROR) return NULL; if (!name || newdefaults) { free(info[FS_PACK]); lowercase(info[FS_MACHINE]); sprintf(temp_buf, "%s:%s", info[FS_MACHINE], info[FS_L_TYPE]); args[0] = temp_buf; args[1] = "AFSPATH"; args[2] = "*"; path = "???"; status = do_mr_query("get_alias", 3, args, GetAliasValue, &path); if (status == MR_SUCCESS) { p = strchr(path, ':'); if (p) { *p = '\0'; depth = atoi(++p); } else depth = 0; sprintf(temp_buf, "/afs/%s/%s", info[FS_MACHINE], path); if (depth >= 0) { for (p = info[FS_NAME]; *p && (p - info[FS_NAME]) < depth; p++) { if (islower(*p)) { strcat(temp_buf, "/x"); temp_buf[strlen(temp_buf) - 1] = *p; } else { sprintf(temp_buf, "/afs/%s/%s/other", info[FS_MACHINE], path); break; } } } else if (depth == -1) { if (isdigit(info[FS_NAME][0])) { strcat(temp_buf, "/"); depth = strlen(temp_buf); for (p = info[FS_NAME]; *p && isdigit(*p); p++) { temp_buf[depth++] = *p; temp_buf[depth] = 0; } } else strcat(temp_buf, "/other"); } else { /* no default */ } strcat(temp_buf, "/"); strcat(temp_buf, info[FS_NAME]); free(path); } else { sprintf(temp_buf, "/afs/%s/%s/%s", info[FS_MACHINE], lowercase(info[FS_L_TYPE]), info[FS_NAME]); } info[FS_PACK] = strdup(temp_buf); } } if (GetValueFromUser("Filesystem's Pack Name", &info[FS_PACK]) == SUB_ERROR) return NULL; if (GetValueFromUser("Filesystem's Mount Point", &info[FS_M_POINT]) == SUB_ERROR) return NULL; sprintf(access_type, "fs_access_%s", info[FS_TYPE]); if (GetTypeFromUser("Filesystem's Default Access", access_type, &info[FS_ACCESS]) == SUB_ERROR) return NULL; } if (GetValueFromUser("Comments about this Filesystem", &info[FS_COMMENTS]) == SUB_ERROR) return NULL; if (GetValueFromUser("Filesystem's owner (user)", &info[FS_OWNER]) == SUB_ERROR) return NULL; if (GetValueFromUser("Filesystem's owners (group)", &info[FS_OWNERS]) == SUB_ERROR) return NULL; if (!fsgroup) if (GetYesNoValueFromUser("Propagate changes to fileserver", &info[FS_CREATE]) == SUB_ERROR) return NULL; if (strcasecmp(info[FS_TYPE], "AFS")) { if (GetTypeFromUser("Filesystem's lockertype", "lockertype", &info[FS_L_TYPE]) == SUB_ERROR) return NULL; } FreeAndClear(&info[FS_MODTIME], TRUE); FreeAndClear(&info[FS_MODBY], TRUE); FreeAndClear(&info[FS_MODWITH], TRUE); if (name) /* slide the newname into the #2 slot. */ SlipInNewName(info, newname); return info; } /* --------------- Filesystem Menu ------------- */ /* Function Name: GetFS * Description: Get Filesystem information by name. * Arguments: argc, argv - name of filsys in argv[1]. * Returns: DM_NORMAL. */ int GetFS(int argc, char **argv) { struct mqelem *top; top = GetFSInfo(LABEL, argv[1]); /* get info. */ Loop(top, (void (*)(char **))PrintFSInfo); FreeQueue(top); /* clean the queue. */ return DM_NORMAL; } /* Function Name: GetFSM * Description: Get Filesystem information by machine. * Arguments: argc, argv - name of server in argv[1]. * Returns: DM_NORMAL. */ int GetFSM(int argc, char **argv) { struct mqelem *top; argv[1] = canonicalize_hostname(strdup(argv[1])); top = GetFSInfo(MACHINE, argv[1]); /* get info. */ Loop(top, (void (*)(char **))PrintFSInfo); FreeQueue(top); /* clean the queue. */ return DM_NORMAL; } /* Function Name: RealDeleteFS * Description: Does the real deletion work. * Arguments: info - array of char *'s containing all useful info. * one_item - a Boolean that is true if only one item * in queue that dumped us here. * Returns: none. */ void RealDeleteFS(char **info, Bool one_item) { int stat; char temp_buf[BUFSIZ]; /* * Deletions are performed if the user hits 'y' on a list of multiple * filesystem, or if the user confirms on a unique alias. */ sprintf(temp_buf, "Are you sure that you want to delete filesystem %s", info[FS_NAME]); if (!one_item || Confirm(temp_buf)) { if ((stat = do_mr_query("delete_filesys", 1, &info[FS_NAME], NULL, NULL))) com_err(program_name, stat, " filesystem not deleted."); else Put_message("Filesystem deleted."); } else Put_message("Filesystem not deleted."); } /* Function Name: DeleteFS * Description: Delete a filesystem give its name. * Arguments: argc, argv - argv[1] is the name of the filesystem. * Returns: none. */ int DeleteFS(int argc, char **argv) { struct mqelem *elem = GetFSInfo(LABEL, argv[1]); QueryLoop(elem, PrintFSInfo, RealDeleteFS, "Delete the Filesystem"); FreeQueue(elem); return DM_NORMAL; } /* Function Name: RealChangeFS * Description: performs the actual change to the filesys. * Arguments: info - the information * junk - an unused boolean. * Returns: none. */ static void RealChangeFS(char **info, Bool junk) { int stat; char **args; extern Menu nfsphys_menu; args = AskFSInfo(info, TRUE); if (!args) { Put_message("Aborted."); return; } stat = do_mr_query("update_filesys", CountArgs(args), args, NULL, NULL); switch (stat) { case MR_NFS: Put_message("That NFS filesystem is not exported."); if (YesNoQuestion("Fix this now (Y/N)", TRUE) == TRUE) { Do_menu(&nfsphys_menu, 0, NULL); if (YesNoQuestion("Retry filesystem update now (Y/N)", TRUE) == TRUE) { if ((stat = do_mr_query("update_filesys", CountArgs(args), args, NULL, NULL))) com_err(program_name, stat, " filesystem not updated"); else Put_message("filesystem sucessfully updated."); } } break; case MR_SUCCESS: break; default: com_err(program_name, stat, " in UpdateFS"); } } /* Function Name: ChangeFS * Description: change the information in a filesys record. * Arguments: arc, argv - value of filsys in argv[1]. * Returns: DM_NORMAL. */ int ChangeFS(int argc, char **argv) { struct mqelem *elem = GetFSInfo(LABEL, argv[1]); QueryLoop(elem, NullPrint, RealChangeFS, "Update the Filesystem"); FreeQueue(elem); return DM_NORMAL; } /* Function Name: AddFS * Description: change the information in a filesys record. * Arguments: arc, argv - name of filsys in argv[1]. * Returns: DM_NORMAL. */ int AddFS(int argc, char **argv) { char *info[MAX_ARGS_SIZE], **args, buf[BUFSIZ]; int stat; extern Menu nfsphys_menu; if (!ValidName(argv[1])) return DM_NORMAL; if (!(stat = do_mr_query("get_filesys_by_label", 1, argv + 1, NULL, NULL))) { Put_message ("A Filesystem by that name already exists."); return DM_NORMAL; } else if (stat != MR_NO_MATCH) { com_err(program_name, stat, " in AddFS"); return DM_NORMAL; } if (!(args = AskFSInfo(SetDefaults(info, argv[1]), FALSE))) { Put_message("Aborted."); return DM_NORMAL; } stat = do_mr_query("add_filesys", CountArgs(args), args, NULL, NULL); switch (stat) { case MR_NFS: Put_message("That NFS filesystem is not exported."); if (YesNoQuestion("Fix this now (Y/N)", TRUE) == TRUE) { Do_menu(&nfsphys_menu, 0, NULL); if (YesNoQuestion("Retry filesystem creation now (Y/N)", TRUE) == TRUE) { if ((stat = do_mr_query("add_filesys", CountArgs(args), args, NULL, NULL))) com_err(program_name, stat, " in AddFS"); else Put_message("Created."); } } break; case MR_SUCCESS: break; default: com_err(program_name, stat, " in AddFS"); } if (stat == MR_SUCCESS && !strcasecmp(info[FS_L_TYPE], "HOMEDIR")) { static char *val[] = {"def_quota", NULL}; static char *def_quota = NULL; char *argv[Q_QUOTA + 1]; struct mqelem *top = NULL; if (!def_quota) { stat = do_mr_query("get_value", CountArgs(val), val, StoreInfo, &top); if (stat != MR_SUCCESS) com_err(program_name, stat, " getting default quota"); else { top = QueueTop(top); def_quota = strdup(((char **)top->q_data)[0]); FreeQueue(top); } } if (def_quota) { sprintf(buf, "Give user %s a quota of %s on filesys %s (Y/N)", info[FS_NAME], def_quota, info[FS_NAME]); if (YesNoQuestion(buf, 1) == TRUE) { argv[Q_NAME] = argv[Q_FILESYS] = info[FS_NAME]; if (!strcmp(info[FS_TYPE], "NFS")) argv[Q_TYPE] = "USER"; else argv[Q_TYPE] = "ANY"; argv[Q_QUOTA] = def_quota; if ((stat = do_mr_query("add_quota", Q_QUOTA + 1, argv, NULL, NULL))) com_err(program_name, stat, " while adding quota"); } } } else if (stat == MR_SUCCESS) { if (YesNoQuestion("Assign a quota on this filesystem (Y/N)", 1) == TRUE) { parsed_argc = 1; parsed_argv[0] = info[FS_NAME]; AddQuota(parsed_argc, parsed_argv); } } FreeInfo(info); return DM_NORMAL; } /* Function Name: SortAfter * Description: choose a sortkey to cause an item to be added after * the count element in the queue * Arguments: queue of filesys names & sortkeys, queue count pointer * Returns: sort key to use. */ char *SortAfter(struct mqelem *elem, int count) { char *prev, *next, prevnext, *key, keybuf[9]; /* first find the two keys we need to insert between */ prev = "A"; for (; count > 0; count--) { prev = ((char **)elem->q_data)[1]; if (elem->q_forw) elem = elem->q_forw; else break; } if (count > 0) next = "Z"; else next = ((char **)elem->q_data)[1]; /* now copy the matching characters */ for (key = keybuf; *prev && *prev == *next; next++) *key++ = *prev++; /* and set the last character */ if (*prev == 0) *prev = prevnext = 'A'; else prevnext = prev[1]; if (prevnext == 0) prevnext = 'A'; if (*next == 0) *next = 'Z'; if (*next - *prev > 1) *key++ = (*next + *prev) / 2; else { *key++ = *prev; *key++ = (prevnext + 'Z') / 2; } *key = 0; return strdup(keybuf); } /* Function Name: AddFSToGroup * Description: add a filesystem to an FS group * Arguments: arc, argv - name of group in argv[1], filesys in argv[2]. * Returns: DM_NORMAL. */ int AddFSToGroup(int argc, char **argv) { int stat, count; struct mqelem *elem = NULL; char buf[BUFSIZ], *args[5], *bufp; if ((stat = do_mr_query("get_fsgroup_members", 1, argv + 1, StoreInfo, &elem))) { if (stat != MR_NO_MATCH) com_err(program_name, stat, " in AddFSToGroup"); } if (elem == NULL) { args[0] = argv[1]; args[1] = argv[2]; args[2] = "M"; stat = do_mr_query("add_filesys_to_fsgroup", 3, args, NULL, NULL); if (stat) com_err(program_name, stat, " in AddFSToGroup"); return DM_NORMAL; } elem = QueueTop(elem); fsgCount = 1; Loop(elem, PrintFSGMembers); sprintf(buf, "%d", QueueCount(elem)); bufp = strdup(buf); if (GetValueFromUser("Enter number of filesystem it should follow " "(0 to make it first):", &bufp) == SUB_ERROR) return DM_NORMAL; count = atoi(bufp); free(bufp); args[2] = SortAfter(elem, count); FreeQueue(QueueTop(elem)); args[0] = argv[1]; args[1] = argv[2]; stat = do_mr_query("add_filesys_to_fsgroup", 3, args, NULL, NULL); if (stat == MR_EXISTS) { Put_message("That filesystem is already a member of the group."); Put_message("Use the order command if you want to change the " "sorting order."); } else if (stat) com_err(program_name, stat, " in AddFSToGroup"); return DM_NORMAL; } /* Function Name: RemoveFSFromGroup * Description: delete a filesystem from an FS group * Arguments: arc, argv - name of group in argv[1]. * Returns: DM_NORMAL. */ int RemoveFSFromGroup(int argc, char **argv) { int stat; char buf[BUFSIZ]; sprintf(buf, "Delete filesystem %s from FS group %s", argv[2], argv[1]); if (!Confirm(buf)) return DM_NORMAL; if ((stat = do_mr_query("remove_filesys_from_fsgroup", 2, argv + 1, NULL, NULL))) com_err(program_name, stat, ", not removed."); return DM_NORMAL; } /* Function Name: ChangeFSGroupOrder * Description: change the sortkey on a filesys in an FSgroup * Arguments: arc, argv - name of group in argv[1]. * Returns: DM_NORMAL. */ int ChangeFSGroupOrder(int argc, char **argv) { int stat, src, dst, i; struct mqelem *elem = NULL, *top, *tmpelem; char buf[BUFSIZ], *bufp, *args[3]; if ((stat = do_mr_query("get_fsgroup_members", 1, argv + 1, StoreInfo, &elem))) { if (stat == MR_NO_MATCH) { sprintf(buf, "Ether %s is not a filesystem group or it has no members", argv[1]); Put_message(buf); } else com_err(program_name, stat, " in ChangeFSGroupOrder"); return DM_NORMAL; } top = QueueTop(elem); fsgCount = 1; Loop(top, PrintFSGMembers); while (1) { bufp = strdup("1"); if (GetValueFromUser("Enter number of the filesystem to move:", &bufp) == SUB_ERROR) return DM_NORMAL; src = atoi(bufp); free(bufp); if (src < 0) { Put_message("You must enter a positive number (or 0 to abort)."); continue; } else if (src == 0) { Put_message("Aborted."); return DM_NORMAL; } for (elem = top, i = src; i-- > 1 && elem->q_forw; elem = elem->q_forw) ; if (i > 0) { Put_message("You entered a number that is too high"); continue; } break; } while (1) { bufp = strdup("0"); if (GetValueFromUser("Enter number of filesystem it should follow " "(0 to make it first):", &bufp) == SUB_ERROR) return DM_NORMAL; dst = atoi(bufp); free(bufp); if (src == dst || src == dst + 1) { Put_message("That has no effect on the sorting order!"); return DM_NORMAL; } if (dst < 0) { Put_message("You must enter a non-negative number."); continue; } for (tmpelem = top, i = dst; i-- > 1 && tmpelem->q_forw; tmpelem = tmpelem->q_forw) ; if (i > 0) { Put_message("You entered a number that is too high"); continue; } break; } args[2] = SortAfter(top, dst); args[0] = argv[1]; args[1] = ((char **)elem->q_data)[0]; if ((stat = do_mr_query("remove_filesys_from_fsgroup", 2, args, NULL, NULL))) { com_err(program_name, stat, " in ChangeFSGroupOrder"); return DM_NORMAL; } if ((stat = do_mr_query("add_filesys_to_fsgroup", 3, args, NULL, NULL))) com_err(program_name, stat, " in ChangeFSGroupOrder"); return DM_NORMAL; } /* -------------- Top Level Menu ---------------- */ /* Function Name: GetFSAlias * Description: Gets the value for a Filesystem Alias. * Arguments: argc, argv - name of alias in argv[1]. * Returns: DM_NORMAL. * NOTES: There should only be one filesystem per alias, thus * this will work correctly. */ int GetFSAlias(int argc, char **argv) { struct mqelem *top; top = GetFSInfo(ALIAS, argv[1]); Put_message(" "); /* blank line. */ Loop(top, (void *) PrintFSAlias); FreeQueue(top); return DM_NORMAL; } /* Function Name: CreateFSAlias * Description: Create an alias name for a filesystem * Arguments: argc, argv - name of alias in argv[1]. * Returns: DM_NORMAL. * NOTES: This requires (name, type, transl) I get {name, translation} * from the user. I provide type, which is well-known. */ int CreateFSAlias(int argc, char **argv) { int stat; struct mqelem *elem, *top; char *args[MAX_ARGS_SIZE], buf[BUFSIZ], **info; elem = NULL; if (!ValidName(argv[1])) return DM_NORMAL; args[ALIAS_NAME] = strdup(argv[1]); args[ALIAS_TYPE] = strdup(FS_ALIAS_TYPE); args[ALIAS_TRANS] = strdup("*"); /* * Check to see if this alias already exists in the database, if so then * print out values, free memory used and then exit. */ if (!(stat = do_mr_query("get_alias", 3, args, StoreInfo, &elem))) { top = elem = QueueTop(elem); while (elem) { info = elem->q_data; sprintf(buf, "The alias: %s currently describes the filesystem %s", info[ALIAS_NAME], info[ALIAS_TRANS]); Put_message(buf); elem = elem->q_forw; } FreeQueue(top); return DM_NORMAL; } else if (stat != MR_NO_MATCH) { com_err(program_name, stat, " in CreateFSAlias."); return DM_NORMAL; } args[ALIAS_TRANS] = strdup(""); args[ALIAS_END] = NULL; if (GetValueFromUser("Which filesystem will this alias point to?", &args[ALIAS_TRANS]) == SUB_ERROR) return DM_NORMAL; if ((stat = do_mr_query("add_alias", 3, args, NULL, NULL))) com_err(program_name, stat, " in CreateFSAlias."); FreeInfo(args); return DM_NORMAL; } /* Function Name: RealDeleteFSAlias * Description: Does the real deletion work. * Arguments: info - array of char *'s containing all useful info. * one_item - a Boolean that is true if only one item * in queue that dumped us here. * Returns: none. */ void RealDeleteFSAlias(char **info, Bool one_item) { int stat; char temp_buf[BUFSIZ]; /* * Deletions are performed if the user hits 'y' on a list of multiple * filesystem, or if the user confirms on a unique alias. */ sprintf(temp_buf, "Are you sure that you want to delete the filesystem alias %s", info[ALIAS_NAME]); if (!one_item || Confirm(temp_buf)) { if ((stat = do_mr_query("delete_alias", CountArgs(info), info, NULL, NULL))) com_err(program_name, stat, " filesystem alias not deleted."); else Put_message("Filesystem alias deleted."); } else Put_message("Filesystem alias not deleted."); } /* Function Name: DeleteFSAlias * Description: Delete an alias name for a filesystem * Arguments: argc, argv - name of alias in argv[1]. * Returns: DM_NORMAL. * NOTES: This requires (name, type, transl) I get {name, translation} * from the user. I provide type, which is well-known. */ int DeleteFSAlias(int argc, char **argv) { struct mqelem *elem = GetFSInfo(ALIAS, argv[1]); QueryLoop(elem, PrintFSAlias, RealDeleteFSAlias, "Delete the Filesystem Alias"); FreeQueue(elem); return DM_NORMAL; } /* Function Name: AttachHelp * Description: Print help info on attachmaint. * Arguments: none * Returns: DM_NORMAL. */ int AttachHelp(void) { static char *message[] = { "These are the options:", "", "get - get information about a filesystem.", "add - add a new filesystem to the data base.", "update - update the information in the database on a filesystem.", "delete - delete a filesystem from the database.", "check - check information about association of a name and a filesys.", "alias - associate a name with a filesystem.", "unalias - disassociate a name with a filesystem.", "verbose - toggle the request for delete confirmation.", NULL, }; return PrintHelp(message); } /* Function Name: FSGroupHelp * Description: Print help info on fsgroups. * Arguments: none * Returns: DM_NORMAL. */ int FSGroupHelp(int argc, char **argv) { static char *message[] = { "A filesystem group is a named sorted list of filesystems.", "", "To create, modify, or delete a group itself, use the menu above", " this one, and manipulate a filesystem of type FSGROUP.", "Options here are:", " get - get info about a group and show its members", " add - add a new member to a group.", " remove - remove a member from a group.", " order - change the sorting order of a group.", NULL }; return PrintHelp(message); }