int kmk_builtin_ln(int argc, char *argv[], char **envp) { struct stat sb; char *sourcedir; int ch, exitval; /* initialize globals. */ fflag = hflag = iflag = sflag = vflag = 0; linkch = 0; linkf = NULL; /* kmk: reset getopt() and set program name. */ g_progname = argv[0]; opterr = 1; optarg = NULL; optopt = 0; optind = 0; /* init */ while ((ch = getopt_long(argc, argv, "fhinsv", long_options, NULL)) != -1) switch (ch) { case 'f': fflag = 1; iflag = 0; break; case 'h': case 'n': hflag = 1; break; case 'i': iflag = 1; fflag = 0; break; case 's': sflag = 1; break; case 'v': vflag = 1; break; case 261: usage(stdout); return 0; case 262: return kbuild_version(argv[0]); case '?': default: return usage(stderr); } argv += optind; argc -= optind; linkf = sflag ? symlink : link; linkch = sflag ? '-' : '='; switch(argc) { case 0: return usage(stderr); /* NOTREACHED */ case 1: /* ln target */ return linkit(argv[0], ".", 1); case 2: /* ln target source */ return linkit(argv[0], argv[1], 0); default: ; } /* ln target1 target2 directory */ sourcedir = argv[argc - 1]; if (hflag && lstat(sourcedir, &sb) == 0 && S_ISLNK(sb.st_mode)) { /* * We were asked not to follow symlinks, but found one at * the target--simulate "not a directory" error */ errno = ENOTDIR; return err(1, "st_mode: %s", sourcedir); } if (stat(sourcedir, &sb)) return err(1, "stat: %s", sourcedir); if (!S_ISDIR(sb.st_mode)) return usage(stderr); for (exitval = 0; *argv != sourcedir; ++argv) exitval |= linkit(*argv, sourcedir, 1); return exitval; }
/** * Appends text to a textfile, creating the textfile if necessary. */ int kmk_builtin_append(int argc, char **argv, char **envp) { int i; int fFirst; int iFile; FILE *pFile; int fNewline = 0; int fNoTrailingNewline = 0; int fTruncate = 0; int fDefine = 0; int fVariables = 0; int fCommands = 0; g_progname = argv[0]; /* * Parse options. */ i = 1; while (i < argc && argv[i][0] == '-' && argv[i][1] != '\0' /* '-' is a file */ && strchr("-cdnNtv", argv[i][1]) /* valid option char */ ) { char *psz = &argv[i][1]; if (*psz != '-') { do { switch (*psz) { case 'c': if (fVariables) { errx(1, "Option '-c' clashes with '-v'."); return usage(stderr); } #ifndef kmk_builtin_append fCommands = 1; break; #else errx(1, "Option '-c' isn't supported in external mode."); return usage(stderr); #endif case 'd': if (fVariables) { errx(1, "Option '-d' must come before '-v'!"); return usage(stderr); } fDefine = 1; break; case 'n': fNewline = 1; break; case 'N': fNoTrailingNewline = 1; break; case 't': fTruncate = 1; break; case 'v': if (fCommands) { errx(1, "Option '-v' clashes with '-c'."); return usage(stderr); } #ifndef kmk_builtin_append fVariables = 1; break; #else errx(1, "Option '-v' isn't supported in external mode."); return usage(stderr); #endif default: errx(1, "Invalid option '%c'! (%s)", *psz, argv[i]); return usage(stderr); } } while (*++psz); } else if (!strcmp(psz, "-help")) { usage(stdout); return 0; } else if (!strcmp(psz, "-version")) return kbuild_version(argv[0]); else break; i++; } if (i + fDefine >= argc) { if (i <= argc) errx(1, "missing filename!"); else errx(1, "missing define name!"); return usage(stderr); } /* * Open the output file. */ iFile = i; pFile = fopen(argv[i], fTruncate ? "w" : "a"); if (!pFile) return err(1, "failed to open '%s'", argv[i]); /* * Start define? */ if (fDefine) { i++; fprintf(pFile, "define %s\n", argv[i]); } /* * Append the argument strings to the file */ fFirst = 1; for (i++; i < argc; i++) { const char *psz = argv[i]; size_t cch = strlen(psz); if (!fFirst) fputc(fNewline ? '\n' : ' ', pFile); #ifndef kmk_builtin_append if (fCommands) { char *pszOldBuf; unsigned cchOldBuf; char *pchEnd; install_variable_buffer(&pszOldBuf, &cchOldBuf); pchEnd = func_commands(variable_buffer, &argv[i], "commands"); fwrite(variable_buffer, 1, pchEnd - variable_buffer, pFile); restore_variable_buffer(pszOldBuf, cchOldBuf); } else if (fVariables) { struct variable *pVar = lookup_variable(psz, cch); if (!pVar) continue; if ( !pVar->recursive || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar)) fwrite(pVar->value, 1, pVar->value_length, pFile); else { char *pszExpanded = allocated_variable_expand(pVar->value); fwrite(pszExpanded, 1, strlen(pszExpanded), pFile); free(pszExpanded); } } else #endif fwrite(psz, 1, cch, pFile); fFirst = 0; } /* * End the define? */ if (fDefine) { if (fFirst) fwrite("\nendef", 1, sizeof("\nendef") - 1, pFile); else fwrite("endef", 1, sizeof("endef") - 1, pFile); } /* * Add the final newline (unless supressed) and close the file. */ if ( ( !fNoTrailingNewline && fputc('\n', pFile) == EOF) || ferror(pFile)) { fclose(pFile); return errx(1, "error writing to '%s'!", argv[iFile]); } if (fclose(pFile)) return err(1, "failed to fclose '%s'!", argv[iFile]); return 0; }
int kmk_builtin_chmod(int argc, char *argv[], char **envp) { FTS *ftsp; FTSENT *p; mode_t *set; int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval; int vflag; char *mode; mode_t newmode; int (*change_mode)(const char *, mode_t); /* kmk: reset getopt and set progname */ g_progname = argv[0]; opterr = 1; optarg = NULL; optopt = 0; optind = 0; /* init */ set = NULL; Hflag = Lflag = Rflag = fflag = hflag = vflag = 0; while ((ch = getopt_long(argc, argv, "HLPRXfghorstuvwx", long_options, NULL)) != -1) switch (ch) { case 'H': Hflag = 1; Lflag = 0; break; case 'L': Lflag = 1; Hflag = 0; break; case 'P': Hflag = Lflag = 0; break; case 'R': Rflag = 1; break; case 'f': fflag = 1; break; case 'h': /* * In System V (and probably POSIX.2) the -h option * causes chmod to change the mode of the symbolic * link. 4.4BSD's symbolic links didn't have modes, * so it was an undocumented noop. In FreeBSD 3.0, * lchmod(2) is introduced and this option does real * work. */ hflag = 1; break; /* * XXX * "-[rwx]" are valid mode commands. If they are the entire * argument, getopt has moved past them, so decrement optind. * Regardless, we're done argument processing. */ case 'g': case 'o': case 'r': case 's': case 't': case 'u': case 'w': case 'X': case 'x': if (argv[optind - 1][0] == '-' && argv[optind - 1][1] == ch && argv[optind - 1][2] == '\0') --optind; goto done; case 'v': vflag++; break; case 261: usage(stdout); return 0; case 262: return kbuild_version(argv[0]); case '?': default: return usage(stderr); } done: argv += optind; argc -= optind; if (argc < 2) return usage(stderr); if (Rflag) { fts_options = FTS_PHYSICAL; if (hflag) return errx(1, "the -R and -h options may not be specified together."); if (Hflag) fts_options |= FTS_COMFOLLOW; if (Lflag) { fts_options &= ~FTS_PHYSICAL; fts_options |= FTS_LOGICAL; } } else fts_options = hflag ? FTS_PHYSICAL : FTS_LOGICAL; if (hflag) change_mode = lchmod; else change_mode = chmod; mode = *argv; if ((set = bsd_setmode(mode)) == NULL) return errx(1, "invalid file mode: %s", mode); if ((ftsp = fts_open(++argv, fts_options, 0)) == NULL) return err(1, "fts_open"); for (rval = 0; (p = fts_read(ftsp)) != NULL;) { switch (p->fts_info) { case FTS_D: /* Change it at FTS_DP. */ if (!Rflag) fts_set(ftsp, p, FTS_SKIP); continue; case FTS_DNR: /* Warn, chmod, continue. */ warnx("fts: %s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; break; case FTS_ERR: /* Warn, continue. */ case FTS_NS: warnx("fts: %s: %s", p->fts_path, strerror(p->fts_errno)); rval = 1; continue; case FTS_SL: /* Ignore. */ case FTS_SLNONE: /* * The only symlinks that end up here are ones that * don't point to anything and ones that we found * doing a physical walk. */ if (!hflag) continue; /* else */ /* FALLTHROUGH */ default: break; } newmode = bsd_getmode(set, p->fts_statp->st_mode); if ((newmode & ALLPERMS) == (p->fts_statp->st_mode & ALLPERMS)) continue; if ((*change_mode)(p->fts_accpath, newmode) && !fflag) { warn("%schmod: %s", hflag ? "l" : "", p->fts_path); rval = 1; } else { if (vflag) { (void)printf("%s", p->fts_path); if (vflag > 1) { char m1[12], m2[12]; bsd_strmode(p->fts_statp->st_mode, m1); bsd_strmode((p->fts_statp->st_mode & S_IFMT) | newmode, m2); (void)printf(": 0%o [%s] -> 0%o [%s]", (unsigned int)p->fts_statp->st_mode, m1, (unsigned int)((p->fts_statp->st_mode & S_IFMT) | newmode), m2); } (void)printf("\n"); } } } if (errno) rval = err(1, "fts_read"); free(set); fts_close(ftsp); return rval; }
int kmk_builtin_test(int argc, char **argv, char **envp, char ***ppapszArgvSpawn) { int res; char **argv_spawn; int i; g_progname = argv[0]; /* look for the '--', '--help' and '--version'. */ argv_spawn = NULL; for (i = 1; i < argc; i++) { if ( argv[i][0] == '-' && argv[i][1] == '-') { if (argv[i][2] == '\0') { argc = i; argv[i] = NULL; /* skip blank arguments (happens inside kmk) */ while (argv[++i]) { const char *psz = argv[i]; while (isspace(*psz)) psz++; if (*psz) break; } argv_spawn = &argv[i]; break; } if (!strcmp(argv[i], "--help")) return usage(argv[0]); if (!strcmp(argv[i], "--version")) return kbuild_version(argv[0]); } } /* are we '['? then check for ']'. */ if (strcmp(g_progname, "[") == 0) { /** @todo should skip the path in g_progname */ if (strcmp(argv[--argc], "]")) return errx(1, "missing ]"); argv[argc] = NULL; } /* evaluate the expression */ if (argc < 2) res = 1; else { t_wp = &argv[1]; res = oexpr(t_lex(*t_wp)); if (res != -42 && *t_wp != NULL && *++t_wp != NULL) res = syntax(*t_wp, "unexpected operator"); if (res == -42) return 1; /* don't mix syntax errors with the argv_spawn ignore */ res = !res; } /* anything to execute on success? */ if (argv_spawn) { if (res != 0 || !argv_spawn[0]) res = 0; /* ignored */ else { #ifdef kmk_builtin_test /* try exec the specified process */ # if defined(_MSC_VER) res = _spawnvp(_P_WAIT, argv_spawn[0], argv_spawn); if (res == -1) res = err(1, "_spawnvp(_P_WAIT,%s,..)", argv_spawn[0]); # else execvp(argv_spawn[0], argv_spawn); res = err(1, "execvp(%s,..)", argv_spawn[0]); # endif #else /* in kmk */ /* let job.c spawn the process, make a job.c style argv_spawn copy. */ char *buf, *cur, **argv_new; size_t sz = 0; int argc_new = 0; while (argv_spawn[argc_new]) { size_t len = strlen(argv_spawn[argc_new]) + 1; sz += (len + sizeof(void *) - 1) & ~(sizeof(void *) - 1); argc_new++; } argv_new = xmalloc((argc_new + 1) * sizeof(char *)); buf = cur = xmalloc(sz); for (i = 0; i < argc_new; i++) { size_t len = strlen(argv_spawn[i]) + 1; argv_new[i] = memcpy(cur, argv_spawn[i], len); cur += (len + sizeof(void *) - 1) & ~(sizeof(void *) - 1); } argv_new[i] = NULL; *ppapszArgvSpawn = argv_new; res = 0; #endif /* in kmk */ } } return res; }
/* * rm -- * This rm is different from historic rm's, but is expected to match * POSIX 1003.2 behavior. The most visible difference is that -f * has two specific effects now, ignore non-existent files and force * file removal. */ int kmk_builtin_rm(int argc, char *argv[], char **envp) { int ch, rflag; /* reinitialize globals */ argv0 = argv[0]; dflag = eval = fflag = iflag = Pflag = vflag = Wflag = stdin_ok = 0; uid = 0; kBuildProtectionInit(&g_ProtData); /* kmk: reset getopt and set program name. */ g_progname = argv[0]; opterr = 1; optarg = NULL; optopt = 0; optind = 0; /* init */ Pflag = rflag = 0; while ((ch = getopt_long(argc, argv, "dfiPRvW", long_options, NULL)) != -1) switch(ch) { case 'd': dflag = 1; break; case 'f': fflag = 1; iflag = 0; break; case 'i': fflag = 0; iflag = 1; break; case 'P': Pflag = 1; break; case 'R': #if 0 case 'r': /* Compatibility. */ #endif rflag = 1; break; case 'v': vflag = 1; break; #ifdef FTS_WHITEOUT case 'W': Wflag = 1; break; #endif case 261: kBuildProtectionTerm(&g_ProtData); usage(stdout); return 0; case 262: kBuildProtectionTerm(&g_ProtData); return kbuild_version(argv[0]); case 263: kBuildProtectionDisable(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE); break; case 264: kBuildProtectionEnable(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE); break; case 265: kBuildProtectionEnable(&g_ProtData, KBUILDPROTECTIONTYPE_FULL); break; case 266: kBuildProtectionDisable(&g_ProtData, KBUILDPROTECTIONTYPE_FULL); break; case 267: if (kBuildProtectionSetDepth(&g_ProtData, optarg)) { kBuildProtectionTerm(&g_ProtData); return 1; } break; case '?': default: kBuildProtectionTerm(&g_ProtData); return usage(stderr); } argc -= optind; argv += optind; if (argc < 1) { kBuildProtectionTerm(&g_ProtData); if (fflag) return (0); return usage(stderr); } if (!kBuildProtectionScanEnv(&g_ProtData, envp, "KMK_RM_")) { checkdot(argv); uid = geteuid(); if (*argv) { stdin_ok = isatty(STDIN_FILENO); if (rflag) eval |= rm_tree(argv); else eval |= rm_file(argv); } } else { eval = 1; } kBuildProtectionTerm(&g_ProtData); return eval; }