1 #if (!defined(lint) && !defined(SABER))
2 static char rcsid_module_c[] = "$Header$";
5 /* This is the file utils.c for the MOIRA Client, which allows a nieve
6 * user to quickly and easily maintain most parts of the MOIRA database.
7 * It Contains: Many useful utility functions.
10 * By: Chris D. Peterson
16 * Copyright 1988 by the Massachusetts Institute of Technology.
18 * For further information on copyright and distribution
19 * see the file mit-copyright.h
25 #include <moira_site.h>
29 #include "mit-copyright.h"
33 #include <netdb.h> /* for gethostbyname. */
34 #include <sys/types.h>
35 #include <netinet/in.h>
38 /* Function Name: AddQueue
39 * Description: Adds an element to a queue
40 * Arguments: elem, pred - element and its predecessor.
46 struct qelem * elem, *pred;
54 elem->q_forw = pred->q_forw;
58 /* Function Name: RemoveQueue
59 * Description: removes an element from a queue.
68 if (elem->q_forw != NULL)
69 (elem->q_forw)->q_back = elem->q_back;
70 if (elem->q_back != NULL)
71 (elem->q_back)->q_forw = elem->q_forw;
75 /* CopyInfo: allocates memory for a copy of a NULL terminated array of
76 * strings <and returns a pointer to the copy.
85 ret = (char **) malloc(sizeof(char *) * (CountArgs(info) + 1));
88 for (i = 0; info[i]; i++)
89 ret[i] = Strsave(info[i]);
95 /* Function Name: FreeInfo
96 * Description: Frees all elements of a NULL terminated arrary of char*'s
97 * Arguments: info - array who's elements we are to free.
105 while (*info != NULL)
106 FreeAndClear(info++, TRUE);
109 /* Function Name: FreeAndClear - I couldn't resist the name.
110 * Description: Clears pointer and optionially frees it.
111 * Arguments: pointer - pointer to work with.
112 * free_it - if TRUE then free pointer.
117 FreeAndClear(pointer, free_it)
121 if (*pointer == NULL)
128 /* Function Name: QueueTop
129 * Description: returns a qelem pointer that points to the top of
131 * Arguments: elem - any element of a queue.
132 * Returns: top element of a queue.
139 if (elem == NULL) /* NULL returns NULL. */
141 while (elem->q_back != NULL)
146 /* Function Name: FreeQueueElem
147 * Description: Frees one element of the queue.
148 * Arguments: elem - the elem to free.
156 char ** info = (char **) elem->q_data;
158 if (info != (char **) NULL) {
159 FreeInfo( info ); /* free info fields */
160 free(elem->q_data); /* free info array itself. */
162 RemoveQueue(elem); /* remove this element from the queue */
163 free(elem); /* free its space. */
166 /* Function Name: FreeQueue
167 * Description: Cleans up the queue
168 * Arguments: elem - any element of the queue.
176 struct qelem *temp, *local = QueueTop(elem);
178 while(local != NULL) {
179 temp = local->q_forw;
180 FreeQueueElem(local);
185 /* Function Name: QueueCount
186 * Description: Counts the number of elements in a queue
187 * Arguments: elem - any element in the queue.
196 elem = QueueTop(elem);
197 while (elem != NULL) {
204 /* Function Name: StoreInfo
205 * Description: Stores information from an moira query into a queue.
206 * Arguments: argc, argv, - information returned from the query returned
208 * data - the previous element on the queue, this data will be
209 * stored in a qelem struct immediatly after this elem.
210 * If NULL then a new queue will be created. This value
211 * is updated to the current element at the end off the
213 * Returns: MR_CONT, or MR_ABORT if it has problems.
217 StoreInfo(argc, argv, data)
222 char ** info = (char **) malloc( MAX_ARGS_SIZE * sizeof(char *));
223 struct qelem ** old_elem = (struct qelem **) data;
224 struct qelem * new_elem = (struct qelem *) malloc (sizeof (struct qelem));
227 if ( (new_elem == (struct qelem *) NULL) || (info == (char **) NULL) ) {
228 Put_message("Could Not allocate more memory.");
229 FreeQueue(*old_elem);
230 *old_elem = (struct qelem *) NULL;
234 for (count = 0; count < argc; count++)
235 info[count] = Strsave(argv[count]);
236 info[count] = NULL; /* NULL terminate this sucker. */
238 new_elem->q_data = (char *) info;
239 AddQueue(new_elem, *old_elem);
241 *old_elem = new_elem;
245 /* Function Name: CountArgs
246 * Description: Retrieve the number of args in a null terminated
248 * Arguments: info - the argument list.
249 * Returns: number if args in the list.
258 while (*info != NULL) {
266 /* Function Name: Scream
267 * Description: Bitch Loudly and exit, it is intended as a callback
268 * function for queries that should never return a value.
270 * Returns: doesn't exit.
276 com_err(program_name, 0,
277 "\nA Moira update returned a value -- programmer botch\n");
284 /* Function Name: PromptWithDefault
285 * Description: allows a user to be prompted for input, and given a
287 * Arguments: prompt - the prompt string.
288 * buf, buflen - buffer to be returned and its MAX size?
289 * default value for the answer.
290 * Returns: zero on failure
294 PromptWithDefault(prompt, buf, buflen, def)
302 if (parsed_argc > 0) {
304 strncpy(buf, parsed_argv[0], buflen);
305 sprintf(tmp, "%s: %s", prompt, buf);
311 (void) sprintf(tmp, "%s [%s]: ", prompt, def ? def : "");
312 ans = Prompt_input(tmp, buf, buflen);
314 (void) strcpy(buf, def);
315 else if (!strcmp(buf, "\"\""))
320 /* Function Name: YesNoQuestion
321 * Description: This prompts the user for the answer to a yes-no or
322 * true-false question.
323 * Arguments: prompt - the prompt for the user.
324 * bool_def - the default value either TRUE or FALSE.
325 * Returns: TRUE or FALSE or -1 on error
329 YesNoQuestion(prompt, bool_def)
336 if (!PromptWithDefault(prompt, ans, 2, bool_def ? "y" : "n"))
346 Put_message("Please answer 'y' or 'n'.");
351 /* Function Name: YesNoQuitQuestion
352 * Description: This prompts the user for the answer to a yes-no or
353 * true-false question, with a quit option.
354 * Arguments: prompt - the prompt for the user.
355 * bool_def - the default value either TRUE or FALSE.
356 * Returns: TRUE or FALSE or -1 on error or QUIT
357 * NOTE: It is not possible to have quit the default, but then I don't
358 * seem to need this functionality.
362 YesNoQuitQuestion(prompt, bool_def)
369 if (!PromptWithDefault(prompt, ans, 2, bool_def ? "y" : "n"))
382 Put_message("Please answer 'y', 'n' or 'q'.");
388 /* Function Name: Confirm
389 * Description: This function asks the user to confirm the action
390 * he is about to take, used for things like deleting.
391 * Arguments: prompt - the prompt string.
392 * Returns: TRUE/FALSE - wether or not the confirmation occured.
399 return( !verbose || (YesNoQuestion(prompt,FALSE) == TRUE) );
402 /* Function Name: ValidName
403 * Description: This function checks to see if we have a valid list name.
404 * Arguments: s - the list name.
405 * Returns: TRUE if Valid.
413 Put_message("Please use a non-empty name.");
414 else if (strchr(s, ' '))
415 Put_message("You cannot use space (' ') in this name.");
416 else if (strchr(s, '*') || strchr(s, '?') || strchr(s, '['))
417 Put_message("Wildcards not accepted here.");
423 /* Function Name: ToggleVerboseMode
424 * Description: This function toggles the verbose mode.
426 * Returns: DM_NORMAL.
436 Put_message("Delete functions will first confirm\n");
438 Put_message("Delete functions will be silent\n");
443 /* Function Name: NullFunc
444 * Description: dummy callback routine
455 /* Function Name: SlipInNewName
456 * Description: Slips the new name into the number 2 slot of a list, and
457 * returns a pointer to the new list.
458 * Arguments: info - list that needs this name slipped into it.
459 * name - the name to slip into the list.
460 * Returns: a pointer to the new list.
461 * NOTE: This screws up the numbers of the elements of the array in a
466 SlipInNewName(info, name)
472 /* This also pushes the NULL down. */
473 for (i = CountArgs(info); i > 0; i--) {
476 info[1] = name; /* now slip in the name. */
479 /* Function Name: GetValueFromUser
480 * Description: This function gets a value from a user for the field
482 * Arguments: prompt - prompt for user.
483 * pointer - pointer to default value, will be returned
485 * Returns: SUB_ERROR if break hit (^C).
489 GetValueFromUser(prompt, pointer)
490 char * prompt, ** pointer;
494 if (PromptWithDefault(prompt, buf, BUFSIZ, *pointer) == 0)
498 * If these are the same then there is no need to allocate a new string.
500 * a difference that makes no difference, IS no difference.
503 if (*pointer != NULL) {
504 if (strcmp(buf, *pointer) != 0) {
506 *pointer = Strsave(buf);
512 /* Function Name: GetYesNoValueFromUser
513 * Description: This function gets a value from a user for the field
515 * Arguments: prompt - prompt for user.
516 * pointer - pointer to default value, will be returned
518 * Returns: SUB_ERROR if break hit (^C).
522 GetYesNoValueFromUser(prompt, pointer)
523 char * prompt, ** pointer;
525 char user_prompt[BUFSIZ];
528 if ( strcmp (*pointer, DEFAULT_YES) == 0 )
533 sprintf(user_prompt, "%s (y/n)", prompt);
535 switch (YesNoQuestion(user_prompt, default_val)) {
537 if (*pointer != NULL)
539 *pointer = Strsave(DEFAULT_YES);
542 if (*pointer != NULL)
544 *pointer = Strsave(DEFAULT_NO);
553 /* Function Name: GetFSVal
554 * Description: asks about a specific filesystem value.
555 * Arguments: name - string for this type of filesystem.
556 * mask - mask for this type of filesystem.
557 * current - current filesystem state. (for defaults).
558 * new - new filesystem state.
559 * Returns: TRUE if successful.
563 GetFSVal(name, mask, current, new)
565 int mask, current, *new;
567 char temp_buf[BUFSIZ];
568 sprintf(temp_buf, "Is this a %s filsystem", name);
569 switch (YesNoQuestion(temp_buf, ( (mask & current) == mask) )) {
574 break; /* zero by default. */
581 /* Function Name: GetFSTypes
582 * Description: Allows user to specify filsystem types.
583 * Arguments: current - current value of filsystem, freed here.
584 * Returns: SUB_ERROR on ^C.
588 GetFSTypes(current, options)
592 int c_value, new_val = 0; /* current value of filesys type (int). */
593 char ret_value[BUFSIZ];
595 if (*current == NULL)
598 c_value = atoi(*current);
600 if (GetFSVal("student", MR_FS_STUDENT, c_value, &new_val) == FALSE)
602 if (GetFSVal("faculty", MR_FS_FACULTY, c_value, &new_val) == FALSE)
604 if (GetFSVal("staff", MR_FS_STAFF, c_value, &new_val) == FALSE)
606 if (GetFSVal("miscellaneous", MR_FS_MISC, c_value, &new_val) == FALSE)
609 if (GetFSVal("Group Quotas", MR_FS_GROUPQUOTA, c_value, &new_val) ==
614 FreeAndClear(current, TRUE);
615 sprintf(ret_value, "%d", new_val);
616 *current = Strsave(ret_value);
620 /* Function Name: Strsave
621 * Description: save a string.
622 * Arguments: string - the string to save.
623 * Returns: The malloced string, now safely saved, or NULL.
630 register char *newstr = malloc((unsigned) strlen(str) + 1);
632 if (newstr == (char *) NULL)
633 return ((char *) NULL);
635 return (strcpy(newstr, str));
639 /* atot: convert ASCII integer unix time into human readable date string */
654 /* Function Name: Print
655 * Description: prints out all the arguments on a single line.
656 * Arguments: argc, argv - the standard MR arguments.
657 * callback - the callback function - NOT USED.
663 Print(argc, argv, callback)
665 char **argv, *callback;
671 (void) strcpy(buf,argv[0]); /* no newline 'cause Put_message adds one */
672 for (i = 1; i < argc; i++)
673 (void) sprintf(buf,"%s %s",buf,argv[i]);
674 (void) Put_message(buf);
679 /* Function Name: PrintByType
680 * Description: This function prints all members of the type specified
681 * by the callback arg, unless the callback is NULL, in which
682 * case it prints all members.
683 * Arguments: argc, argc - normal arguments for mr_callback function.
684 * callback - either a type of member or NULL.
685 * Returns: MR_CONT or MR_QUIT.
690 PrintByType(argc, argv, callback)
692 char **argv, *callback;
694 if (callback == NULL)
695 return( Print(argc, argv, callback) );
696 if (strcmp(argv[0], callback) == 0)
697 return( Print(argc, argv, callback) );
701 /* Function Name: PrintHelp
702 * Description: Prints Help Information in a NULL terminated
704 * Arguments: message.
705 * Returns: DM_NORMAL.
714 for (i = 0; i < CountArgs(message); i++)
715 Put_message(message[i]);
720 /* Function Name: Loop
721 * Description: This function goes through the entire queue, and
722 * and executes the given function on each element.
723 * Arguments: elem - top element of the queue.
724 * func - the function to execute.
733 while (elem != NULL) {
734 char ** info = (char **) elem->q_data;
741 /* Function Name: QueryLoop
742 * Description: This functions loops through a queue containing
743 * information about some item that we want to perform
744 * an operation on, and then calls the correct routine
745 * perform that operation.
746 * Arguments: top - top of the queue of information.
747 * print_func - print function.
748 * op_function - operation to be performed.
749 * query_string - string the prompts the user whether or not
750 * to perform this operation.
753 * print_opt - should expect one arguent, the info array
755 * is expected to return the name of the item.
756 * op_func - should expect two arguments.
757 * 1) the info array of char *'s.
758 * 2) a boolean the is true if there only
759 * one item in this queue, used for delete
761 * query_string - this should be of such a form that when the
762 * name of the object and '(y/n/q) ?' are appended
763 * then it should still make sense, an example is
768 QueryLoop(elem, print_func, op_func, query_string)
771 FCharStar print_func;
775 char temp_buf[BUFSIZ], *name;
777 elem = QueueTop(elem);
778 one_item = (QueueCount(elem) == 1);
779 while (elem != NULL) {
780 char **info = (char **) elem->q_data;
783 (*op_func) (info, one_item);
785 name = (*print_func) (info); /* call print function. */
786 sprintf(temp_buf,"%s %s (y/n/q)", query_string, name);
787 switch(YesNoQuitQuestion(temp_buf, FALSE)) {
789 (*op_func) (info, one_item);
794 Put_message("Aborting...");
802 /* Function Name: NullPrint
803 * Description: print function that returns nothing.
804 * Arguments: info - a pointer to the info array - Not used.
816 /* Function Name: GetTypeValues
817 * Description: gets legal values for a typed object, keeping a cache
818 * Arguments: type name
819 * Returns: argv of values
827 char *argv[3], *p, **pp, *strsave();
828 struct qelem *elem, *oelem;
829 static struct qelem *cache = NULL;
830 struct cache_elem { char *cache_name; struct qelem *cache_data; } *ce;
832 for (elem = cache; elem; elem = elem->q_forw) {
833 ce = (struct cache_elem *)elem->q_data;
834 if (!strcmp(ce->cache_name, tname))
835 return(ce->cache_data);
842 if (stat = do_mr_query("get_alias", 3, argv, StoreInfo, (char *)&elem)) {
843 com_err(program_name, stat, " in GetTypeValues");
847 for (elem = QueueTop(elem); elem; elem = elem->q_forw) {
848 pp = (char **) elem->q_data;
853 elem = (struct qelem *) malloc(sizeof(struct qelem));
854 ce = (struct cache_elem *) malloc(sizeof(struct cache_elem));
855 ce->cache_name = strsave(tname);
856 ce->cache_data = QueueTop(oelem);
857 elem->q_data = (char *)ce;
858 AddQueue(elem, cache);
859 cache = QueueTop(elem);
860 return(ce->cache_data);
864 /* Function Name: GetTypeFromUser
865 * Description: gets a typed value from the user
866 * Arguments: prompt string, type name, buffer pointer
867 * Returns: SUB_ERROR if ^C, SUB_NORMAL otherwise
870 int GetTypeFromUser(prompt, tname, pointer)
875 char def[BUFSIZ], buffer[BUFSIZ], *p, *argv[3];
879 strcpy(def, *pointer);
880 strcpy(buffer, prompt);
881 strcat(buffer, " (");
882 for (elem = GetTypeValues(tname); elem; elem = elem->q_forw) {
883 strcat(buffer, elem->q_data);
885 strcat(buffer, ", ");
888 if (strlen(buffer) > 64)
889 sprintf(buffer, "%s (? for help)", prompt);
890 if (GetValueFromUser(buffer, pointer) == SUB_ERROR)
892 if (**pointer == '?') {
893 sprintf(buffer, "Type %s is one of:", tname);
895 for (elem = GetTypeValues(tname); elem; elem = elem->q_forw) {
896 Put_message(elem->q_data);
898 *pointer = strsave(def);
899 return(GetTypeFromUser(prompt, tname, pointer));
901 for (elem = GetTypeValues(tname); elem; elem = elem->q_forw) {
902 if (!strcasecmp(elem->q_data, *pointer)) {
903 strcpy(*pointer, elem->q_data);
907 sprintf(buffer, "\"%s\" is not a legal value for %s. Use one of:",
910 for (elem = GetTypeValues(tname); elem; elem = elem->q_forw) {
911 Put_message(elem->q_data);
913 sprintf(buffer, "Are you sure you want \"%s\" to be a legal %s",
915 if (YesNoQuestion("Do you want this to be a new legal value", 0) == TRUE &&
916 YesNoQuestion(buffer, 0) == TRUE) {
920 /* don't uppercase access flags. Do uppercase everything else */
921 if (strncmp(tname, "fs_access", 9))
922 for (p = argv[2]; *p; p++)
925 if (stat = do_mr_query("add_alias", 3, argv, Scream, NULL)) {
926 com_err(program_name, stat, " in add_alias");
928 elem = (struct qelem *) malloc(sizeof(struct qelem));
929 elem->q_data = strsave(*pointer);
930 AddQueue(elem, GetTypeValues(tname));
931 Put_message("Done.");
934 *pointer = strsave(def);
935 return(GetTypeFromUser(prompt, tname, pointer));
939 /* Function Name: GetAddressFromUser
940 * Description: gets an IP address from the user
941 * Arguments: prompt string, buffer pointer
942 * buffer contains default value as long int
943 * Returns: SUB_ERROR if ^C, SUB_NORMAL otherwise
946 int GetAddressFromUser(prompt, pointer)
950 char *value, buf[256];
954 addr.s_addr = htonl(atoi(*pointer));
955 value = strsave(inet_ntoa(addr));
956 ret = GetValueFromUser(prompt, &value);
957 if (ret == SUB_ERROR) return(SUB_ERROR);
958 addr.s_addr = inet_addr(value);
960 sprintf(buf, "%d", ntohl(addr.s_addr));
961 *pointer = strsave(buf);
966 do_mr_query(name, argc, argv, proc, hint)
974 extern char *whoami, *moira_server;
977 status = mr_query(name, argc, argv, proc, hint);
978 if (status != MR_ABORTED && status != MR_NOT_CONNECTED)
980 status = mr_connect(moira_server);
982 com_err(whoami, status, " while re-connecting to server %s",
986 status = mr_auth(whoami);
988 com_err(whoami, status, " while re-authenticating to server %s",
993 status = mr_query(name, argc, argv, proc, hint);