static char rcsid[] = "@(#)$Id: elmregister.c,v 1.42.2.2 2007/09/02 13:31:06 hurtta Exp $"; /****************************************************************************** * The Elm (ME+) Mail System - $Revision: 1.42.2.2 $ $State: Exp $ * * Author: Kari Hurtta (was hurtta+elm@ozone.FMI.FI) *****************************************************************************/ #include "defs_major.h" #include "patchlevel.h" #include "reghelper.h" /* Protocol in PIPE: * * file descriptor given on $ELM_INSTALLER * installer root given on $ELM_ROOT * * filenames are relative to $ELM_ROOT * * -- module * 'm' module {rest of line} * * -- copy file * * 'F' user group mode filename '\n' * 'd' user group mode filename '\n' (document) * 's' user group mode filename '\n' (stage file) * * -- create directory * * 'M' user group mode filename '\n' * * -- execute * {n} user group mode filename '\n' * {n} user group mode filename'\n' * * 'E' filename {n} xx yy {n} '\n' * * -- config file touched on replay time * * 'C' user group mode filename'\n' * * -- remove files * * 'R' file file file '\n' * * -- link file * * 'L' file file '\n' * */ #define IMPARGDIR "{--implicit-stage-directory--}" /* putenv.c */ #ifndef PUTENV extern int putenv P_((char *)); #endif /* strstr.c */ #ifndef STRSTR extern char *strstr P_((char *,char *)); #endif #ifdef PWDINSYS # include # include /* TODO: Not necessary correct .... */ #else # include # include #endif #include #ifndef ANSI_C extern int errno; #endif #if defined(BSD_TYPE) && !defined(WEXITSTATUS) typedef union wait S__; #else typedef int S__; #endif static char * filelist = SYSTEM_DEFAULT_FILELIST; static char * stage_dir = STAGE_DIR; static char * register_pipe = "$ELM_INSTALLER"; /* To be assigned */ int register_fd = -1; static char * installer_root = "$ELM_ROOT"; /* To be assigned */ char * program_name = "elmregister"; /* To be assigned */ char * register_module = NULL; static int create_pipe P_((int argc, char *argv[], int x, int *PID, char *root, char *module)); static int create_pipe(argc,argv,x,PID,root,module) int argc; char *argv[]; int x; int *PID; char *root; char *module; { static char array[] = "ELM_INSTALLER=XXXX"; int filedes[2]; int z = pipe(filedes); char *command; int pid; if (z < 0) { fprintf(stderr,"%s: pipe() failed\n",program_name); exit(1); } if (x >= argc) { fprintf(stderr,"%s: No command given\n",program_name); exit(1); } command = argv[x]; fflush(stdout); pid = fork(); /* BRANCH child process */ if (0 == pid) { int l = strlen(root) + 12; char *array2 = malloc(l); sprintf(array,"ELM_INSTALLER=%d",filedes[1]); if (!array2) { fprintf(stderr,"%s: malloc %d bytes failed\n",program_name,l); exit(1); } sprintf(array2,"ELM_ROOT=%s",root); if (0 != putenv(array)) { fprintf(stderr,"%s: putenv() failed\n",program_name); exit(1); } if (0 != putenv(array2)) { fprintf(stderr,"%s: putenv() failed\n",program_name); exit(1); } if (module) { int l = strlen(root) + 15; char *array3 = malloc(l); sprintf(array3,"ELM_MODULE=%s",module); if (0 != putenv(array3)) { fprintf(stderr,"%s: putenv() failed\n",program_name); exit(1); } } close(filedes[0]); /* read end */ fprintf(stdout,"%s: Running %s ...\n", program_name,command); execvp(command,argv+x); fprintf(stderr, "%s: Failed to EXECute %s\n",program_name,command); fflush(stderr); _exit(127); } if (pid < 0) { fprintf(stderr,"%s: fork() failed\n",program_name); exit(1); } close(filedes[1]); /*write end */ *PID=pid; return filedes[0]; } #define MAX_ARGS 300 static void make_package_dir P_((char *y,char *root)); static void make_package_dir(y,root) char *y; char *root; { int l = strlen(root); char *Z; char *x; if (l < 2) return; Z = strdup(y); if (0 != strncmp(Z,root,l)) { free(Z); return ; } for (x = Z + l; *x; x++) { if ('/' == *x) { *x = '\0'; if (0 == mkdir(Z,0755)) { fprintf(stdout, "%s: parent directory %s created (of %s)\n", program_name,Z,y); } *x = '/'; } } free(Z); } struct log_record { char * buffer; int buffer_len; char * module_ptr; int command_letter; char * command_ptr; /* Following points to space on buffer ... */ char * user_ptr; char * group_ptr; char * mode_ptr; char ** arg_ptrs; }; struct log_entries { char * version; struct log_record * log; int log_count; }; struct log_instance { FILE *file; char *filename; struct log_entries * entries; int entries_count; }; static void clear_log_instance P_((struct log_instance *LI)); static void clear_log_instance(LI) struct log_instance *LI; { LI->file = NULL; LI->filename = NULL; LI->entries = NULL; LI->entries_count = 0; } static void add_bytes P_((FILE *F,char * buffer, int *ptr)); static void add_bytes(F,buffer,ptr) FILE *F; char * buffer; int *ptr; { while (1) { int c = fgetc(F); if (EOF == c) { fprintf(stderr,"%s: Failed to read from pipe or file (or EOF)\n", program_name); exit(1); } if (*ptr > MAX_PIPE_LOG) { fprintf(stderr,"%s: Record from pipe or file too long\n", program_name); exit(1); } buffer[*ptr] = c; (*ptr)++; if (0 == c) { /* END OF RECORD MARK */ return; } } } static void parse_log_tail P_(( struct log_record *l, char buffer1[MAX_PIPE_LOG +10 ], int ptr, int module_ptr, int command_ptr, int user_ptr, int group_ptr, int mode_ptr, int args_ptr[MAX_ARGS], int argnum)); static void parse_log P_((FILE *F, struct log_record *l)); static void parse_log(F,l) FILE *F; struct log_record *l; { char buffer1[MAX_PIPE_LOG +10 ]; /* write routines quarantee that this is enough! */ int ptr = 0; int c = fgetc(F); int module_ptr = -1; int command_ptr = -1; int user_ptr = -1; int group_ptr = -1; int mode_ptr = -1; int args_ptr[MAX_ARGS]; int argnum = 0; l->buffer = NULL; l->buffer_len = 0; l->module_ptr = NULL; l->command_ptr = NULL; l->user_ptr = NULL; l->group_ptr = NULL; l->mode_ptr = NULL; l->arg_ptrs = NULL; if (EOF == c) { /* EOF or error */ l->command_letter = EOF; return; } ungetc(c,F); /* add_bytes reread character */ command_ptr = ptr; add_bytes(F,buffer1,&ptr); if (buffer1[0] != c) { fprintf(stderr,"%s: Character %c not buffered (reading from pipe or file)\n", program_name,c); exit(1); } if ('m' == c) { module_ptr = ptr; add_bytes(F,buffer1,&ptr); /* module */ command_ptr = ptr; add_bytes(F,buffer1,&ptr); /* command */ c = buffer1[command_ptr]; } l->command_letter = c; switch (c) { case 'F': case 'd': user_ptr = ptr; add_bytes(F,buffer1,&ptr); /* user */ group_ptr = ptr; add_bytes(F,buffer1,&ptr); /* group */ mode_ptr = ptr; add_bytes(F,buffer1,&ptr); /* mode */ args_ptr[0] = ptr; add_bytes(F,buffer1,&ptr); /* target file */ argnum = 1; break; case '{': /* .... filename variable already readed */ user_ptr = ptr; add_bytes(F,buffer1,&ptr); /* user */ group_ptr = ptr; add_bytes(F,buffer1,&ptr); /* group */ mode_ptr = ptr; add_bytes(F,buffer1,&ptr); /* mode */ args_ptr[0] = ptr; add_bytes(F,buffer1,&ptr); /* target file */ argnum = 1; break; case 'C': case 'M': case 's': user_ptr = ptr; add_bytes(F,buffer1,&ptr); /* user */ group_ptr = ptr; add_bytes(F,buffer1,&ptr); /* group */ mode_ptr = ptr; add_bytes(F,buffer1,&ptr); /* mode */ args_ptr[0] = ptr; add_bytes(F,buffer1,&ptr); /* target file */ argnum = 1; break; case 'L': args_ptr[0] = ptr; add_bytes(F,buffer1,&ptr); /* file1 file */ args_ptr[1] = ptr; add_bytes(F,buffer1,&ptr); /* file2 file */ argnum = 2; break; case 'R': case 'E': do { int n = ptr; c = fgetc(F); if (EOF == c) { fprintf(stderr,"%s: unexpected EOF\n", program_name); exit(1); } ungetc(c,F); /* add_bytes reread character */ if ('\n' == c) break; if (argnum >= MAX_ARGS) { fprintf(stderr,"%s: Too many arguments on pipe or file\n", program_name); exit(1); } args_ptr[argnum++] = ptr; add_bytes(F,buffer1,&ptr); if (buffer1[n] != c) { fprintf(stderr,"%s: Character %c not buffered (reading from pipe or file)\n", program_name,c); exit(1); } } while(1); break; default: fprintf(stderr,"%s: Bad command letter: %c (reading from pipe or file)\n", program_name,c); exit(1); } c = fgetc(F); if ('\n' != c) { fprintf(stderr,"%s: newline expected: %c (reading from pipe or file)\n", program_name,c); exit(1); } l->buffer_len = ptr; l->buffer = malloc(l->buffer_len); if (! l->buffer ) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,l->buffer_len); exit(1); /* FAILURE */ } parse_log_tail(l,buffer1,ptr,module_ptr,command_ptr,user_ptr, group_ptr,mode_ptr,args_ptr,argnum); } static void parse_log_tail(l,buffer1,ptr,module_ptr,command_ptr,user_ptr, group_ptr,mode_ptr,args_ptr,argnum) struct log_record *l; char buffer1[MAX_PIPE_LOG +10 ]; /* write routines quarantee that this is enough! */ int ptr; int module_ptr; int command_ptr; int user_ptr; int group_ptr; int mode_ptr; int args_ptr[MAX_ARGS]; int argnum; { memcpy(l->buffer,buffer1,l->buffer_len); if (module_ptr != -1) l->module_ptr = l->buffer + module_ptr; if (command_ptr != -1) l->command_ptr = l->buffer + command_ptr; if (user_ptr != -1) l->user_ptr = l->buffer + user_ptr; if (group_ptr != -1) l->group_ptr = l->buffer + group_ptr; if (mode_ptr != -1) l->mode_ptr = l->buffer + mode_ptr; if (argnum > 0) { int i; l->arg_ptrs = malloc((argnum +1) * sizeof (l->arg_ptrs[0])); if (!l->arg_ptrs) { fprintf(stderr,"%s: malloc %d items failed\n", program_name,argnum+1); exit(1); /* FAILURE */ } for (i = 0; i < argnum; i++) l->arg_ptrs[i] = l->buffer + args_ptr[i]; l->arg_ptrs[argnum] = NULL; } } static void add_entries P_((struct log_instance *LI)); static void add_entries(LI) struct log_instance *LI; { struct log_entries * last = NULL; do { int c = fgetc(LI->file); if (EOF == c) { /* EOF or error */ return; } ungetc(c,LI->file); /* add_bytes reread character */ if ('[' == c) { char version_buffer[MAX_PIPE_LOG]; int ptr = 0; add_bytes(LI->file,version_buffer,&ptr); if (version_buffer[0] != c) { fprintf(stderr,"%s: Character %c not buffered (reading from file %s)\n", program_name,c,LI->filename); exit(1); } if (ptr <3 || version_buffer[ptr-2] != ']') { fprintf(stderr, "%s: File %s is not elmregister filelist\n", program_name,LI->filename); exit(1); } c = fgetc(LI->file); if ('\n' != c) { fprintf(stderr,"%s: newline expected: %c (reading from file %s)\n", program_name,c,LI->filename); exit(1); } LI->entries = realloc(LI->entries,(LI->entries_count+1) * sizeof (LI->entries[0])); if (! LI->entries) { fprintf(stderr, "%s: Failed to realloc %d items (file %s)\n", program_name,LI->entries_count+1,LI->filename); exit(1); } last = & (LI->entries[LI->entries_count]); LI->entries_count++; last -> version = strdup(version_buffer); if (!last -> version) { fprintf(stderr, "%s: Failed to strdup string (%d bytes?): %s (file %s)\n", program_name,ptr,version_buffer,LI->filename); exit(1); } last -> log = NULL; last -> log_count = 0; } else if (!last) { fprintf(stderr,"%s: OOPS (file %s)!\n", program_name,LI->filename); exit(1); } else { last -> log = realloc(last -> log, (last -> log_count+1) * sizeof (last -> log[0])); if (! last->log) { fprintf(stderr, "%s: Failed to realloc %d items (file %s)\n", program_name,last -> log_count+1,LI->filename); exit(1); } parse_log(LI->file,&( last -> log[last -> log_count] )); last -> log_count++; } } while (1); } static struct log_entries * add_last P_((struct log_instance *LI)); static struct log_entries * add_last(LI) struct log_instance *LI; { char buffer[ MAX_PIPE_LOG]; char *ptr; struct log_entries * last = NULL; #if ANSI_C char my_version[] = "[ELM" VERSION " " PATCHLEVEL "]"; #else char my_version[40]; sprintf(my_version,"[ELM %s %s]",VERSION,PATCHLEVEL); #endif /* Write version header --- */ ptr = buffer; add_to_buffer(buffer, sizeof buffer,&ptr,my_version,strlen (my_version)); *ptr++ = '\n'; /* Terminating NL on line */ if (ptr-buffer != fwrite(buffer,1,ptr-buffer,LI->file)) { fprintf(stderr,"%s: write error (file %s)\n", program_name,LI->filename); fclose(LI->file); exit (1); /* FAILURE */ } LI->entries = realloc(LI->entries,(LI->entries_count+1) * sizeof (LI->entries[0])); if (!LI->entries) { fprintf(stderr, "%s: Failed to realloc %d items (file %s)\n", program_name,LI->entries_count+1,LI->filename); fclose(LI->file); exit (1); /* FAILURE */ } last = & (LI->entries[LI->entries_count]); LI->entries_count++; last -> version = strdup(my_version); if (!last -> version) { fprintf(stderr, "%s: Failed to strdup string (%d bytes?): %s\n", program_name,ptr-buffer-1,my_version); fclose(LI->file); exit(1); /* FAILURE */ } last -> log = NULL; last -> log_count = 0; return last; } static int take_arg P_((char *buffer, char *ptr, int L)); static int take_arg(buffer,ptr,L) char *buffer; char *ptr; int L; { int n; if (!ptr) return -1; n = ptr - buffer; if (n < 0 || n >= L) { fprintf(stderr,"%s: [take_arg] bad argument\n",program_name); exit(1); } return n; } static void move_record P_((struct log_instance *LI,struct log_entries * last, struct log_record *L)); static void move_record(LI,last,L) struct log_instance *LI; struct log_entries * last; struct log_record *L; { int module_ptr; int command_ptr; int user_ptr; int group_ptr; int mode_ptr; int args_ptr[MAX_ARGS]; int argnum = 0; last -> log = realloc(last -> log, (last -> log_count+1) * sizeof (last -> log[0])); last -> log[last -> log_count].buffer = malloc(L->buffer_len); if (!last -> log[last -> log_count].buffer) { fprintf(stderr,"%s: malloc %d bytes failed\n",program_name, L->buffer_len); exit(1); } last -> log[last -> log_count].buffer_len = L->buffer_len; last -> log[last -> log_count].module_ptr = NULL; last -> log[last -> log_count].command_letter = L->command_letter; last -> log[last -> log_count].command_ptr = NULL; last -> log[last -> log_count].user_ptr = NULL; last -> log[last -> log_count].group_ptr = NULL; last -> log[last -> log_count].mode_ptr = NULL; last -> log[last -> log_count].arg_ptrs = NULL; module_ptr = take_arg(L->buffer,L->module_ptr,L->buffer_len); command_ptr = take_arg(L->buffer,L->command_ptr,L->buffer_len); user_ptr = take_arg(L->buffer,L->user_ptr,L->buffer_len); group_ptr = take_arg(L->buffer,L->group_ptr,L->buffer_len); mode_ptr = take_arg(L->buffer,L->mode_ptr,L->buffer_len); while (L->arg_ptrs && L->arg_ptrs[argnum] && argnum < MAX_ARGS) { args_ptr[argnum] = take_arg(L->buffer,L->arg_ptrs[argnum], L->buffer_len); argnum++; } if (L->buffer_len != fwrite(L->buffer,1,L->buffer_len,LI->file)) { fprintf(stderr, "%s: write error (file %s)\n", program_name,LI->filename); fclose(LI->file); exit (1); /* FAILURE */ } putc('\n',LI->file); parse_log_tail(& last -> log[last -> log_count], L->buffer, L->buffer_len, module_ptr, command_ptr, user_ptr, group_ptr, mode_ptr, args_ptr, argnum); last -> log_count++; } static void log_copy_loop P_((FILE *fd, struct log_instance *target, struct log_entries * last)); static void log_copy_loop(fd,target,last) FILE *fd; struct log_instance *target; struct log_entries * last; { while(1) { struct log_record L; parse_log(fd,&L); if (EOF != L.command_letter) { move_record(target,last,&L); } /* L.buffer and L.arg_ptrs are only think what are malloced */ if (L.buffer) { free(L.buffer); L.buffer = NULL; } if (L.arg_ptrs) { free(L.arg_ptrs); L.arg_ptrs = NULL; } if (EOF == L.command_letter) { fprintf(stderr,"%s: EOF from pipe\n",program_name); break; } } } static void remove_unlinked1 P_((struct log_instance *target,int Z, char *relative, int *count)); static void remove_unlinked1(target,Z,relative,count) struct log_instance *target; int Z; char *relative; int *count; { int i; for (i = 0; i < target->entries_count && i < Z; i++) { struct log_record * ptr2; for (ptr2 = target->entries[i].log; ptr2 < target->entries[i].log + target->entries[i].log_count; ptr2++) { switch (ptr2->command_letter) { case 'M': case '{': case 's': case 'F': case 'd': case 'C': if (ptr2->arg_ptrs && ptr2->arg_ptrs[0] && 0 == strcmp(ptr2->arg_ptrs[0],relative)) { (*count) ++; if (ptr2->buffer) { free(ptr2->buffer); ptr2->buffer = NULL; } if (ptr2->arg_ptrs) { free(ptr2->arg_ptrs); ptr2->arg_ptrs = NULL; } ptr2->command_letter = '\0'; /* ENTRY DELETED */ } break; case 'L': /* SECOND ARGUMENT IS NEW NAME */ if (ptr2->arg_ptrs && ptr2->arg_ptrs[1] && 0 == strcmp(ptr2->arg_ptrs[1],relative)) { (*count) ++; if (ptr2->buffer) { free(ptr2->buffer); ptr2->buffer = NULL; } if (ptr2->arg_ptrs) { free(ptr2->arg_ptrs); ptr2->arg_ptrs = NULL; } ptr2->command_letter = '\0'; /* ENTRY DELETED */ } break; } } } } static char * make_rooted P_((struct log_record * ptr, char *rel, char *root)); static char * make_rooted(ptr,rel,root) struct log_record * ptr; char *rel; char *root; { int L = strlen(root); int l = strlen(rel) + 2 + L; char * translated = malloc(l); if (!translated) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,l); exit (1); /* FAILURE */ } strcpy(translated,root); if ('/' == rel[0]) { fprintf(stderr, "%s: entry '%c' -- Not relative? %s\n", program_name,ptr->command_letter,rel); } else { if (L < 1 || root[L-1] != '/') { translated[L] = '/'; translated[L+1] = '\0'; } } strcat(translated,rel); return translated; } static void remove_unlinked P_((struct log_instance *target,char *root, int *remove_count)); static void remove_unlinked(target,root,remove_count) struct log_instance *target; char *root; int *remove_count; { int i; int y = 0; *remove_count = 0; for (i = 0; i < target->entries_count; i++) { struct log_record * ptr2; for (ptr2 = target->entries[i].log; ptr2 < target->entries[i].log + target->entries[i].log_count; ptr2++) { switch (ptr2->command_letter) { int j; case 'R': /* FILE DELETED */ if (!y) { y++; fprintf(stdout, "%s: Trimming unlinked files from %s\n", program_name,target->filename); } for (j = 0; ptr2->arg_ptrs[j] && j < MAX_ARGS; j++) { int count = 0; char * translated = make_rooted(ptr2,ptr2->arg_ptrs[j],root); struct stat X; if (stat(translated,&X) < 0) { remove_unlinked1(target,i,ptr2->arg_ptrs[j], &count); if (count > 0) { fprintf(stdout, "%s: (%s) File %s is removed -- removing from log\n", program_name,translated,ptr2->arg_ptrs[j]); *remove_count += count; } } free(translated); } break; } } } } static void rewrite_list P_((struct log_instance *target)); static void rewrite_list(target) struct log_instance *target; { FILE * new_fd; char *tempname; int l = strlen(target->filename); int i; tempname = malloc(l+4); if (!tempname) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,l); exit(1); /* FAILURE */ } strcpy(tempname,target->filename); strcat(tempname,"~N~"); if (0 == unlink(tempname)) { fprintf(stderr,"%s: %s unlinked\n",program_name,tempname); } new_fd = fopen(tempname,"w+"); if (!new_fd) { fail: fprintf(stderr, "%s: Failed to create %s -- %s not rewritten\n", program_name,tempname,target->filename); free(tempname); return; } fprintf(stdout,"%s: Rewriting %s\n",program_name,target->filename); for (i = 0; i < target->entries_count; i++) { char buffer[ MAX_PIPE_LOG]; char *ptr; struct log_record * ptr2; /* Write version header --- */ ptr = buffer; add_to_buffer(buffer, sizeof buffer,&ptr, target->entries[i].version, strlen (target->entries[i].version)); *ptr++ = '\n'; /* Terminating NL on line */ if (ptr-buffer != fwrite(buffer,1,ptr-buffer,new_fd)) { fprintf(stderr,"%s: write error (file %s)\n", program_name,tempname); fclose(new_fd); goto fail; } for (ptr2 = target->entries[i].log; ptr2 < target->entries[i].log + target->entries[i].log_count; ptr2++) { switch (ptr2->command_letter) { case '\0': /* ENTRY DELETED */ break; default: if (ptr2->buffer) { if (ptr2->buffer_len != fwrite(ptr2->buffer,1,ptr2->buffer_len,new_fd)) { fprintf(stderr, "%s: write error (file %s)\n", program_name,tempname); fclose(new_fd); goto fail; } putc('\n',new_fd); } break; } } } if (EOF == fflush(new_fd)) { fprintf(stderr, "%s: Failed to write %s\n", program_name,tempname); fclose(new_fd); goto fail; } if (-1 == rename(tempname,target->filename)) { fprintf(stderr, "%s: Failed to replace %s\n", program_name,target->filename); fclose(new_fd); goto fail; } fclose(target->file); target->file = new_fd; free(tempname); } static int master P_((int argc, char *argv[], int x)); static int master(argc, argv, x) int argc; char *argv[]; int x; { int read_pipe; int t; int c; int PID; int w; S__ status; FILE *fd = NULL; struct log_entries * last = NULL; struct stat X; char *X1; int remove_count; struct log_instance LI; clear_log_instance(&LI); installer_root = "/"; while (x < argc && '-' == argv[x][0]) { if (x < argc -1 && 0 == strcmp("-F", argv[x])) { filelist = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-R", argv[x])) { installer_root = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-M", argv[x])) { register_module = argv[x+1]; x += 2; } else { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } } if ('\0' == installer_root[0]) { fprintf(stderr,"%s: -R '' invalid\n", argv[0]); return 1; /* FAILURE */ } if (stat(installer_root,&X) < 0) { fprintf(stderr,"%s: -R %s invalid\n", argv[0],installer_root); return 1; /* FAILURE */ } if ( #ifdef S_ISDIR ! S_ISDIR(X.st_mode) #else S_IFDIR != (X.st_mode & S_IFMT) #endif ) { fprintf(stderr,"%s: -R %s invalid (not a directory)\n", argv[0],installer_root); return 1; /* FAILURE */ } /* We use open instead of fopen so that we can create file and not truncate existing file */ LI.filename = filelist; if (0 != strcmp(installer_root,"/")) { int l = strlen(filelist) + strlen(installer_root) +2; LI.filename = malloc(l); if (!LI.filename) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,l); return 1; /* FAILURE */ } sprintf(LI.filename,"%s%s",installer_root,filelist); } /* HACK */ X1 = strrchr(LI.filename,'/'); if (X1) { char *Z = strdup(LI.filename); if (Z) { X1 = strrchr(Z,'/'); *X1 = '\0'; make_package_dir(Z,installer_root); if (0 == mkdir(Z,0755)) { fprintf(stdout, "%s: Directory %s created\n", program_name,Z); } else if (errno != EEXIST) { fprintf(stderr, "%s: Failed to create %s directory\n", program_name,Z); exit(1); } free(Z); } } t = open(LI.filename,O_RDWR|O_CREAT,0644); if (t < 0) { fprintf(stderr, "%s: Failed to create or open file %s on %s: %s\n", program_name,filelist,installer_root, LI.filename); return 1; /* FAILURE */ } fprintf(stdout,"%s: Creating %s\n",program_name,LI.filename); LI.file = fdopen(t,"r+"); if (! LI.file) { fprintf(stderr,"%s: fdopen() failed\n",program_name); close(t); return 1; /* FAILURE */ } c = fgetc(LI.file); if (EOF != c) { if (c != '[') { fprintf(stderr, "%s: File %s is not elmregister filelist\n", program_name,LI.filename); close(t); return 1; /* FAILURE */ } ungetc(c,LI.file); /* add_bytes reread character */ add_entries(& LI); } last = add_last(&LI); read_pipe = create_pipe(argc,argv,x,&PID,installer_root,register_module); fd = fdopen(read_pipe,"r"); if (!fd) { fprintf(stderr,"%s: fdopen() failed\n",program_name); close(read_pipe); return 1; /* FAILURE */ } log_copy_loop(fd,&LI,last); remove_unlinked(&LI,installer_root,&remove_count); if (remove_count > 0) rewrite_list(&LI); if (EOF == fclose(LI.file)) { fprintf(stderr, "%s: Write(?) failed on closing of file: %s\n", program_name,LI.filename); return 1; /* FAILURE */ } fclose(fd); while ((w = #ifdef HASWAITPID waitpid(PID,&status,0) #else wait(status) #endif ) != PID) if (w == -1 && errno != EINTR) break; if (w != PID || status != 0) { fprintf(stderr, "%s: Failed to run %s\n", program_name,argv[x]); return 1; /* FAILURE */ } /* NOTE: LI leaked ... */ return 0; } static char * rel_path = ""; /* Path to prepended to log written on pipe ?? is this needed ?? */ /* Returns: 'S' relpath is relative to source 'T' relpath is relative to installer_root "//" on arg is supposed to be mark for $ELM_ROOT */ static int split_file P_((char *arg, char **fullpath, char **relpath)); static int split_file(arg,fullpath,relpath) char *arg; char **fullpath; char **relpath; /* relpath have rel_path prepended is original was relative */ { char *ptr = strstr(arg,"//"); int L = strlen(installer_root); while (L > 0 && '/' == installer_root[L-1]) L--; if (ptr && '/' == arg[0]) { /* TARGET FILE -- installer prefix given */ if (ptr-arg != L && 0 != strncmp(arg,installer_root,L)) { fprintf(stderr, "%s: prefix %.*s on %s do not match with $ELM_ROOT=%s\n", program_name,ptr-arg,arg,arg,installer_root); exit(1); /* FAILURE */ } *fullpath = strdup(arg); if (!*fullpath) { fprintf(stderr, "%s: strdup failed\n", program_name); exit(1); /* FAILURE */ } while ('/' == *ptr) ptr++; *relpath = strdup(ptr); if (!*relpath) { fprintf(stderr, "%s: strdup failed\n", program_name); exit(1); /* FAILURE */ } return 'T'; /* relpath is relative to installer_root */ } else if ('/' == arg[0]) { /* TARGET FILE -- installer prefix not given */ int x = L + 3 + strlen(arg); char *Y = arg; while('/' == *Y) Y++; *fullpath = malloc(x); if (!*fullpath) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,x); exit(1); /* FAILURE */ } strncpy(*fullpath,installer_root,L); strcpy(*fullpath +L,"//"); strcpy(*fullpath +L+2,Y); *relpath = strdup(Y); if (!*relpath) { fprintf(stderr, "%s: strdup failed\n", program_name); exit(1); /* FAILURE */ } return 'T'; /* relpath is relative to installer_root */ } else { /* SOURCE FILE ... */ int y = strlen(rel_path); int x = y + strlen(arg) + 1; *fullpath = strdup(arg); if (!*fullpath) { fprintf(stderr, "%s: strdup failed\n", program_name); exit(1); /* FAILURE */ } *relpath = malloc(x); if (!*relpath) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,x); exit(1); /* FAILURE */ } strcpy(*relpath,rel_path); strcpy(*relpath + y, arg); return 'S'; /* relpath is relative to source */ } } static char * gen_tempname P_((char * target)); static char * gen_tempname(target) char * target; { int l = strlen(target) + 10; char *tempname = malloc(l); if (!tempname) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,l); exit(1); /* FAILURE */ } strcpy(tempname,target); strcat(tempname,"~_~"); return tempname; } /* 0 == OK */ static int install_file P_((char * source, char * target, uid_t user, gid_t group, int mode)); static int install_file(source,target,user,group,mode) char * source; char * target; uid_t user; gid_t group; int mode; { char * tempname; FILE * F, *S; int c; /* HACK */ char *Z = strdup(target); if (Z) { char * X1 = strrchr(Z,'/'); if (X1) { *X1 = '\0'; if (0 == mkdir(Z,0755)) { int r = 0; if (user != (uid_t)-1 || group != (gid_t)-1) { r = chown(Z,user,group); } fprintf(stdout, "%s: Directory %s created%s\n", program_name,Z, r == -1 ? " (failed to set owner)" : ""); } else if (errno != EEXIST) { fprintf(stderr, "%s: Failed to create %s directory\n", program_name,Z); free(Z); return 1; /* FAILURE */ } } free(Z); } tempname = gen_tempname(target); if (0 == unlink(tempname)) { fprintf(stderr,"%s: %s unlinked\n",program_name,tempname); } F = fopen(tempname,"w"); if (!F) { fprintf(stderr,"%s: Failed to create %s\n", program_name,tempname); return 1; /* FAILURE */ } S = fopen(source,"r"); if (!F) { fprintf(stderr,"%s: Failed to read %s\n", program_name,source); fclose(F); unlink(tempname); return 1; /* FAILURE */ } while (EOF != (c = getc(S))) { if (putc(c,F) == EOF) { fclose(F); fail: fprintf(stderr,"%s: Failed to write %s\n", program_name,tempname); fclose(S); unlink(tempname); return 1; /* FAILURE */ } } if (ferror(S)) { fprintf(stderr,"%s: Failed to read %s\n", program_name,source); fclose(S); fclose(F); unlink(tempname); return 1; /* FAILURE */ } if (EOF == fclose(F)) { goto fail; } if (-1 == rename(tempname,target)) { fprintf(stderr, "%s: Failed to replace %s\n", program_name,target); goto fail; } if (user != (uid_t)-1 || group != (gid_t)-1) { if (-1 == chown(target,user,group)) { fprintf(stderr,"%s: Failed to set owner of %s\n", program_name,target); } } if (-1 == chmod(target,mode)) { fprintf(stderr,"%s: Failed to set mode of %s\n", program_name,target); } fprintf(stdout,"%s: File %s installed\n", program_name,target); fclose(S); free(tempname); return 0; } static void copy_dir P_((char *src,char *trg, char *rel, struct log_instance *LI, struct log_entries * last, char *register_module)); #ifdef DIROPS #if DIROPS == USE_DIRENT #include #endif /* DIROPS == USE_DIRENT */ #if DIROPS == USE_SYSDIR #include #endif /* DIROPS == USE_SYSDIR */ static void copy_dir(src,trg,rel,LI,last, register_module) char *src; char *trg; char *rel; struct log_instance *LI; struct log_entries * last; char *register_module; { DIR * handle; #if DIROPS == USE_DIRENT struct dirent * Xptr; #endif /* DIROPS == USE_DIRENT */ #if DIROPS == USE_SYSDIR struct direct * Xptr; #endif /* DIROPS == USE_SYSDIR */ int slen = strlen(src); int tlen = strlen(trg); int rlen = strlen(rel); handle = opendir(src); if (!handle) { fprintf(stderr, "%s: Failed to open directory %s\n", program_name,src); exit(1); /* FAILURE */ } fprintf(stdout, "%s: Copying directory %s -> %s:\n", program_name,src,trg); if (0 == mkdir(trg,0755)) { fprintf(stdout, "%s: Directory %s created\n", program_name,trg); } else if (errno != EEXIST) { fprintf(stderr, "%s: Failed to create %s directory\n", program_name,trg); exit (1); /* FAILURE */ } while (NULL != (Xptr = readdir(handle))) { if ('.' != Xptr->d_name[0]) { int L; struct stat X; char *fullname; int elen; #if DIROPS == USE_DIRENT char * entryname = strdup(Xptr->d_name); if (!entryname) { fprintf(stderr,"%s: strdup failed: %s\n", program_name,Xptr->d_name); exit(1); /* FAILURE */ } #endif /* DIROPS == USE_DIRENT */ #if DIROPS == USE_SYSDIR char * entryname = malloc(Xptr->d_namlen+1); if (!entryname) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,Xptr->d_namlen+1); exit(1); /* FAILURE */ } strncpy(entryname,Xptr->d_name,Xptr->d_namlen); entryname[Xptr->d_namlen] = '\0'; #endif /* DIROPS == USE_SYSDIR */ elen = strlen(entryname); L = elen + 3 + slen; fullname = malloc(L); if (!fullname) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,L); exit(1); /* FAILURE */ } strcpy(fullname,src); strcat(fullname,"/"); strcat(fullname,entryname); if (stat(fullname,&X) < 0) { fprintf(stderr,"%s: Can't stat %s\n", program_name,fullname); exit(1); /* FAILURE */ } if ( #ifdef S_ISREG S_ISREG(X.st_mode) #else S_IFREG == (buf.st_mode & S_IFMT) #endif ) { int l2 = tlen + 3 + elen; char * fulltrgname = malloc(l2); char * relname; int l3; if (!fulltrgname) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,l2); exit(1); /* FAILURE */ } strcpy(fulltrgname,trg); strcat(fulltrgname,"/"); strcat(fulltrgname,entryname); if (0 != install_file(fullname,fulltrgname, (uid_t)-1, (gid_t)-1, X.st_mode & 0777)) { fprintf(stderr, "%s: Install %s -> %s failed\n", program_name, fullname,fulltrgname); exit(1); /* FAILURE */ } l3 = rlen + 3 + elen; relname = malloc(l3); if (!relname) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,l3); exit(1); /* FAILURE */ } strcpy(relname,rel); strcat(relname,"/"); strcat(relname,entryname); if (!last) log_it("s",relname,"-","-", X.st_mode & 0777, register_module); else { char buffer[ MAX_PIPE_LOG]; char *ptr; char mode_s[6]; int rname = strlen(relname); int L; struct log_record L1; int module_ptr = -1; int command_ptr = -1; int user_ptr = -1; int group_ptr = -1; int mode_ptr = -1; int args_ptr[1]; int argnum = 0; sprintf(mode_s,"%05o",X.st_mode & 0777); ptr = buffer; if (register_module) { int l = strlen(register_module); add_to_buffer(buffer, sizeof buffer,&ptr,"m",1); module_ptr = ptr-buffer; add_to_buffer(buffer, sizeof buffer,&ptr, register_module,l); } command_ptr = ptr-buffer; add_to_buffer(buffer, sizeof buffer,&ptr,"s",1); user_ptr = ptr-buffer; add_to_buffer(buffer, sizeof buffer,&ptr,"-",1); group_ptr = ptr-buffer; add_to_buffer(buffer, sizeof buffer,&ptr,"-",1); mode_ptr = ptr-buffer; add_to_buffer(buffer, sizeof buffer,&ptr,mode_s,5); args_ptr[argnum++] = ptr-buffer; add_to_buffer(buffer, sizeof buffer,&ptr,relname,rname); /* NO terminating NL to buffer */ L = ptr - buffer; if (L > MAX_PIPE_LOG-2) { fprintf(stderr,"%s: Can't register file, string too long: %d\n", program_name,L); exit(1); } L1.buffer = malloc(L); if (!L1.buffer) { fprintf(stderr,"%s: malloc %d bytes failed\n",program_name, L); exit(1); } L1.buffer_len = L; L1.command_letter = 's'; parse_log_tail(&L1,buffer,L,module_ptr,command_ptr,user_ptr, group_ptr,mode_ptr,args_ptr,argnum); last -> log = realloc(last -> log, (last -> log_count+1) * sizeof (last -> log[0])); if (! last->log) { fprintf(stderr, "%s: Failed to realloc %d items (file %s)\n", program_name,last -> log_count+1,LI->filename); exit(1); } last -> log[last -> log_count] = L1; last -> log_count++; if (L1.buffer_len != fwrite(L1.buffer,1,L1.buffer_len,LI->file)) { fprintf(stderr, "%s: write error (file %s)\n", program_name,LI->filename); fclose(LI->file); exit (1); /* FAILURE */ } putc('\n',LI->file); } free(fulltrgname); free(relname); } free(entryname); free(fullname); } } closedir(handle); } #else static void copy_dir(src,trg, char *rel,LI,last,register_module) char *src; char *trg; char *rel; struct log_instance *LI; struct log_entries * last; char *register_module; { char * x = strrchr(trg,'/'); int w; int pid; S__ status; if (!x) { fprintf(stderr,"%s: No / on path: %s\n", program_name,trg); exit(1); /* FAILURE */ } fflush(stdout); pid = fork(); if (-1 == pid) { fprintf(stderr,"%s: fork failed\n", program_name); exit(1); /* FAILURE */ } if (0 == pid) { /* because this is fork()ed, this have on own address space, and trg on parent is NOT affected... */ *x = '\0'; fprintf(stdout, "%s: Copying %s to %s(/%s) with %s -r\n", program_name,src,trg,x+1,ELMREGISTER_CP); fflush(stdout); execlp(ELMREGISTER_CP,ELMREGISTER_CP,"-r", src,trg,NULL); fprintf(stderr, "%s: Failed to EXECute %s\n",program_name,ELMREGISTER_CP); fflush(stderr); _exit(127); } while ((w = #ifdef HASWAITPID waitpid(pid,&status,0) #else wait(status) #endif ) != pid) if (w == -1 && errno != EINTR) break; if (w != pid || status != 0) { fprintf(stderr, "%s: Failed to copy %s to %s (with using %s)\n", program_name,src,trg,ELMREGISTER_CP); exit(1); /* FAILURE */ } } #endif /* DIROPS */ static void make_argcopy P_((char *arg, int arg_len, char * stage_subdir, char *register_module)); static void make_argcopy(arg,arg_len, stage_subdir, register_module) char *arg; int arg_len; char * stage_subdir; char *register_module; { struct stat X; char bufferz[256]; int p; int n; int R; char *y; char * source_f = NULL; char * source_r = NULL; char * target_f = NULL; char * target_r = NULL; if (arg_len >= 256) { fprintf(stderr, "%s: Argument too long: %s\n", program_name,arg); return; /* FAILURE */ } strcpy(bufferz,arg+1); if (bufferz[arg_len-2] != '}') { fprintf(stderr, "%s: OOPS %s\n", program_name, bufferz); exit(1); } bufferz[arg_len-2] = '\0'; R = stat(bufferz,&X); p = split_file(bufferz, &source_f, &source_r); if ('T' == p) { /* if ARG is already on target on, just register it ... May also be directory */ if (0 != R) log_it(arg,source_r,"-", "-", 0444, register_module); else log_it(arg,source_r,"-", "-", X.st_mode & 0777, register_module); free(source_r); free(source_f); return; } if (0 != R) { fprintf(stderr, "%s: Argument %s (filename %s) does not exists?\n", program_name,arg, bufferz); exit(1); } if ('/' != stage_dir[0]) { fprintf(stderr, "%s: stage dir %s does not have absolute\n", program_name,stage_dir); exit(1); } n = strlen(stage_dir) + arg_len; if (stage_subdir) { n += strlen(stage_subdir) + 1; } target_r = malloc(n); if (!target_r) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,n); exit(1); /* FAILURE */ } strcpy(target_r,stage_dir+1); strcat(target_r,"/"); if (stage_subdir) { char * Y; int n1; strcat(target_r,stage_subdir); n1 = strlen(installer_root) + strlen(target_r) + 3; Y = malloc(n1); if (!Y) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,n1); exit(1); /* FAILURE */ } strcpy(Y,installer_root); strcat(Y,"/"); strcat(Y,target_r); if (0 == mkdir(Y,0755)) { fprintf(stdout, "%s: Directory %s created\n", program_name,Y); /* HACK -- Do not use letter 'M', because it can break handling of * stored argument list */ log_it(IMPARGDIR,target_r,"-", "-", 0755, register_module); } else if (errno != EEXIST) { fprintf(stderr, "%s: Failed to create %s directory\n", program_name,Y); exit(1); } free(Y); strcat(target_r,"/"); } y = strrchr(bufferz,'/'); if (y) strcat(target_r,y+1); else strcat(target_r,bufferz); n = strlen(installer_root) + strlen(target_r) + 3; target_f = malloc(n); if (!target_f) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,n); exit(1); /* FAILURE */ } strcpy(target_f,installer_root); strcat(target_f,"/"); strcat(target_f,target_r); if ( #ifdef S_ISDIR S_ISDIR(X.st_mode) #else S_IFDIR == (buf.st_mode & S_IFMT) #endif ) { copy_dir(bufferz,target_f,target_r,NULL,NULL,register_module); log_it(arg,target_r,"-", "-", X.st_mode & 0777, register_module); } else { /* Just normal file */ if (0 != install_file(source_f,target_f, (uid_t)-1, (gid_t)-1, X.st_mode & 0777)) { fprintf(stderr, "%s: Install %s -> %s failed\n", program_name, source_r,target_r); exit(1); /* FAILURE */ } log_it(arg,target_r,"-", "-", X.st_mode & 0777, register_module); } free(source_r); free(source_f); free(target_r); free(target_f); } static int command P_((int argc, char *argv[], int x)); static int command(argc, argv, x) int argc; char *argv[]; int x; { int fd; struct stat X; char * cmd; if (!register_pipe) { fprintf(stderr,"%s: $ELM_INSTALLER is missing\n", argv[0]); return 1; /* FAILURE */ } if (!installer_root) { fprintf(stderr,"%s: $ELM_ROOT is missing\n", argv[0]); return 1; /* FAILURE */ } fd = atoi(register_pipe); if (fd < 1) { fprintf(stderr,"%s: $ELM_INSTALLER=%s invalid\n", argv[0],register_pipe); return 1; /* FAILURE */ } if (fstat(fd,&X) < 0) { fprintf(stderr,"%s: $ELM_INSTALLER=%s invalid\n", argv[0],register_pipe); return 1; /* FAILURE */ } register_fd = fd; if (stat(installer_root,&X) < 0) { fprintf(stderr,"%s: $ELM_ROOT=%s invalid\n", argv[0],installer_root); return 1; /* FAILURE */ } if ( #ifdef S_ISDIR ! S_ISDIR(X.st_mode) #else S_IFDIR != (buf.st_mode & S_IFMT) #endif ) { fprintf(stderr,"%s: $ELM_ROOT=%s invalid (not a directory)\n", argv[0],installer_root); return 1; /* FAILURE */ } while (x < argc && '-' == argv[x][0]) { if (x < argc -1 && 0 == strcmp("-R", argv[x])) { int l; rel_path = argv[x+1]; x += 2; l = strlen(rel_path); if (l > 0 && '/' != rel_path[l-1]) { char * X = malloc(l+2); if (!X) { fprintf(stderr,"%s: malloc %d bytes failed\n", argv[0],l+2); return 1; /* FAILURE */ } strncpy(X,rel_path,l+2); X[l] = '/'; fprintf(stdout,"%s: Adding / to -R %s: %s\n", argv[0],rel_path,X); rel_path = X; } } else if (x < argc -1 && 0 == strcmp("-M", argv[x])) { register_module = argv[x+1]; x += 2; } else { break; } } /* COPY mode ?? */ if (x < argc && 0 == strcmp("rm", argv[x])) { char buffer[ MAX_PIPE_LOG]; char *ptr; int j; char * translated [MAX_ARGS+1]; char * relative [MAX_ARGS+1]; int i; int L = 4; x++; if (argc - x >= MAX_ARGS) { fprintf(stderr, "%s: %s too many arguments\n", argv[0], argv[x-1]); return 1; /* FAILURE */ } i = 0; for (j = x; j < argc; j++) { if ('T' != split_file(argv[j],& translated[i], & relative[i])) { fprintf(stderr, "%s: file %s does not look like remove target\n", argv[0],argv[x]); return 1; /* FAILURE */ } i++; L += strlen(argv[j]) +1; } translated[i] = NULL; relative[i] = NULL; if (L > MAX_PIPE_LOG-2) { fprintf(stderr,"%s: Can't register command, string too long: %d\n", program_name,L); return 1; /* FAILURE */ } for (j = 0; j < i; j++) { if (0 == unlink(translated[j])) { fprintf(stdout, "%s: File %s removed\n", program_name,translated[j]); } } ptr = buffer; if (register_module) { int l = strlen(register_module); add_to_buffer(buffer, sizeof buffer,&ptr,"m",1); add_to_buffer(buffer, sizeof buffer,&ptr,register_module,l); } add_to_buffer(buffer, sizeof buffer,&ptr,"R",1); for (j = 0; j < i; j++) { int l = strlen(relative[j]); add_to_buffer(buffer, sizeof buffer,&ptr,relative[j],l); } *ptr++ = '\n'; /* Terminating NL on line */ L = ptr - buffer; if (L > MAX_PIPE_LOG-2) { fprintf(stderr,"%s: Can't register command, string too long: %d\n", program_name,L); return 1; /* FAILURE */ } /* We have better to able write whole string at ONCE, or otherwise two different writes from different processes are mixed on pipe ... (ie. if paraller make) */ write_once(register_fd,buffer,L); } else if (x < argc && 0 == strcmp("link", argv[x])) { char buffer[ MAX_PIPE_LOG]; char *ptr; char * translated [2]; char * relative [2]; char * tempname; int L = 4; int i,j; int Exit_it = 0; x++; if (argc - x != 2) { fprintf(stderr, "%s: %s: 2 arguments required\n", argv[0], argv[x-1]); return 1; /* FAILURE */ } i = 0; for (j = x; j < argc; j++) { if ('T' != split_file(argv[j],& translated[i], & relative[i])) { fprintf(stderr, "%s: file %s does not look like link target\n", argv[0],argv[x]); return 1; /* FAILURE */ } i++; L += strlen(argv[j]) +1; } if (L > MAX_PIPE_LOG-2) { fprintf(stderr,"%s: Can't register command, string too long: %d\n", program_name,L); return 1; /* FAILURE */ } tempname = gen_tempname(translated[1]); if (0 == unlink(tempname)) { fprintf(stderr,"%s: %s unlinked\n",program_name,tempname); } if (-1 == link(translated[0],tempname)) { fprintf(stderr, "%s: Failed to link %s to %s\n", program_name,translated[0],tempname); Exit_it = 1; goto fail3; } if (-1 == rename(tempname,translated[1])) { fprintf(stderr, "%s: Failed to replace %s\n", program_name,translated[1]); Exit_it = 1; goto fail3; } fprintf(stdout,"%s: Link %s == %s installed\n",program_name,translated[1],translated[0]); ptr = buffer; if (register_module) { int l = strlen(register_module); add_to_buffer(buffer, sizeof buffer,&ptr,"m",1); add_to_buffer(buffer, sizeof buffer,&ptr,register_module,l); } add_to_buffer(buffer, sizeof buffer,&ptr,"L",1); for (j = 0; j < i; j++) { int l = strlen(relative[j]); add_to_buffer(buffer, sizeof buffer,&ptr,relative[j],l); } *ptr++ = '\n'; /* Terminating NL on line */ L = ptr - buffer; if (L > MAX_PIPE_LOG-2) { fprintf(stderr,"%s: Can't register command, string too long: %d\n", program_name,L); return 1; /* FAILURE */ } /* We have better to able write whole string at ONCE, or otherwise two different writes from different processes are mixed on pipe ... (ie. if paraller make) */ write_once(register_fd,buffer,L); fail3: free(tempname); for (i =0; i < 2; i++) { free(translated[i]); free(relative[i]); } if (Exit_it) return Exit_it; /* FAILURE */ } else if (x < argc && (cmd = argv[x]) && ( 0 == strcmp("copy", argv[x]) || 0 == strcmp("copydoc", argv[x]) || 0 == strcmp("mkdir", argv[x]) )) { uid_t id_user = (uid_t)-1; gid_t id_group = (gid_t)-1; char * s_user = "-"; char * s_group = "-"; mode_t f_mode = 0; /* Use mode of source file */ x++; while (x < argc && '-' == argv[x][0]) { if (0 == strcmp(argv[x],"-o")) { struct passwd * p; if ((uid_t)-1 != id_user) { fprintf(stderr, "%s: Duplicate -o option\n", argv[0]); return 1; /* FAILURE */ } if (x+1 >= argc) { fprintf(stderr,"%s: Missing user after -o option\n", argv[0]); return 1; /* FAILURE */ } p = getpwnam(argv[x+1]); if (!p) { fprintf(stderr, "%s: -o option: user %s do not found\n", argv[0], argv[x+1]); return 1; /* FAILURE */ } id_user = p->pw_uid; s_user = argv[x+1]; if ((gid_t)-1 == id_group) id_group = p->pw_gid; x += 2; } else if (0 == strcmp(argv[x],"-g")) { struct group *g; if (x+1 >= argc) { fprintf(stderr, "%s: Missing group after -g option\n", argv[0]); return 1; /* FAILURE */ } g = getgrnam(argv[x+1]); if (!g) { fprintf(stderr, "%s: -g option: group %s do not found\n", argv[0], argv[x+1]); return 1; /* FAILURE */ } id_group = g->gr_gid; s_group = argv[x+1]; x += 2; } else if (0 == strcmp(argv[x],"-m")) { char * ptr; if (x+1 >= argc) { fprintf(stderr, "%s: Missing octal mode after -m option\n", argv[0]); return 1; /* FAILURE */ } f_mode = strtol(argv[x+1],&ptr,8); if (*ptr != '\0') { fprintf(stderr, "%s: -m option: bad octal mode %s (character %c) \n", argv[0], argv[x+1],*ptr); return 1; /* FAILURE */ } x += 2; } else { fprintf(stderr, "%s: %s option unknown\n", argv[0],argv[x]); return 1; /* FAILURE */ } } if (0 == strcmp(cmd,"mkdir")) { char * target_f = NULL; char * target_r = NULL; if ('T' != split_file(argv[x],&target_f,&target_r)) { fprintf(stderr, "%s: directory %s does not look like install target\n", argv[0],argv[x]); return 1; /* FAILURE */ } x++; if (x < argc) { fprintf(stderr, "%s: Too many arguments\n",argv[0]); return 1; /* FAILURE */ } if (0 == f_mode) f_mode = 0755; make_package_dir(target_f,installer_root); if (0 == mkdir(target_f,f_mode)) { int r = 0; if (id_user != (uid_t)-1 || id_group != (gid_t)-1) { r = chown(target_f,id_user,id_group); } fprintf(stdout, "%s: Directory %s created%s\n", program_name,target_f, r == -1 ? " (failed to set owner)" : ""); } else if (errno != EEXIST) { fprintf(stderr, "%s: Failed to create %s directory\n", program_name,target_f); return 1; /* FAILURE */ } log_it("M",target_r,s_user, s_group, f_mode, register_module); free(target_r); free(target_f); } else { struct stat X; char * source_f = NULL; char * source_r = NULL; char * target_f = NULL; char * target_r = NULL; if (x >= argc) { fprintf(stderr, "%s: source file not given\n",argv[0]); return 1; /* FAILURE */ } if ('S' != split_file(argv[x],&source_f,&source_r)) { fprintf(stderr, "%s: file %s does not look like install source\n", argv[0],argv[x]); return 1; /* FAILURE */ } x++; if ('T' != split_file(argv[x],&target_f,&target_r)) { fprintf(stderr, "%s: file %s does not look like install target\n", argv[0],argv[x]); return 1; /* FAILURE */ } x++; if (x < argc) { fprintf(stderr, "%s: Too many arguments\n",argv[0]); return 1; /* FAILURE */ } if (0 != stat(source_f,&X)) { fprintf(stderr, "%s: File %s does not exists?\n", program_name,source_f); return 1; /* FAILURE */ } if ( #ifdef S_ISDIR S_ISDIR(X.st_mode) #else S_IFDIR == (buf.st_mode & S_IFMT) #endif ) { fprintf(stderr, "%s: %s is directory\n", program_name,source_f); return 1; /* FAILURE */ } if (0 == f_mode) f_mode = X.st_mode & 0777; if (f_mode > 07777) { fprintf(stderr, "%s: file mode %05o illegal\n", argv[0], f_mode); return 1; /* FAILURE */ } if (0 != install_file(source_f,target_f, id_user, id_group, f_mode)) { fprintf(stderr, "%s: Install %s -> %s failed\n", argv[0], source_r,target_r); return 1; /* FAILURE */ } if (0 == strcmp("copydoc",cmd)) log_it("d",target_r,s_user, s_group, f_mode, register_module); else log_it("F",target_r,s_user, s_group, f_mode, register_module); free(source_r); free(source_f); free(target_r); free(target_f); } } else { int j; /* Execute program ( actually delay executing )*/ char buffer[ MAX_PIPE_LOG]; char *ptr; char * stage_subdir = NULL; int L = 4; if (x < argc -1 && 0 == strcmp("-s", argv[x])) { int l; stage_subdir = argv[x+1]; x += 2; } if (argc - x >= MAX_ARGS) { fprintf(stderr, "%s: %s too many arguments\n", argv[0], argv[x]); return 1; /* FAILURE */ } for (j = x; j < argc; j++) { int z; if ('{' == argv[j][0] && (z = strlen(argv[j])) && '}' == argv[j][z-1]) { make_argcopy(argv[j],z, stage_subdir,register_module); } L += strlen(argv[j]) +1; } if (L > MAX_PIPE_LOG-2) { fprintf(stderr,"%s: Can't register command, string too long: %d\n", program_name,L); return 1; /* FAILURE */ } ptr = buffer; if (register_module) { int l = strlen(register_module); add_to_buffer(buffer, sizeof buffer,&ptr,"m",1); add_to_buffer(buffer, sizeof buffer,&ptr,register_module,l); } add_to_buffer(buffer, sizeof buffer,&ptr,"E",1); for (j = x; j < argc; j++) { int l = strlen(argv[j]); add_to_buffer(buffer, sizeof buffer,&ptr,argv[j],l); } *ptr++ = '\n'; /* Terminating NL on line */ L = ptr - buffer; if (L > MAX_PIPE_LOG-2) { fprintf(stderr,"%s: Can't register command, string too long: %d\n", program_name,L); return 1; /* FAILURE */ } /* We have better to able write whole string at ONCE, or otherwise two different writes from different processes are mixed on pipe ... (ie. if paraller make) */ write_once(register_fd,buffer,L); } return 0; } static void pick_one P_((struct log_record * ptr, char **src, int L, uid_t *id_user, gid_t *id_group, int *mode, int *is_dir)); static void pick_one(ptr,src,L,id_user,id_group,mode,is_dir) struct log_record * ptr; char **src; int L; uid_t *id_user; gid_t *id_group; int *mode; int *is_dir; { struct passwd * p = NULL; struct group * g = NULL; struct stat X; if (!ptr->arg_ptrs || !ptr->arg_ptrs[0]) { fprintf(stderr, "%s: [pick_one] '%c' no arg 0 \n", program_name,ptr->command_letter); exit(1); /* FAILURE */ } *src = make_rooted(ptr,ptr->arg_ptrs[0],installer_root); if (ptr->user_ptr && 0 != strcmp(ptr->user_ptr,"-")) { p = getpwnam(ptr->user_ptr); if (!p) fprintf(stderr, "%s: [pick_one] '%c' User %s not found\n", program_name,ptr->command_letter, ptr->user_ptr); } if (ptr->group_ptr && 0 != strcmp(ptr->group_ptr,"-")) { g = getgrnam(ptr->group_ptr); if (!g) fprintf(stderr, "%s: [pick_one] '%c' Group %s not found\n", program_name,ptr->command_letter, ptr->group_ptr); } if (stat(*src,&X) < 0) { fprintf(stderr, "%s: (note) %s : %s not accessible\n", program_name, ptr->arg_ptrs[0],*src); *is_dir = -1; *id_user = (uid_t)-1; *id_group = (gid_t)-1; *mode = 0555; return; } if (p) *id_user = p->pw_uid; else *id_user = X.st_uid; if (g) *id_group = g->gr_gid; else if (p) *id_group = p->pw_gid; else *id_group = X.st_gid; if (ptr->mode_ptr && 0 != strcmp(ptr->mode_ptr,"-") && 0 != strcmp(ptr->mode_ptr,"0")) { char * x; *mode = strtol(ptr->mode_ptr,&x,8); if (*x || 0 == *mode) goto failmode; } else { failmode: *mode = X.st_mode & 0777; } /* if directory ... */ if ( #ifdef S_ISDIR S_ISDIR(X.st_mode) #else S_IFDIR == (buf.st_mode & S_IFMT) #endif ) { *is_dir = 1; } else { /* REGULAR */ *is_dir = 0; } } static char * make_absolute P_((struct log_record * ptr, char *rel)); static char * make_absolute(ptr,rel) struct log_record * ptr; char *rel; { int l = strlen(rel) + 2; char * translated = malloc(l); if (!translated) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,l); exit (1); /* FAILURE */ } if ('/' == rel[0]) { fprintf(stderr, "%s: entry '%c' -- Not relative? %s\n", program_name,ptr->command_letter,rel); translated[0] = '\0'; } else { translated[0] = '/'; translated[1] = '\0'; } strcat(translated,rel); return translated; } static int filter_record P_((struct log_record *record, char **module, int match_all)); static int filter_record(record,module,match_all) struct log_record *record; char **module; int match_all; { int i; if (module && module[0] && 0 == strcmp(module[0], "all")) return 1; if (! record->module_ptr) { if (!module) return 1; return 0; } if (match_all && 0 == strcmp(record->module_ptr,"all")) return 1; if (!module) return 0; for (i = 0; module[i]; i++) { if (0 == strcmp(record->module_ptr, module[i])) return 1; } return 0; } static int copy_list P_((struct log_entries *entry, struct log_instance *source, struct log_instance *target, struct log_entries *last, char **module)); static int copy_list(entry,source,target,last, module) struct log_entries *entry; struct log_instance *source; struct log_instance *target; struct log_entries *last; char **module; { struct log_record * ptr; int L = strlen(installer_root); for (ptr = entry->log; ptr < entry->log + entry->log_count; ptr++) { char * src = NULL; uid_t id_user = (uid_t)-1; gid_t id_group = (gid_t)-1; int mode = 0555; int is_dir = 0; if (! filter_record(ptr,module,1)) continue; switch (ptr->command_letter) { char *trg; case '\0': /* ENTRY DELETED */ break; case 'E': /* We do not execute on copy ... */ break; case 'R': { int i; for (i = 0; ptr->arg_ptrs[i] && i < MAX_ARGS; i++) { char * translated = make_absolute(ptr,ptr->arg_ptrs[i]); if (0 == unlink(translated)) { fprintf(stdout, "%s: File %s removed\n", program_name,translated); } free(translated); } move_record(target,last,ptr); } break; case 's': /* Copying of directory does this ... */ break; case '{': /* MUST BE handled on execute ... */ break; case 'C': fprintf(stdout, "%s: Config file %s (%s) not copied\n", program_name,ptr->arg_ptrs[0],src); break; case 'L': /* Handled now on execute ... */ break; case 'M': pick_one(ptr,&src,L,&id_user,&id_group,&mode,&is_dir); trg = src + L; if (is_dir < 0) { fprintf(stderr, "%s: 'Source' directory %s does not exists\n", program_name, src); } else if (!is_dir) { fprintf(stderr, "%s: [copy_list] '%c' %s is NOT directory\n", program_name,ptr->command_letter, src); free(src); return 1; /* FAILURE */ } if (0 == mkdir(trg,mode)) { int r = chown(trg,id_user,id_group); fprintf(r == -1 ? stderr : stdout, "%s: Directory %s created%s\n", program_name,trg, r == -1 ? " (failed to set owner)" : ""); move_record(target,last,ptr); } else if (errno != EEXIST) { fprintf(stderr, "%s: Failed to create %s directory\n", program_name,trg); free(src); return 1; /* FAILURE */ } break; case 'F': case 'd': pick_one(ptr,&src,L,&id_user,&id_group,&mode,&is_dir); trg = src + L; if (is_dir < 0) { fprintf(stderr, "%s: [copy_list] '%c' Source file %s does not exists\n", program_name,ptr->command_letter, src); free(src); return 1; /* FAILURE */ } else if (is_dir) { fprintf(stderr, "%s: [copy_list] '%c' %s is directory\n", program_name,ptr->command_letter, src); free(src); return 1; /* FAILURE */ } if (0 != install_file(src,trg,id_user,id_group,mode)) { fprintf(stderr, "%s: [copy_list] '%c' Failed to install %s : %s -> %s\n", program_name,ptr->command_letter, ptr->arg_ptrs[0],src,trg); free(src); return 1; /* FAILURE */ } move_record(target,last,ptr); break; default: fprintf(stderr, "%s: [copy_list] Bad command letter: %c \n", program_name,ptr->command_letter); return 1; } if (src) free(src); } return 0; } static struct log_record * on_other_module P_((struct log_instance *LI, char *entry, char **module)); static struct log_record * on_other_module(LI,entry,module) struct log_instance *LI; char *entry; char **module; { int i; for (i = 0; i < LI->entries_count; i++) { struct log_record * ptr; for (ptr = LI->entries[i].log; ptr < LI->entries[i].log + LI->entries[i].log_count; ptr++) { /* Check if entry is mentioned on filtered module */ if (!filter_record(ptr,module,1)) { switch (ptr->command_letter) { case '\0': /* ENTRY DELETED */ break; case '{': case 's': case 'F': case 'd': case 'C': case 'M': if (ptr->arg_ptrs && ptr->arg_ptrs[0] && 0 == strcmp(ptr->arg_ptrs[0],entry)) return ptr; break; case 'L': /* second argument is new name */ if (ptr->arg_ptrs && ptr->arg_ptrs[1] && 0 == strcmp(ptr->arg_ptrs[1],entry)) return ptr; break; case 'E': /* execute ... */ break; case 'R': /* remove ... */ break; default: fprintf(stderr, "%s: [on_other_module] Bad command letter: %c \n", program_name,ptr->command_letter); } } } } return NULL; } static int on_current P_((struct log_instance *LI,char *entry)); static int on_current(LI,entry) struct log_instance *LI; char *entry; { int i; #if ANSI_C char my_version[] = "[ELM" VERSION " " PATCHLEVEL "]"; #else char my_version[40]; sprintf(my_version,"[ELM %s %s]",VERSION,PATCHLEVEL); #endif for (i = 0; i < LI->entries_count; i++) { if (0 == strcmp(LI->entries[i].version, my_version)) { struct log_record * ptr; for (ptr = LI->entries[i].log; ptr < LI->entries[i].log + LI->entries[i].log_count; ptr++) { switch (ptr->command_letter) { case '\0': /* ENTRY DELETED */ break; case '{': case 's': case 'F': case 'd': case 'C': case 'M': if (ptr->arg_ptrs && ptr->arg_ptrs[0] && 0 == strcmp(ptr->arg_ptrs[0],entry)) return 1; break; case 'L': /* second argument is new name */ if (ptr->arg_ptrs && ptr->arg_ptrs[1] && 0 == strcmp(ptr->arg_ptrs[1],entry)) return 1; break; case 'E': /* execute ... */ break; case 'R': /* remove ... */ break; default: fprintf(stderr, "%s: [on_current] Bad command letter: %c \n", program_name,ptr->command_letter); } } } } return 0; } static void trim_list P_((struct log_entries *entry, struct log_instance *source, char **module)); static void trim_list(entry,source,module) struct log_entries *entry; struct log_instance *source; char **module; { struct log_record * ptr; for (ptr = entry->log; ptr < entry->log + entry->log_count; ptr++) { if (! filter_record(ptr,module,0)) continue; switch (ptr->command_letter) { case '\0': /* ENTRY DELETED */ break; case 'L': /* second arg is new name */ if (ptr->arg_ptrs && ptr->arg_ptrs[1]) { if (!on_current(source,ptr->arg_ptrs[1])) { fprintf(stdout, "%s: (%s) Keeping link %s from old version (was %s)\n", program_name,source->filename,ptr->arg_ptrs[1], ptr->arg_ptrs[0] ); continue; } } goto trim; case 's': if (ptr->arg_ptrs && ptr->arg_ptrs[0]) { if (!on_current(source,ptr->arg_ptrs[0])) { fprintf(stdout, "%s: (%s) Stage file %s from old version found -- incomplete install?\n", program_name,source->filename,ptr->arg_ptrs[0]); continue; } } goto trim; case 'M': case '{': case 'F': case 'd': case 'C': if (ptr->arg_ptrs && ptr->arg_ptrs[0]) { if (!on_current(source,ptr->arg_ptrs[0])) { if ('M' != ptr->command_letter) fprintf(stdout, "%s: (%s) Keeping file %s from old version\n", program_name,source->filename,ptr->arg_ptrs[0]); continue; } } /* FALLTHRU */ case 'R': /* Trim delete ... */ case 'E': /* Trim execute ... */ trim: if (ptr->buffer) { free(ptr->buffer); ptr->buffer = NULL; } if (ptr->arg_ptrs) { free(ptr->arg_ptrs); ptr->arg_ptrs = NULL; } ptr->command_letter = '\0'; /* ENTRY DELETED */ break; default: fprintf(stderr, "%s: [trim_list] Bad command letter: %c \n", program_name,ptr->command_letter); } } } static int unstage_list P_((struct log_entries *entry, struct log_instance *source, char **module)); static int unstage_list(entry,source,module) struct log_entries *entry; struct log_instance *source; char **module; { int exit_stat = 0; struct log_record * ptr; int X = strlen(stage_dir); for (ptr = entry->log; ptr < entry->log + entry->log_count; ptr++) { int ok = 0; if (! filter_record(ptr,module,0)) continue; switch (ptr->command_letter) { case '\0': /* ENTRY DELETED */ break; case 'E': ok = 1; /* JUST CLEAN */ break; case 's': case '{': if (ptr->arg_ptrs && ptr->arg_ptrs[0]) { char *ab = make_absolute(ptr,ptr->arg_ptrs[0]); if (0 == strncmp(stage_dir,ab,X)) { struct log_record *other = on_other_module(source,ptr->arg_ptrs[0],module); struct stat X; if (stat(ab,&X) < 0) ok = 1; /* Assume that cleared */ else if ( #ifdef S_ISDIR S_ISDIR(X.st_mode) #else S_IFDIR == (buf.st_mode & S_IFMT) #endif ) { if (0 == rmdir(ab)) { fprintf(stdout, "%s: Stage directory %s uninstalled\n", program_name,ab); ok = 1; } } else { if (other) { fprintf(stdout, "%s: Keeping stage file %s, used by %s package/module\n", program_name,ab, other->module_ptr ? other->module_ptr : "main"); ok = 1; /* Remove double reference */ } else if (0 == unlink(ab)) { fprintf(stdout, "%s: Stage file %s uninstalled\n", program_name,ab); ok = 1; } else { fprintf(stderr, "%s: Can't unlink %s\n", program_name,ab); exit_stat = 1; } } } else { fprintf(stdout, "%s: Ignoring entry %s -- not in stage area (%s)\n", program_name,ab,stage_dir); ok = 1; /* JUST CLEAN */ } free(ab); } break; } if (ok) { if (ptr->buffer) { free(ptr->buffer); ptr->buffer = NULL; } if (ptr->arg_ptrs) { free(ptr->arg_ptrs); ptr->arg_ptrs = NULL; } ptr->command_letter = '\0'; /* ENTRY DELETED */ } } return exit_stat; } static dev_t this_program_dev = 0; static ino_t this_program_ino = 0; static int this_program = 0; static int uninstall_list P_((struct log_entries *entry, struct log_instance *source, char **module)); static int uninstall_list(entry,source,module) struct log_entries *entry; struct log_instance *source; char **module; { int exit_stat = 0; struct log_record * ptr; int X = strlen(stage_dir); for (ptr = entry->log; ptr < entry->log + entry->log_count; ptr++) { int ok = 0; if (! filter_record(ptr,module,0)) continue; switch (ptr->command_letter) { case '\0': /* ENTRY DELETED */ break; case 'L': /* second arg is new name */ if (ptr->arg_ptrs && ptr->arg_ptrs[1]) { char *ab = make_absolute(ptr,ptr->arg_ptrs[1]); struct log_record *other = on_other_module(source,ptr->arg_ptrs[1],module); struct stat X; if (stat(ab,&X) < 0) { if (ENOENT == errno) ok = 1; else { fprintf(stderr, "%s: Can't stat %s\n", program_name,ab); exit_stat = 1; } } else if ( #ifdef S_ISLNK ! S_ISREG(X.st_mode) #else S_IFREG != (X.st_mode & S_IFMT) #endif ) { fprintf(stderr, "%s: Name %s is not regular file (link)\n", program_name,ab); } else if (other) { fprintf(stdout, "%s: Keeping link %s, used by %s package/module\n", program_name,ab, other->module_ptr ? other->module_ptr : "main"); ok = 1; /* Remove double reference */ } else if ((!module || !module[0] || 0 != strcmp(module[0],"all")) && (X.st_dev == this_program_dev && X.st_ino == this_program_ino || 0 == strcmp(program_name,ab))) { fprintf(stdout, "%s: Keeping link %s, is this program\n", program_name,ab); this_program++; } else if (0 == unlink(ab)) { fprintf(stdout, "%s: Link %s uninstalled\n", program_name,ab); ok = 1; } else if (ENOENT == errno) ok = 1; else { fprintf(stderr, "%s: Can't unlink %s\n", program_name,ab); exit_stat = 1; } free(ab); } break; case 'M': /* No failure if directory can't be uninstalled */ if (ptr->arg_ptrs && ptr->arg_ptrs[0]) { char *ab = make_absolute(ptr,ptr->arg_ptrs[0]); if (0 == rmdir(ab)) { fprintf(stdout, "%s: Directory %s uninstalled\n", program_name,ab); ok = 1; } else if (ENOENT == errno) ok = 1; free(ab); } break; case 'E': case 'R': ok = 1; /* JUST CLEAN */ break; case 'F': case 'd': case 's': /* also handled by unstage_list() */ if (ptr->arg_ptrs && ptr->arg_ptrs[0]) { char *ab = make_absolute(ptr,ptr->arg_ptrs[0]); struct log_record *other = on_other_module(source,ptr->arg_ptrs[0],module); struct stat X; if (stat(ab,&X) < 0) { if (ENOENT == errno) ok = 1; else { fprintf(stderr, "%s: Can't stat %s\n", program_name,ab); exit_stat = 1; } } else if ( #ifdef S_ISREG ! S_ISREG(X.st_mode) #else S_IFREG != (X.st_mode & S_IFMT) #endif ) { fprintf(stderr, "%s: Name %s is not regular file\n", program_name,ab); } else if (other) { fprintf(stdout, "%s: Keeping file %s, used by %s package/module\n", program_name,ab, other->module_ptr ? other->module_ptr : "main"); ok = 1; /* Remove double reference */ } else if ((!module || !module[0] || 0 != strcmp(module[0],"all")) && (X.st_dev == this_program_dev && X.st_ino == this_program_ino || 0 == strcmp(program_name,ab))) { fprintf(stdout, "%s: Keeping file %s, is this program\n", program_name,ab); this_program++; } else if (0 == unlink(ab)) { fprintf(stdout, "%s: File %s uninstalled\n", program_name,ab); ok = 1; } else if (ENOENT == errno) ok = 1; else { fprintf(stdout, "%s: Can't unlink %s\n", program_name,ab); exit_stat = 1; } free(ab); } break; case 'C': if (ptr->arg_ptrs && ptr->arg_ptrs[0]) { char *ab = make_absolute(ptr,ptr->arg_ptrs[0]); struct log_record *other = on_other_module(source,ptr->arg_ptrs[0],module); struct stat X; if (stat(ab,&X) < 0) { if (ENOENT == errno) ok = 1; else { fprintf(stderr, "%s: Can't stat %s\n", program_name,ab); exit_stat = 1; } } else if ( #ifdef S_ISREG ! S_ISREG(X.st_mode) #else S_IFREG != (X.st_mode & S_IFMT) #endif ) { fprintf(stderr, "%s: Name %s is not regular file\n", program_name,ab); } else if (other) { fprintf(stdout, "%s: Keeping config file %s, used by %s package/module\n", program_name,ab, other->module_ptr ? other->module_ptr : "main"); ok = 1; /* Remove double reference */ } else if (0 == unlink(ab)) { fprintf(stdout, "%s: Config file %s uninstalled\n", program_name,ab); ok = 1; } else if (ENOENT == errno) ok = 1; else { fprintf(stdout, "%s: Can't unlink %s\n", program_name,ab); exit_stat = 1; } free(ab); } break; case '{': /* SHOULD ALREADY BE HANDLED unstage_list() */ break; } if (ok) { if (ptr->buffer) { free(ptr->buffer); ptr->buffer = NULL; } if (ptr->arg_ptrs) { free(ptr->arg_ptrs); ptr->arg_ptrs = NULL; } ptr->command_letter = '\0'; /* ENTRY DELETED */ } } return exit_stat; } static int replay_list P_((struct log_entries *entry, struct log_instance *source, struct log_instance *target, struct log_entries * last, char **module)); static int replay_list(entry,source,target,last, module) struct log_entries *entry; struct log_instance *source; struct log_instance *target; struct log_entries * last; char **module; { struct log_record * ptr; struct log_record * LAST_ARG = NULL; int Exit_status = 0; int L = strlen(installer_root); int n; for (n = 0; n < entry->log_count; n++) { /* Log copy loop adds new entries to array so we can't just increment ptr */ ptr = & entry->log[n]; if (! filter_record(ptr,module,1)) { LAST_ARG = NULL; continue; } switch (ptr->command_letter) { case '\0': /* ENTRY DELETED */ break; case '{': if (!LAST_ARG) { LAST_ARG = ptr; } break; case 'F': case 'd': case 'C': case 'M': case 'R': LAST_ARG = NULL; break; case 'L': /* link */ { int Exit_it = 0; char * file1 = make_absolute(ptr,ptr->arg_ptrs[0]); char * file2 = make_absolute(ptr,ptr->arg_ptrs[1]); char * tempname = gen_tempname(file2); if (0 == unlink(tempname)) { fprintf(stderr,"%s: %s unlinked\n",program_name,tempname); } if (-1 == link(file1,tempname)) { fprintf(stderr, "%s: Failed to link %s to %s\n", program_name,file1,tempname); Exit_it = 1; goto fail3; } if (-1 == rename(tempname,file2)) { fprintf(stderr, "%s: Failed to replace %s\n", program_name,file2); Exit_it = 1; goto fail3; } fprintf(stdout,"%s: Link %s == %s installed\n",program_name,file2,file1); fail3: free(tempname); free(file1); free(file2); if (Exit_it) return Exit_it; /* FAILURE */ if (target != source) move_record(target,last,ptr); LAST_ARG = NULL; } break; case 's': /* NOT BREAK LAST_ARG -- is content of directory specified as arg */ break; case 'E': /* EXECUTE ... */ { char * translated [MAX_ARGS+1]; int i,j; int pid,pipefd; FILE *fd; int w; S__ status; for (i = 0; ptr->arg_ptrs[i] && i < MAX_ARGS; i++) { int z; if ('{' == ptr->arg_ptrs[i][0] && ( z = strlen(ptr->arg_ptrs[i])) && '}' == ptr->arg_ptrs[i][z-1]) { struct log_record *k; if (!LAST_ARG) { fprintf(stderr, "%s: [replay_list] No arguments stored... %s\n", program_name,ptr->arg_ptrs[i]); return 1; /* FAILURE */ } for (k = LAST_ARG; k < ptr; k++) { if ('{' == k->command_letter && k->command_ptr && 0 == strcmp(ptr->arg_ptrs[i], k->command_ptr)) break; } if (k == ptr) { fprintf(stderr, "%s: [replay_list] Argument %s not found\n", program_name,ptr->arg_ptrs[i]); return 1; /* FAILURE */ } if (source != target) { /* NEED COPY */ char * src = NULL; char * trg; uid_t id_user = (uid_t)-1; gid_t id_group = (gid_t)-1; int mode; int is_dir; pick_one(k,&src,L,&id_user,&id_group,&mode,&is_dir); trg = src + L; if (is_dir < 0) { /* Assumed to be target file */ } else if (is_dir) { copy_dir(src,trg,k->arg_ptrs[0],target,last, k->module_ptr); } else { if (0 != install_file(src,trg,id_user,id_group,mode)) { fprintf(stderr, "%s: [replay_list] '%c' Failed to install %s : %s -> %s\n", program_name,k->command_letter, k->arg_ptrs[0],src,trg); return 1; /* FAILURE */ } } move_record(target,last,k); translated[i] = strdup(trg); if (!translated[i]) { fprintf(stderr, "%s: [replay_list] strdup failed: %s \n", program_name,trg); Exit_status = 1; /* FAILURE */ goto fail; } free(src); } else { /* Just translate reference ... */ int l = strlen(k->arg_ptrs[0]) + 2; translated[i] = malloc(l); if (!translated[i]) { fprintf(stderr, "%s: [replay_list] malloc %d bytes failed\n", program_name,l); Exit_status = 1; /* FAILURE */ goto fail; } strcpy(translated[i],"/"); strcat(translated[i],k->arg_ptrs[0]); } } else { translated[i] = strdup(ptr->arg_ptrs[i]); if (!translated[i]) { fprintf(stderr, "%s: [replay_list] strdup failed: %s \n", program_name,ptr->arg_ptrs[i]); Exit_status = 1; goto fail; } } } translated[i] = NULL; fprintf(stdout, "%s: Executing",program_name); for (j = 0; j < i; j++) fprintf(stdout," %s", ptr->arg_ptrs[j]); fprintf(stdout, "\n%s: As",program_name); for (j = 0; j < i; j++) fprintf(stdout," %s", translated[j]); fprintf(stdout,"\n"); fflush(stdout); pipefd = create_pipe(i,translated,0,&pid,"/", ptr->module_ptr); fd = fdopen(pipefd,"r"); if (!fd) { fprintf(stderr,"%s: fdopen() failed\n",program_name); close(pipefd); Exit_status = 1; /* FAILURE */ goto fail; } log_copy_loop(fd,target,last); fclose(fd); while ((w = #ifdef HASWAITPID waitpid(pid,&status,0) #else wait(status) #endif ) != pid) if (w == -1 && errno != EINTR) break; if (w != pid || status != 0) { fprintf(stderr, "%s: Failed to run %s\n", program_name,translated[0]); Exit_status = 1; /* FAILURE */ } fail: for (; i >= 0; i--) { if (translated[i]) { free(translated[i]); translated[i] = NULL; } } if (Exit_status) return Exit_status; } LAST_ARG = NULL; break; default: fprintf(stderr, "%s: [replay_list] Bad command letter: %c \n", program_name,ptr->command_letter); return 1; } } /* Fixing permissions */ for (ptr = entry->log; ptr < entry->log + entry->log_count; ptr++) { if (! filter_record(ptr,module,1)) continue; switch (ptr->command_letter) { char *X; struct passwd * p; struct group * g; struct stat X1; int mode; uid_t user; gid_t group; case 'M': case 'F': case 'd': case 'C': p = NULL; g = NULL; mode = -1; user = (uid_t)-1; group = (gid_t)-1; if (!ptr->arg_ptrs || !ptr->arg_ptrs[0]) { fprintf(stderr, "%s: [replay_list] '%c' no arg 0 \n", program_name,ptr->command_letter); exit(1); /* FAILURE */ } X = make_rooted(ptr,ptr->arg_ptrs[0],"/"); if (ptr->user_ptr && 0 != strcmp(ptr->user_ptr,"-")) { p = getpwnam(ptr->user_ptr); if (!p) fprintf(stderr, "%s: [replay_list] '%c' User %s not found\n", program_name,ptr->command_letter, ptr->user_ptr); else { user = p->pw_uid; group = p->pw_gid; } } if (ptr->group_ptr && 0 != strcmp(ptr->group_ptr,"-")) { g = getgrnam(ptr->group_ptr); if (!g) fprintf(stderr, "%s: [replay_list] '%c' Group %s not found\n", program_name,ptr->command_letter, ptr->group_ptr); else group = g->gr_gid; } if (ptr->mode_ptr && 0 != strcmp(ptr->mode_ptr,"-") && 0 != strcmp(ptr->mode_ptr,"0")) { char * x; mode = strtol(ptr->mode_ptr,&x,8); if (*x || 0 == mode) mode = -1; } if (stat(X,&X1) < 0) { fprintf(stderr, "%s: (note) %s : %s not accessible\n", program_name, ptr->arg_ptrs[0],X); Exit_status = 1; /* FAILURE */ goto failure1; } if ( #ifdef S_ISDIR S_ISDIR(X1.st_mode) #else S_IFDIR == (X1.st_mode & S_IFMT) #endif ) { if (ptr->command_letter != 'M') { fprintf(stderr, "%s: (note) %s : %s is directory when should not\n", program_name, ptr->arg_ptrs[0],X); Exit_status = 1; /* FAILURE */ goto failure1; } } else { if (ptr->command_letter == 'M') { fprintf(stderr, "%s: (note) %s : %s is not a directory\n", program_name, ptr->arg_ptrs[0],X); Exit_status = 1; /* FAILURE */ goto failure1; } } if (user != (uid_t)-1 || group != (gid_t)-1) { if (X1.st_uid != user || X1.st_gid != group) { if (-1 == chown(X,user,group)) { fprintf(stderr,"%s: Failed to set owner/group of %s\n", program_name,X); Exit_status = 1; /* FAILURE */ goto failure1; } } else { fprintf(stdout,"%s: Fixed owner/group of %s\n", program_name,X); } /* Recheck mode */ if (stat(X,&X1) < 0) { fprintf(stderr, "%s: (note) %s : %s not accessible\n", program_name, ptr->arg_ptrs[0],X); Exit_status = 1; /* FAILURE */ goto failure1; } } if (mode > 0) { if ((X1.st_mode & 0777) != mode) { if (-1 == chmod(X,mode)) { fprintf(stderr,"%s: Failed to set mode of %s\n", program_name,X); Exit_status = 1; /* FAILURE */ } else { fprintf(stdout,"%s: Mode of %s fixed\n", program_name,X); } } } failure1: free(X); X = 0; break; default: break; } } return Exit_status; } static int replay P_((int argc, char *argv[], int x)); static int replay(argc, argv, x) int argc; char *argv[]; int x; { struct stat X; struct log_instance * target = NULL; int i; int r = 0; struct log_instance LI_source; struct log_instance LI_target; struct log_entries * last = NULL; char **module_filter = NULL; int module_count = 0; int remove_count; #if ANSI_C char my_version[] = "[ELM" VERSION " " PATCHLEVEL "]"; #else char my_version[40]; sprintf(my_version,"[ELM %s %s]",VERSION,PATCHLEVEL); #endif clear_log_instance(&LI_source); clear_log_instance(&LI_target); installer_root = "/"; while (x < argc && '-' == argv[x][0]) { if (x < argc -1 && 0 == strcmp("-F", argv[x])) { filelist = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-R", argv[x])) { installer_root = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-M", argv[x])) { module_filter = realloc(module_filter, (module_count+2) * sizeof (module_filter[0])); if (! module_filter) { fprintf(stderr, "%s: Failed to realloc -M option\n", program_name); exit(1); } module_filter[module_count++] = argv[x+1]; module_filter[module_count] = NULL; x += 2; } else { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } } if (stat(installer_root,&X) < 0) { fprintf(stderr,"%s: -R %s invalid\n", argv[0],installer_root); return 1; /* FAILURE */ } if ( #ifdef S_ISDIR ! S_ISDIR(X.st_mode) #else S_IFDIR != (buf.st_mode & S_IFMT) #endif ) { fprintf(stderr,"%s: -R %s invalid (not a directory)\n", argv[0],installer_root); return 1; /* FAILURE */ } if (x < argc) { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } LI_source.filename = filelist; if (0 != strcmp(installer_root,"/")) { int l = strlen(filelist) + strlen(installer_root) +2; LI_source.filename = malloc(l); if (!LI_source.filename) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,l); return 1; /* FAILURE */ } sprintf(LI_source.filename,"%s%s",installer_root,filelist); } LI_source.file = fopen(LI_source.filename,"r+"); if (!LI_source.file) { fprintf(stderr, "%s: Failed to open file %s on %s: %s\n", program_name,filelist,installer_root,LI_source.filename); return 1; /* FAILURE */ } add_entries(&LI_source); if (LI_source.entries_count < 1 || 0 != strcmp(LI_source.entries[LI_source.entries_count-1].version, my_version)) { fprintf(stderr, "%s: Last version on file %s on %s (file %s) is not %s\n", program_name,filelist,installer_root, LI_source.filename, my_version); fclose(LI_source.file); return 1; /* FAILURE */ } if (0 != strcmp(installer_root,"/")) { int i; int t; fprintf (stdout, "%s: Copying ELM files from %s to / \n", program_name,installer_root); LI_target.filename = filelist; if (0 == mkdir(ETCHOME,0755)) { fprintf(stdout, "%s: Directory %s created\n", program_name,ETCHOME); } else if (errno != EEXIST) { fprintf(stderr, "%s: Failed to create %s directory\n", program_name,ETCHOME); return 1; /* FAILURE */ } t = open(LI_target.filename,O_RDWR|O_CREAT,0644); if (t < 0) { fprintf(stderr, "%s: Failed to open file %s on target (/): %s\n", program_name,filelist,LI_target.filename); fclose(LI_source.file); return 1; /* FAILURE */ } LI_target.file = fdopen(t,"r+"); if (!LI_target.file) { fprintf(stderr, "%s: Failed to fdopen file %s on target (/): %s\n", program_name,filelist,LI_target.filename); fclose(LI_source.file); close(t); return 1; /* FAILURE */ } add_entries(&LI_target); target = &LI_target; last = add_last(target); /* Copy files marked for current version ... * replay_list() will copy '{' files */ for (i = 0; i < LI_source.entries_count; i++) { if (0 == strcmp(LI_source.entries[i].version, my_version)) { r = copy_list(& LI_source.entries[i], &LI_source, &LI_target, last, module_filter); if (0 != r) goto fail; } else { fprintf(stderr, "%s: On source area (%s) have files for version %s -- NOT COPIED\n", program_name,installer_root, LI_source.entries[i].version); } } if (0 != fflush(LI_target.file)) { fprintf(stderr, "%s: Failed to write file %s on target (/): %s\n", program_name,filelist,LI_target.filename); fclose(LI_source.file); return 1; /* FAILURE */ } } else { target = & LI_source; last = & LI_source.entries[LI_source.entries_count-1]; } /* EXECUTE commands and fix permissions */ r = replay_list(&LI_source.entries[LI_source.entries_count-1], &LI_source,target,last, module_filter); /* Trim files marked for other versions ... LAST entry is current so not need handle it ... */ for (i = 0; i < target->entries_count-1; i++) { if (0 != strcmp(target->entries[i].version, my_version)) { trim_list(& target->entries[i], target, module_filter); } } remove_unlinked(target,"/",&remove_count); rewrite_list(target); if (EOF == fclose(target->file)) { fprintf(stderr, "%s: Write(?) failed on closing of file: %s\n", program_name,target->filename); return 1; /* FAILURE */ } fail: return r; } static int uninstall P_((int argc, char *argv[], int x)); static int uninstall(argc, argv, x) int argc; char *argv[]; int x; { int r = 0; struct log_instance LI; int remove_count; int i; char **module_filter = NULL; int module_count = 0; struct stat X; #if ANSI_C char my_version[] = "[ELM" VERSION " " PATCHLEVEL "]"; #else char my_version[40]; sprintf(my_version,"[ELM %s %s]",VERSION,PATCHLEVEL); #endif clear_log_instance(&LI); while (x < argc && '-' == argv[x][0]) { if (x < argc -1 && 0 == strcmp("-F", argv[x])) { filelist = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-M", argv[x])) { module_filter = realloc(module_filter, (module_count+2) * sizeof (module_filter[0])); if (! module_filter) { fprintf(stderr, "%s: Failed to realloc -M option\n", program_name); exit(1); } module_filter[module_count++] = argv[x+1]; module_filter[module_count] = NULL; x += 2; } else { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } } if (x < argc) { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } if (module_count != 1 || 0 != strcmp(module_filter[0],"all")) { if (stat(program_name,&X) < 0) { fprintf(stderr, "%s: Failed to stat this program name -- needed to avoid unistalling this program\n", program_name); r = 1; } else { this_program_dev = X.st_dev; this_program_ino = X.st_ino; } } LI.filename = filelist; LI.file = fopen(LI.filename,"r+"); if (!LI.file) { fprintf(stderr, "%s: Failed to open file %s\n", program_name,LI.filename); return 1; /* FAILURE */ } add_entries(&LI); if (LI.entries_count < 1 || 0 != strcmp(LI.entries[LI.entries_count-1].version, my_version)) { fprintf(stderr, "%s: Last version on file %s is not %s\n", program_name, LI.filename, my_version); r = 1; } remove_unlinked(&LI,"/",&remove_count); for (i = 0; i < LI.entries_count; i++) { if (0 != unstage_list(& LI.entries[i], &LI,module_filter)) r = 1; if (0 != uninstall_list(& LI.entries[i], &LI,module_filter)) r = 1; } rewrite_list(&LI); if (EOF == fclose(LI.file)) { fprintf(stderr, "%s: Write(?) failed on closing of file: %s\n", program_name,LI.filename); return 1; /* FAILURE */ } if (this_program) { fprintf(stdout, "%s: To unistall this program use %s -M all\n", program_name,program_name); } return r; } static int unstage P_((int argc, char *argv[], int x)); static int unstage(argc, argv, x) int argc; char *argv[]; int x; { int r = 0; struct log_instance LI; int remove_count; int i; char **module_filter = NULL; int module_count = 0; #if ANSI_C char my_version[] = "[ELM" VERSION " " PATCHLEVEL "]"; #else char my_version[40]; sprintf(my_version,"[ELM %s %s]",VERSION,PATCHLEVEL); #endif clear_log_instance(&LI); while (x < argc && '-' == argv[x][0]) { if (x < argc -1 && 0 == strcmp("-F", argv[x])) { filelist = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-M", argv[x])) { module_filter = realloc(module_filter, (module_count+2) * sizeof (module_filter[0])); if (! module_filter) { fprintf(stderr, "%s: Failed to realloc -M option\n", program_name); exit(1); } module_filter[module_count++] = argv[x+1]; module_filter[module_count] = NULL; x += 2; } else { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } } if (x < argc) { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } LI.filename = filelist; LI.file = fopen(LI.filename,"r+"); if (!LI.file) { fprintf(stderr, "%s: Failed to open file %s\n", program_name,LI.filename); return 1; /* FAILURE */ } add_entries(&LI); if (LI.entries_count < 1 || 0 != strcmp(LI.entries[LI.entries_count-1].version, my_version)) { fprintf(stderr, "%s: Last version on file %s is not %s\n", program_name, LI.filename, my_version); r = 1; } remove_unlinked(&LI,"/",&remove_count); for (i = 0; i < LI.entries_count; i++) { if (0 != unstage_list(& LI.entries[i], &LI, module_filter)) r = 1; } rewrite_list(&LI); if (EOF == fclose(LI.file)) { fprintf(stderr, "%s: Write(?) failed on closing of file: %s\n", program_name,LI.filename); return 1; /* FAILURE */ } return r; } static int dir_list P_((int argc, char *argv[], int x)); static int dir_list(argc, argv, x) int argc; char *argv[]; int x; { int r = 0; struct stat X; struct log_instance LI; int i; char **module_filter = NULL; int module_count = 0; #if ANSI_C char my_version[] = "[ELM" VERSION " " PATCHLEVEL "]"; #else char my_version[40]; sprintf(my_version,"[ELM %s %s]",VERSION,PATCHLEVEL); #endif clear_log_instance(&LI); installer_root = "/"; while (x < argc && '-' == argv[x][0]) { if (x < argc -1 && 0 == strcmp("-F", argv[x])) { filelist = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-R", argv[x])) { installer_root = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-M", argv[x])) { module_filter = realloc(module_filter, (module_count+2) * sizeof (module_filter[0])); if (! module_filter) { fprintf(stderr, "%s: Failed to realloc -M option\n", program_name); exit(1); } module_filter[module_count++] = argv[x+1]; module_filter[module_count] = NULL; x += 2; } else { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } } if (x < argc) { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } if (stat(installer_root,&X) < 0) { fprintf(stderr,"%s: -R %s invalid\n", argv[0],installer_root); return 1; /* FAILURE */ } if ( #ifdef S_ISDIR ! S_ISDIR(X.st_mode) #else S_IFDIR != (buf.st_mode & S_IFMT) #endif ) { fprintf(stderr,"%s: -R %s invalid (not a directory)\n", argv[0],installer_root); return 1; /* FAILURE */ } LI.filename = filelist; if (0 != strcmp(installer_root,"/")) { int l = strlen(filelist) + strlen(installer_root) +2; LI.filename = malloc(l); if (!LI.filename) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,l); return 1; /* FAILURE */ } sprintf(LI.filename,"%s%s",installer_root,filelist); } LI.file = fopen(LI.filename,"r"); if (!LI.file) { fprintf(stderr, "%s: Failed to open file %s\n", program_name,LI.filename); return 1; /* FAILURE */ } add_entries(&LI); if (LI.entries_count < 1 || 0 != strcmp(LI.entries[LI.entries_count-1].version, my_version)) { fprintf(stderr, "%s: Last version on file %s is not %s\n", program_name, LI.filename, my_version); r = 1; } for (i = 0; i < LI.entries_count; i++) { struct log_entries *I = &(LI.entries[i]); int r; /* Skip error message if list is actually empty */ if (I->log_count < 1) continue; if (0 != strcmp(I->version,my_version)) { fprintf(stderr, "%s: File %s includes version %s entries (current %s)\n", program_name, LI.filename, I->version, my_version); } for (r = 0; r < I->log_count; r++) { struct log_record * R = & (I->log[r]); char * file = NULL;; if (! filter_record(R,module_filter,1)) continue; if (R->arg_ptrs && R->arg_ptrs[0]) file = R->arg_ptrs[0]; if (!file) continue; if ('/' == file[0]) file++; switch (R->command_letter) { case 'M': fputs(file,stdout); fputc('\n',stdout); case 'd': /* doc */ case 'F': case 's': case 'C': /* config */ case 'E': case 'R': case 'L': break; case '{': { char *F = make_rooted(R,file,installer_root); struct stat X; if (stat(F,&X) < 0) { if (ENOENT != errno) fprintf(stderr, "%s: '%c' File %s (%s) not accessible\n", program_name,R->command_letter, file,F); } else if ( #ifdef S_ISDIR S_ISDIR(X.st_mode) #else S_IFDIR == (X.st_mode & S_IFMT) #endif ) { fputs(file,stdout); fputc('/',stdout); fputc('\n',stdout); } free(F); } break; default: fprintf(stderr, "%s: '%c' Bad command letter\n", program_name,R->command_letter); } } } if (EOF == fclose(LI.file)) { fprintf(stderr, "%s: Failed on closing of file: %s\n", program_name,LI.filename); return 1; /* FAILURE */ } return r; } static int tar_list P_((int argc, char *argv[], int x)); static int tar_list(argc, argv, x) int argc; char *argv[]; int x; { int r = 0; struct stat X; struct log_instance LI; int i; char **module_filter = NULL; int module_count = 0; #if ANSI_C char my_version[] = "[ELM" VERSION " " PATCHLEVEL "]"; #else char my_version[40]; sprintf(my_version,"[ELM %s %s]",VERSION,PATCHLEVEL); #endif clear_log_instance(&LI); installer_root = "/"; while (x < argc && '-' == argv[x][0]) { if (x < argc -1 && 0 == strcmp("-F", argv[x])) { filelist = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-R", argv[x])) { installer_root = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-M", argv[x])) { module_filter = realloc(module_filter, (module_count+2) * sizeof (module_filter[0])); if (! module_filter) { fprintf(stderr, "%s: Failed to realloc -M option\n", program_name); exit(1); } module_filter[module_count++] = argv[x+1]; module_filter[module_count] = NULL; x += 2; } else { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } } if (x < argc) { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } if (stat(installer_root,&X) < 0) { fprintf(stderr,"%s: -R %s invalid\n", argv[0],installer_root); return 1; /* FAILURE */ } if ( #ifdef S_ISDIR ! S_ISDIR(X.st_mode) #else S_IFDIR != (buf.st_mode & S_IFMT) #endif ) { fprintf(stderr,"%s: -R %s invalid (not a directory)\n", argv[0],installer_root); return 1; /* FAILURE */ } LI.filename = filelist; if (0 != strcmp(installer_root,"/")) { int l = strlen(filelist) + strlen(installer_root) +2; LI.filename = malloc(l); if (!LI.filename) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,l); return 1; /* FAILURE */ } sprintf(LI.filename,"%s%s",installer_root,filelist); } LI.file = fopen(LI.filename,"r"); if (!LI.file) { fprintf(stderr, "%s: Failed to open file %s\n", program_name,LI.filename); return 1; /* FAILURE */ } add_entries(&LI); if (LI.entries_count < 1 || 0 != strcmp(LI.entries[LI.entries_count-1].version, my_version)) { fprintf(stderr, "%s: Last version on file %s is not %s\n", program_name, LI.filename, my_version); r = 1; } for (i = 0; i < LI.entries_count; i++) { struct log_entries *I = &(LI.entries[i]); int r; /* Skip error message if list is actually empty */ if (I->log_count < 1) continue; if (0 != strcmp(I->version,my_version)) { fprintf(stderr, "%s: File %s includes version %s entries (current %s)\n", program_name, LI.filename, I->version, my_version); } for (r = 0; r < I->log_count; r++) { struct log_record * R = & (I->log[r]); char * file = NULL;; if (! filter_record(R,module_filter,1)) continue; if (R->arg_ptrs && R->arg_ptrs[0]) file = R->arg_ptrs[0]; if (!file) continue; if ('/' == file[0]) file++; switch (R->command_letter) { case 'M': /* Directories not listed */ break; case 'd': /* doc */ case 'F': case 's': case 'C': /* config */ fputs(file,stdout); fputc('\n',stdout); break; case 'E': break; case 'R': break; case 'L': /* Hard links not listed (although OK) */ break; case '{': { char *F = make_rooted(R,file,installer_root); struct stat X; if (stat(F,&X) < 0) { if (ENOENT != errno) fprintf(stderr, "%s: '%c' File %s (%s) not accessible\n", program_name,R->command_letter, file,F); } else if ( #ifdef S_ISDIR S_ISDIR(X.st_mode) #else S_IFDIR == (X.st_mode & S_IFMT) #endif ) { #if 0 fprintf(stderr, "%s: '%c' File %s (%s) is directory\n", program_name,R->command_letter, file,F); #endif #ifndef DIROPS if (! R->command_ptr || 0 != strcmp(R->command_ptr,IMPARGDIR)) { /* If no DIROPS, then files are not listed, so include dir to listing */ fputs(file,stdout); fputc('/',stdout); fputc('\n',stdout); } #endif } else { fputs(file,stdout); fputc('\n',stdout); } free(F); } break; default: fprintf(stderr, "%s: '%c' Bad command letter\n", program_name,R->command_letter); } } } if (EOF == fclose(LI.file)) { fprintf(stderr, "%s: Failed on closing of file: %s\n", program_name,LI.filename); return 1; /* FAILURE */ } return r; } static int rpm_list P_((int argc, char *argv[], int x)); static int rpm_list(argc, argv, x) int argc; char *argv[]; int x; { int r = 0; struct stat X; struct log_instance LI; int i; char *user1 = "-"; char *group1 = "-"; char **module_filter = NULL; int module_count = 0; #if ANSI_C char my_version[] = "[ELM" VERSION " " PATCHLEVEL "]"; #else char my_version[40]; sprintf(my_version,"[ELM %s %s]",VERSION,PATCHLEVEL); #endif clear_log_instance(&LI); installer_root = "/"; while (x < argc && '-' == argv[x][0]) { if (x < argc -1 && 0 == strcmp("-F", argv[x])) { filelist = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-u", argv[x])) { user1 = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-g", argv[x])) { group1 = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-R", argv[x])) { installer_root = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-M", argv[x])) { module_filter = realloc(module_filter, (module_count+2) * sizeof (module_filter[0])); if (! module_filter) { fprintf(stderr, "%s: Failed to realloc -M option\n", program_name); exit(1); } module_filter[module_count++] = argv[x+1]; module_filter[module_count] = NULL; x += 2; } else { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } } if (x < argc) { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } if (stat(installer_root,&X) < 0) { fprintf(stderr,"%s: -R %s invalid\n", argv[0],installer_root); return 1; /* FAILURE */ } if ( #ifdef S_ISDIR ! S_ISDIR(X.st_mode) #else S_IFDIR != (buf.st_mode & S_IFMT) #endif ) { fprintf(stderr,"%s: -R %s invalid (not a directory)\n", argv[0],installer_root); return 1; /* FAILURE */ } LI.filename = filelist; if (0 != strcmp(installer_root,"/")) { int l = strlen(filelist) + strlen(installer_root) +2; LI.filename = malloc(l); if (!LI.filename) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,l); return 1; /* FAILURE */ } sprintf(LI.filename,"%s%s",installer_root,filelist); } LI.file = fopen(LI.filename,"r"); if (!LI.file) { fprintf(stderr, "%s: Failed to open file %s\n", program_name,LI.filename); return 1; /* FAILURE */ } add_entries(&LI); if (LI.entries_count < 1 || 0 != strcmp(LI.entries[LI.entries_count-1].version, my_version)) { fprintf(stderr, "%s: Last version on file %s is not %s\n", program_name, LI.filename, my_version); r = 1; } for (i = 0; i < LI.entries_count; i++) { struct log_entries *I = &(LI.entries[i]); int r; /* Skip error message if list is actually empty */ if (I->log_count < 1) continue; if (0 != strcmp(I->version,my_version)) { fprintf(stderr, "%s: File %s includes version %s entries (current %s)\n", program_name, LI.filename, I->version, my_version); } for (r = 0; r < I->log_count; r++) { struct log_record * R = & (I->log[r]); char * user = R->user_ptr; char * group = R->group_ptr; char * mode = R->mode_ptr; char * file = NULL;; if (! filter_record(R,module_filter,1)) continue; if (R->arg_ptrs && R->arg_ptrs[0]) file = R->arg_ptrs[0]; if (!user || 0 == strcmp(user,"-")) user = user1; if (!group || 0 == strcmp(group,"-")) group = group1; if (!mode || 0 == atoi(mode)) mode = "-"; if (!file) continue; switch (R->command_letter) { case 'M': fputs("%dir ",stdout); if (0 != strcmp(user,"-") || 0 != strcmp(group,"-") || 0 != strcmp(mode,"-")) printf("%%attr(%s,%s,%s) ",mode,user,group); printf("%s%s\n", file[0] != '/' ? "/" : "", file); break; case 'd': fputs("%doc ",stdout); if (0 != strcmp(user,"-") || 0 != strcmp(group,"-") || 0 != strcmp(mode,"-")) printf("%%attr(%s,%s,%s) ",mode,user,group); printf("%s%s\n", file[0] != '/' ? "/" : "", file); break; case 'F': case 's': if (0 != strcmp(user,"-") || 0 != strcmp(group,"-") || 0 != strcmp(mode,"-")) printf("%%attr(%s,%s,%s) ",mode,user,group); printf("%s%s\n", file[0] != '/' ? "/" : "", file); break; case 'C': fputs("%config ",stdout); if (0 != strcmp(user,"-") || 0 != strcmp(group,"-") || 0 != strcmp(mode,"-")) printf("%%attr(%s,%s,%s) ",mode,user,group); printf("%s%s\n", file[0] != '/' ? "/" : "", file); break; case 'E': break; case 'R': break; case 'L': /* SECOND ARGUMENT IS NEW NAME hard links need not to put archive -- they are created on elmregister replay */ if (R->arg_ptrs && R->arg_ptrs[1]) { char *new_file = R->arg_ptrs[1]; printf("%%ghost %s%s\n", new_file[0] != '/' ? "/" : "", new_file); } break; case '{': { char *F = make_rooted(R,file,installer_root); struct stat X; if (stat(F,&X) < 0) { if (ENOENT != errno) fprintf(stderr, "%s: '%c' File %s (%s) not accessible\n", program_name,R->command_letter, file,F); } else if ( #ifdef S_ISDIR S_ISDIR(X.st_mode) #else S_IFDIR == (X.st_mode & S_IFMT) #endif ) { #if 0 fprintf(stderr, "%s: '%c' File %s (%s) is directory\n", program_name,R->command_letter, file,F); #endif if (R->command_ptr && 0 == strcmp(R->command_ptr,IMPARGDIR)) fputs("%dir ",stdout); #ifdef DIROPS else /* Files are already logged ... */ fputs("%dir ",stdout); #endif if (0 != strcmp(user,"-") || 0 != strcmp(group,"-") || 0 != strcmp(mode,"-")) printf("%%attr(%s,%s,%s) ",mode,user,group); printf("%s%s\n", file[0] != '/' ? "/" : "", file); } else { if (0 != strcmp(user,"-") || 0 != strcmp(group,"-") || 0 != strcmp(mode,"-")) printf("%%attr(%s,%s,%s) ",mode,user,group); printf("%s%s\n", file[0] != '/' ? "/" : "", file); } free(F); } break; default: fprintf(stderr, "%s: '%c' Bad command letter\n", program_name,R->command_letter); } } } if (EOF == fclose(LI.file)) { fprintf(stderr, "%s: Failed on closing of file: %s\n", program_name,LI.filename); return 1; /* FAILURE */ } return r; } static int filter P_((int argc, char *argv[], int x)); static int filter(argc, argv, x) int argc; char *argv[]; int x; { int r = 0; struct stat X; struct log_instance * target = NULL; struct log_entries * last = NULL; struct log_instance LI; struct log_instance LI_target; int i; char **module_filter = NULL; int module_count = 0; #if ANSI_C char my_version[] = "[ELM" VERSION " " PATCHLEVEL "]"; #else char my_version[40]; sprintf(my_version,"[ELM %s %s]",VERSION,PATCHLEVEL); #endif clear_log_instance(&LI); clear_log_instance(&LI_target); installer_root = "/"; while (x < argc && '-' == argv[x][0]) { if (x < argc -1 && 0 == strcmp("-F", argv[x])) { filelist = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-w", argv[x])) { char * file = argv[x+1]; int t; x += 2; if (LI_target.filename) { fprintf(stderr, "%s: Duplicate -w option\n", program_name); exit(1); } LI_target.filename = file; t = open(LI_target.filename,O_RDWR|O_CREAT,0644); if (t < 0) { fprintf(stderr, "%s: Failed to open file %s on targe: %s\n", program_name,filelist,LI_target.filename); fclose(LI.file); return 1; /* FAILURE */ } LI_target.file = fdopen(t,"r+"); if (!LI_target.file) { fprintf(stderr, "%s: Failed to fdopen file %s on target (/): %s\n", program_name,filelist,LI_target.filename); fclose(LI.file); close(t); return 1; /* FAILURE */ } add_entries(&LI_target); target = &LI_target; last = add_last(target); } else if (x < argc -1 && 0 == strcmp("-R", argv[x])) { installer_root = argv[x+1]; x += 2; } else if (x < argc -1 && 0 == strcmp("-M", argv[x])) { module_filter = realloc(module_filter, (module_count+2) * sizeof (module_filter[0])); if (! module_filter) { fprintf(stderr, "%s: Failed to realloc -M option\n", program_name); exit(1); } module_filter[module_count++] = argv[x+1]; module_filter[module_count] = NULL; x += 2; } else { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } } if (x < argc) { fprintf(stderr, "%s: Bad option %s\n", program_name,argv[x]); exit(1); } if (stat(installer_root,&X) < 0) { fprintf(stderr,"%s: -R %s invalid\n", argv[0],installer_root); return 1; /* FAILURE */ } if ( #ifdef S_ISDIR ! S_ISDIR(X.st_mode) #else S_IFDIR != (buf.st_mode & S_IFMT) #endif ) { fprintf(stderr,"%s: -R %s invalid (not a directory)\n", argv[0],installer_root); return 1; /* FAILURE */ } LI.filename = filelist; if (0 != strcmp(installer_root,"/")) { int l = strlen(filelist) + strlen(installer_root) +2; LI.filename = malloc(l); if (!LI.filename) { fprintf(stderr,"%s: malloc %d bytes failed\n", program_name,l); return 1; /* FAILURE */ } sprintf(LI.filename,"%s%s",installer_root,filelist); } LI.file = fopen(LI.filename,"r"); if (!LI.file) { fprintf(stderr, "%s: Failed to open file %s\n", program_name,LI.filename); return 1; /* FAILURE */ } add_entries(&LI); if (LI.entries_count < 1 || 0 != strcmp(LI.entries[LI.entries_count-1].version, my_version)) { fprintf(stderr, "%s: Last version on file %s is not %s\n", program_name, LI.filename, my_version); r = 1; } if (target) { for (i = 0; i < LI.entries_count; i++) { struct log_entries *I = &(LI.entries[i]); int r; /* Skip error message if list is actually empty */ if (I->log_count < 1) continue; if (0 != strcmp(I->version,my_version)) { fprintf(stderr, "%s: File %s includes version %s entries (current %s)\n", program_name, LI.filename, I->version, my_version); } for (r = 0; r < I->log_count; r++) { struct log_record * R = & (I->log[r]); if (! filter_record(R,module_filter,1)) continue; move_record(target,last,R); } } if (EOF == fclose(target->file)) { fprintf(stderr, "%s: Write(?) failed on closing of file: %s\n", program_name,target->filename); return 1; /* FAILURE */ } } return r; } int main P_((int argc, char *argv[])); int main(argc, argv) int argc; char *argv[]; { int x = 1; int r = 1; char *y; enum register_mode { register_master, register_command, register_replay, register_uninstall, register_unstage, register_dir_list, register_tar_list, register_rpm_list, register_filter } mode = register_command; register_pipe = getenv("ELM_INSTALLER"); installer_root = getenv("ELM_ROOT"); register_module = getenv("ELM_MODULE"); program_name = argv[0]; #if defined(ANSI_C) || defined(SETLINEBUF) setlinebuf(stdout); #endif #if 0 if (register_pipe) fprintf(stderr,"%s: $ELM_INSTALLER=%s\n",program_name,register_pipe); if (installer_root) fprintf(stderr,"%s: $ELM_ROOT=%s\n",program_name,installer_root); #endif if (x < argc -1 && 0 == strcmp("-S", argv[x])) { stage_dir = argv[x+1]; x += 2; } #if 0 if (stage_dir) fprintf(stderr,"%s: STAGE_DIR=%s\n",program_name,stage_dir); #endif if ((y = strrchr(program_name,'/')) && 0 == strcmp("/elmuninstall",y)) { mode = register_uninstall; } else if (x < argc && 0 == strcmp("uninstall", argv[x])) { x += 1; mode = register_uninstall; } if (x < argc && 0 == strcmp("master", argv[x])) { x += 1; mode = register_master; } else if (x < argc && 0 == strcmp("replay", argv[x])) { x += 1; mode = register_replay; } else if (x < argc && 0 == strcmp("unstage", argv[x])) { x += 1; mode = register_unstage; } else if (x < argc && 0 == strcmp("list", argv[x])) { x += 1; mode = register_tar_list; } else if (x < argc && 0 == strcmp("list-directories", argv[x])) { x += 1; mode = register_dir_list; } else if (x < argc && 0 == strcmp("rpm-list", argv[x])) { x += 1; mode = register_rpm_list; } else if (x < argc && 0 == strcmp("filter", argv[x])) { x += 1; mode = register_filter; } if (mode != register_command) { if (register_pipe) { fprintf(stderr, "%s: $ELM_INSTALLER=%s incompatible with arguments 'master' and 'replay', 'unstage'\n", argv[0],register_pipe); return 1; /* FAILURE */ } if (installer_root) { fprintf(stderr,"%s: $ELM_ROOT=%s incompatible with arguments 'master' and 'replay, 'unstage'\n", argv[0],installer_root); return 1; /* FAILURE */ } if (installer_root) { fprintf(stderr,"%s: $ELM_MODULE=%s incompatible with arguments 'master' and 'replay, 'unstage'\n", argv[0],installer_root); return 1; /* FAILURE */ } } switch(mode) { case register_master: r = master(argc,argv,x); break; case register_command: r = command(argc,argv,x); break; case register_replay: r = replay(argc,argv,x); break; case register_uninstall: r = uninstall(argc,argv,x); break; case register_unstage: r = unstage(argc,argv,x); break; case register_tar_list: r = tar_list(argc,argv,x); break; case register_dir_list: r = dir_list(argc,argv,x); break; case register_rpm_list: r = rpm_list(argc,argv,x); break; case register_filter: r = filter(argc,argv,x); break; } return r; } /* * Local Variables: * mode:c * c-basic-offset:4 * buffer-file-coding-system: iso-8859-1 * End: */