#include #include #include #include #include #include #include #include "global.h" #include "manhat-lib/shared_util.h" #include "manhat-lib/shared_person_list.h" #include "manhat-lib/shared_strtrm.h" #include "manhat-lib/shared_file_util.h" #define SUBDIR_NAME "orig" typedef enum {STANDALONE, CENTRAL, TEMPLATE} COURSE_TYPE; #define MAX_COURSE_DIRNAME 100 typedef struct xml_course_info { char course_code[MAX_COURSE_NO +1]; char title[MAX_COURSE_TITLE +1]; char semester[MAX_SEMESTER +1]; char subdir[MAX_COURSE_SUBDIR + 1]; char dir_id[MAX_COURSE_DIRNAME +1]; COURSE_TYPE course_type; P_NODE *user_head; P_NODE *user_current; struct xml_course_info *next; }XML_COURSE_INFO; typedef struct xml_course_info_list { XML_COURSE_INFO *head; XML_COURSE_INFO *current; }XML_COURSE_INFO_LIST; typedef struct user_course_list { char course_path[MAX_PATH +1]; struct user_course_list *next; }USER_COURSE_LIST; typedef struct username_courses { char username[MAX_USERNAME +1]; USER_COURSE_LIST *course_head; USER_COURSE_LIST *course_current; struct username_courses *next; }USERNAME_COURSES; int normal_count = 0; int standalone_count = 0; int template_count = 0; int user_count = 0; USERNAME_COURSES * find_username(USERNAME_COURSES *head, const char *username) { USERNAME_COURSES *ptr; for(ptr = head; ptr; ptr = ptr->next) { if(strcmp(ptr->username, username) ==0) return ptr; } return 0; } USERNAME_COURSES * find_last(USERNAME_COURSES *head) { USERNAME_COURSES *ptr; USERNAME_COURSES *last =0; for(ptr = head; ptr; ptr = ptr->next) { last = ptr; } return last; } void free_user_course_list(USER_COURSE_LIST *head) { USER_COURSE_LIST *ptr; while(head) { ptr = head->next; free(head); head = ptr; } } void free_username_courses(USERNAME_COURSES *head) { USERNAME_COURSES *ptr; while(head) { ptr = head->next; free_user_course_list(head->course_head); free(head); head = ptr; } } /** Updates the USERNAME_COURSES list, which holds for each user a list *** of courses they belong to. Each call for this function acts only on *** one user - username ***/ USERNAME_COURSES * insert_username_data(USERNAME_COURSES *head, const char *username, const char *course_path) { USERNAME_COURSES *ptr; USERNAME_COURSES *last; /* does username already have an entry on the list? */ ptr = find_username(head, username); /* yes - add this course to the end of the list ***/ if(ptr) { ptr->course_current->next = (USER_COURSE_LIST*)malloc(sizeof(USER_COURSE_LIST)); if(!ptr->course_current->next) { perror("malloc failed - Not enough memory?"); exit(1); } ptr->course_current = ptr->course_current->next; strncpy(ptr->course_current->course_path, course_path, MAX_PATH +1); ptr->course_current->next = 0; } else /* no add this user, then add the course to the end of the list */ { user_count++; ptr = (USERNAME_COURSES*)malloc(sizeof(USERNAME_COURSES)); if(!ptr) { perror("malloc failed - Not enough memory?"); exit(1); } strncpy(ptr->username, username, MAX_USERNAME +1); ptr->course_head = (USER_COURSE_LIST*)malloc(sizeof(USER_COURSE_LIST)); if(!ptr->course_head) { perror("malloc() failed - Not enough memory?"); exit(1); } ptr->course_current = ptr->course_head; strncpy(ptr->course_current->course_path, course_path, MAX_PATH +1); ptr->course_current->next = 0; ptr->next =0; if(!head) head = ptr; else { last = find_last(head); last->next = ptr; } } return head; } /** Shows simplified instructions, and forces user to type *** a phrase to continue ***/ void show_instructions() { char line[200 +1]; printf("\n\n\n\n\n"); puts("This upgrade program will move all of your existing course directories"); printf("into a new SUBDIRECTORY called '%s' (for 'original') The new release\n", SUBDIR_NAME); puts("of Manhattan calls this a 'course group'. See the Manhattan 2.2 "); puts("Administrator's Reference for details."); puts("\nBefore you continue, you must get everyone off of Manhattan and "); puts("BACK UP your current installation.\n"); printf("Type I BACKED UP to do the upgrade: "); fgets(line, 200,stdin); *(line + 200) = '\0'; strtrm(line); if(strcmp(line,"I BACKED UP")) { puts("You need to type I BACKED UP (in uppercase)"); puts("to do the upgrade. You didn't so I quit!\n\n"); exit(1); } } /** builds a list of the courses found in course_base directory *** course_base can be either ../courses or ../templates **/ XML_COURSE_INFO_LIST * build_course_list(const char *course_base, const char *subdir, XML_COURSE_INFO_LIST *list) { XML_COURSE_INFO *ptr; DIR *dir_ptr; struct dirent *dir_entry; CONFIG_STRUCT conf; int doing_templates; doing_templates = (int)strstr(course_base,"templates"); if(!doing_templates) printf("\nBuilding a list of normal and standalone courses in the 'courses' directory.\n"); else printf("\nBuilding a list of course templates in the 'templates' directory.\n"); dir_ptr = opendir(course_base); if(!dir_ptr) { perror(course_base); exit(1); } while(NULL != (dir_entry = readdir(dir_ptr))) { if(*(dir_entry->d_name) != '.') { printf("."); fflush(stdout); ptr = (XML_COURSE_INFO*)malloc(sizeof(XML_COURSE_INFO)); if(!ptr) { perror("malloc() failed - Not enough memory?"); exit(1); } /* store the name of the subdir (which is really SUBDIR_NAME ** This will be changed later for course templates */ strncpy(ptr->subdir, subdir, MAX_COURSE_SUBDIR +1); *(ptr->subdir + MAX_COURSE_SUBDIR) = '\0'; /*** store the internal name of the course ***/ strncpy(ptr->dir_id, dir_entry->d_name, MAX_COURSE_DIRNAME + 1); *(ptr->dir_id + MAX_COURSE_DIRNAME) = '\0'; /** Try to read the config.dat file *** If we can't there's a problem, so stop **/ if(!read_configuration_file_ok(dir_entry->d_name, &conf)) { printf("\n\nThe directory named %s/%s is not a valid course directory.\n", course_base, dir_entry->d_name); printf("\n\nAre you SURE you are upgrading from version 2.0 or 2.0.1???\n\n"); printf("If so, move this directory out of the way and try again.\n\n"); exit(1); } ptr->course_type = (conf.standalone)? STANDALONE : (conf.template)? TEMPLATE:CENTRAL; switch(ptr->course_type) { case STANDALONE: standalone_count++; break; case TEMPLATE : template_count++; break; default: normal_count++; break; } strncpy(ptr->course_code, conf.course_no, MAX_COURSE_NO +1); strncpy(ptr->title, conf.title, MAX_COURSE_TITLE +1); strncpy(ptr->semester, conf.semester, MAX_SEMESTER +1); /* get a list of users in this course */ ptr->user_head = build_option_person_list(&conf); ptr->user_current = ptr->user_head; ptr->next =0; if(!list->head) list->head = ptr; else list->current->next = ptr; list->current = ptr; } } if(doing_templates) printf("\nFound %d course_templates.\n", template_count); else printf("\nFound %d normal and %d standalone courses.\n", normal_count, standalone_count); closedir(dir_ptr); return list; } /*** copies the username of the first teacher found **** in list to 'username'. Returns 1 if a teacher **** was found, else returns 0 ***/ int find_temp_course_teacher(char *username, P_NODE *head) { P_NODE *ptr; for(ptr = head; ptr; ptr = ptr->next) { if(ptr->data.group == FACULTY) { strncpy(username, ptr->data.username, MAX_USERNAME +1); return 1; } } return 0; } /*** For course templates, the subdirectory is actually **** derived as 'T' followed by the teacher's username. **** This function changes the value of 'subdir' to the **** new correct value ***/ void update_temp_course_list(XML_COURSE_INFO_LIST *list) { XML_COURSE_INFO *ptr; char username[MAX_USERNAME +1]; printf("\nDetermining subdirectory name for the course templates."); fflush(stdout); for(ptr = list->head; ptr; ptr = ptr->next) { printf("."); fflush(stdout); if(find_temp_course_teacher(username, ptr->user_head)) { snprintf(ptr->subdir, MAX_COURSE_SUBDIR +1, "T%s", username); *(ptr->subdir + MAX_COURSE_SUBDIR) = '\0'; } else { printf("\nCould not find a teacher in the course template: %s\n", ptr -> dir_id); puts("Aborting.\n\n"); exit(1); } } puts("done\n"); } /** For each course in list, add the user to the USERNAME_COURSES list *** (if not already there) and add the course to their list of courses *** Do this only for courses that are not standalone courses! **/ USERNAME_COURSES * get_all_users(XML_COURSE_INFO_LIST *list, USERNAME_COURSES *head) { char course_path[MAX_PATH +1]; for(list->current = list->head; list->current; list->current = list->current->next) { if(list->current->course_type != STANDALONE) { snprintf(course_path, MAX_PATH +1, "%s/%s", list->current->subdir, list->current->dir_id); for(list->current->user_current = list->current->user_head; list->current->user_current; list->current->user_current=list->current->user_current->next) { printf("."); fflush(stdout); head = insert_username_data(head, list->current->user_current->data.username, course_path); } } } return head; } void print_username_course_list(USERNAME_COURSES *list) { USERNAME_COURSES *ptr; for(ptr = list; ptr; ptr = ptr->next) { printf("****\nUsername: %s\n", ptr->username); for(ptr->course_current = ptr->course_head; ptr->course_current; ptr->course_current=ptr->course_current->next) printf("course_path: %s\n", ptr->course_current->course_path); } } void update_user_course_list(USERNAME_COURSES *head) { USERNAME_COURSES *ptr; char course_list[MAX_PATH +1]; FILE *fp; for(ptr = head; ptr; ptr = ptr->next) { printf("."); fflush(stdout); snprintf(course_list, MAX_PATH + 1, "../%s/%c/%s/%s", USERS_DIR, sub_dir_name(ptr->username), ptr->username, COURSE_LIST_FNAME); fp = fopen(course_list, "w"); if(fp) { for(ptr->course_current = ptr->course_head; ptr->course_current; ptr->course_current=ptr->course_current->next) fprintf(fp, "%s\n", ptr->course_current->course_path); } fclose(fp); } } void move_courses_to_subdir(XML_COURSE_INFO_LIST *list) { char dir_path[MAX_PATH +1]; char cmd[MAX_PATH *2 +1]; for(list->current = list->head; list->current; list->current = list->current->next) { if(list->current->course_type == TEMPLATE) snprintf(dir_path, MAX_PATH +1, "%s%s", TEMPLATE_PATH, list->current->subdir); else snprintf(dir_path, MAX_PATH +1, "%s%s", COURSE_PATH, list->current->subdir); mkdir(dir_path, 0777); snprintf(cmd, MAX_PATH*2+1, "cd %s; mv %s %s; cd ../src", list->current->course_type == TEMPLATE ? TEMPLATE_PATH : COURSE_PATH, list->current->dir_id, list->current->subdir); system(cmd); printf("."); fflush(stdout); } } void print_list(XML_COURSE_INFO_LIST *list) { for(list->current = list->head; list->current; list->current = list->current->next) { printf("*****\n"); printf("subdir = %s\n", list->current->subdir); printf("dir_id = %s\n", list->current->dir_id); for(list->current->user_current = list->current->user_head; list->current->user_current; list->current->user_current =list->current->user_current->next) { printf("Username: %s\n", list->current->user_current->data.username); printf("ID: %s\n", list->current->user_current->data.id); printf("Realname: %s\n", list->current->user_current->data.realname); } } } void free_xml_data_list( XML_COURSE_INFO_LIST *list) { XML_COURSE_INFO *ptr; list->current = list->head; while(list->current) { ptr = list->current->next; if(list->current->user_head) free_option_person_list(list->current->user_head); free(list->current); list->current = ptr; } free(list); } void print_course_info(XML_COURSE_INFO_LIST *list) { for(list->current = list->head; list->current; list->current = list->current->next) { printf("*********\nCourse No: %s\n", list->current->course_code); printf("Course Title: %s\n", list->current->title); printf("Course Semester: %s\n", list->current->semester); printf("Course subdir: %s\n", list->current->subdir); printf("Course id: %s\n", list->current->dir_id); printf("Course Type: %s\n", list->current->course_type == NORMAL ? "Normal" : list->current->course_type == TEMPLATE ? "template" : "standalone"); } } void print_msg(const char *subdir, XML_COURSE_INFO_LIST *list, XML_COURSE_INFO_LIST *temp_list) { if(list->head) { printf("\n\n#############\nCreated subdir: %s in courses directory\n", subdir); printf("The following normal and standalone courses have been moved to directory: %s\n", subdir); print_course_info(list); } if(temp_list->head) { printf("\n\n############\nTemplate courses are organized by teacher's username. \nThat means each teacher has their own subdir for all his/her template courses\n"); print_course_info(temp_list); } } void move_logs() { system("mv ../users/logs ../users/old_logs"); system("mkdir ../users/logs ; chgrp www ../users/logs ; chmod 770 ../users/logs"); } /*** driver for the upgrade process ***/ void do_upgrade(const char *subdir) { XML_COURSE_INFO_LIST *list; /* a list of normal and standalone courses */ XML_COURSE_INFO_LIST *temp_list; /* a list of course templates */ USERNAME_COURSES *head =0; /* a list of usernames and the courses they belong to */ /* create the empty normal and standalone list structure */ list = (XML_COURSE_INFO_LIST *)malloc(sizeof(XML_COURSE_INFO_LIST)); if(!list) { perror("malloc() failed - Not enough memory?"); exit(1); } list->head = 0; list->current = 0; /* create the empty course template list structure */ temp_list = (XML_COURSE_INFO_LIST *)malloc(sizeof(XML_COURSE_INFO_LIST)); if(!temp_list) { perror("malloc() failed - Not enough memory?"); exit(1); } temp_list->head = 0; temp_list->current = 0; list = build_course_list("../courses", subdir, list); /* build a list of normal and standalone courses */ temp_list =build_course_list("../templates", subdir, temp_list); /* build a list of course templates */ /** If there are any course templates, we need to figure out which *** subdirectory within the templates directory each template needs to *** be stored in. **/ if(temp_list->head) update_temp_course_list(temp_list); /* If there were any normal or standalone courses, add the users to ** the username list (which also records which courses they belong to) */ if(list->head) { printf("Building a list of users in normal courses."); fflush(stdout); head = get_all_users(list, head); puts("done\n"); } /** If there were any course templates, add the users to the username list */ if(temp_list->head) { printf("Building a list of users in course templates."); fflush(stdout); head = get_all_users(temp_list, head); puts("done\n"); } /** If there were any normal/standalone courses, move them to the subdirectory */ if(list->head) { printf("Moving normal and standalone course directories."); fflush(stdout); move_courses_to_subdir(list); puts("done\n"); } /*** move the course templates to the appropriate subdir within the templates dir ***/ if(temp_list->head) { printf("Moving course template directories."); fflush(stdout); move_courses_to_subdir(temp_list); puts("done\n"); } /*** rewrite all of the individual user's course list files ****/ if(head) { printf("Updating user info to reflect new course locations."); fflush(stdout); update_user_course_list(head); puts("done\n"); } /* report success ***/ // print_msg( subdir, list, temp_list); free_xml_data_list( list); free_xml_data_list( temp_list); free_username_courses(head); /* the old log files need to be moved away, since they are incompatible ** with the new version **/ puts("Moving obsolete login logs to ../users/old_logs.\n"); move_logs(); /** need to delete this index file so the super-user can re-create *** his account **/ puts("Deleting administrative user accounts.\n"); unlink("../users/admin/index.txt"); } void show_super_user_instructions() { printf("\n\nYou must now create a new super-user account.\n"); printf("Visit: http(s)://YOURSERVER.edu/%s/super_conf\n\n", SBIN_ALIAS); } /** checks to see if a file named SUBDIR_NAME *** already exists in the courses directory. *** If it does, we stop, since it (probably) means *** this program was already run once **/ void check_validity() { char path[MAX_PATH + 1]; snprintf(path, MAX_PATH + 1, "../courses/%s", SUBDIR_NAME); if(file_exists(path)) { printf("A directory (or file) named %s already exists.\n", path); printf("Did you already run this program?\n"); printf("Aborting\n\n."); exit(1); } } int main() { show_instructions(); check_validity(); do_upgrade(SUBDIR_NAME); show_super_user_instructions(); return 0; }